From 8862ce9883f9a8d4d72711969b87cdb10a36e4ee Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 23 Mar 2022 12:13:32 +0100 Subject: [PATCH] s390/ap: uevent on apmask/aqpmask change MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This patch introduces user space notifications for changes on the apmask or aqmask attributes. So it could be possible to write a udev rule to load/unload the vfio_ap kernel module based on changes of these masks. On chance of the apmask or aqmask an AP change event will be produced with an uevent environment variable showing the new APMASK or AQMASK mask. So a change on the apmask triggers an uvevent like this: KERNEL[490.160396] change /devices/ap (ap) ACTION=change DEVPATH=/devices/ap SUBSYSTEM=ap APMASK=0xffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffff SEQNUM=13367 and a change on the aqmask looks like this: KERNEL[283.217642] change /devices/ap (ap) ACTION=change DEVPATH=/devices/ap SUBSYSTEM=ap AQMASK=0xfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff SEQNUM=13348 Only real changes to the masks are processed - the old and new masks are compared and no action is done if the values are equal (and thus no uevent). The emit of the uevent is the very last action done when a mask change is processed. However, there is no guarantee that all unbind/bind actions caused by the apmask/aqmask changes are completed when the apmask/aqmask change uevent is received in userspace. Signed-off-by: Harald Freudenberger Tested-by: Thomas Huth Reviewed-by: Jürgen Christ Signed-off-by: Heiko Carstens --- drivers/s390/crypto/ap_bus.c | 40 ++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index fdf16cb708819..dc37732412d7e 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -693,6 +693,24 @@ void ap_send_online_uevent(struct ap_device *ap_dev, int online) } EXPORT_SYMBOL(ap_send_online_uevent); +static void ap_send_mask_changed_uevent(unsigned long *newapm, + unsigned long *newaqm) +{ + char buf[100]; + char *envp[] = { buf, NULL }; + + if (newapm) + snprintf(buf, sizeof(buf), + "APMASK=0x%016lx%016lx%016lx%016lx\n", + newapm[0], newapm[1], newapm[2], newapm[3]); + else + snprintf(buf, sizeof(buf), + "AQMASK=0x%016lx%016lx%016lx%016lx\n", + newaqm[0], newaqm[1], newaqm[2], newaqm[3]); + + kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp); +} + /* * calc # of bound APQNs */ @@ -1355,7 +1373,7 @@ static int apmask_commit(unsigned long *newapm) static ssize_t apmask_store(struct bus_type *bus, const char *buf, size_t count) { - int rc; + int rc, changes = 0; DECLARE_BITMAP(newapm, AP_DEVICES); if (mutex_lock_interruptible(&ap_perms_mutex)) @@ -1365,14 +1383,19 @@ static ssize_t apmask_store(struct bus_type *bus, const char *buf, if (rc) goto done; - rc = apmask_commit(newapm); + changes = memcmp(ap_perms.apm, newapm, APMASKSIZE); + if (changes) + rc = apmask_commit(newapm); done: mutex_unlock(&ap_perms_mutex); if (rc) return rc; - ap_bus_revise_bindings(); + if (changes) { + ap_bus_revise_bindings(); + ap_send_mask_changed_uevent(newapm, NULL); + } return count; } @@ -1443,7 +1466,7 @@ static int aqmask_commit(unsigned long *newaqm) static ssize_t aqmask_store(struct bus_type *bus, const char *buf, size_t count) { - int rc; + int rc, changes = 0; DECLARE_BITMAP(newaqm, AP_DOMAINS); if (mutex_lock_interruptible(&ap_perms_mutex)) @@ -1453,14 +1476,19 @@ static ssize_t aqmask_store(struct bus_type *bus, const char *buf, if (rc) goto done; - rc = aqmask_commit(newaqm); + changes = memcmp(ap_perms.aqm, newaqm, APMASKSIZE); + if (changes) + rc = aqmask_commit(newaqm); done: mutex_unlock(&ap_perms_mutex); if (rc) return rc; - ap_bus_revise_bindings(); + if (changes) { + ap_bus_revise_bindings(); + ap_send_mask_changed_uevent(NULL, newaqm); + } return count; } -- 2.39.5