[PATCH v7 06/22] s390/zcrypt: Support for apmask and aqmask change on live system

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Harald Freudenberger <freude@xxxxxxxxxxxxx>

This patch enables modifications of the apmask and aqmask on a live
system. Until now these both masks are read-only on a live system. The
only way to change these masks was via kernel command line parameter.

This patch makes the sysfs attributes /sys/bus/ap/apmask and
/sys/bus/ap/aqmask writeable by root. With changing the mask(s) a
revision of the existing queue to driver bindings is done. So all
APQNs which are bound to the 'wrong' driver are reprobed via kernel
function device_reprobe() and thus the new correct driver will be
assigned with respect of the changed apmask and aqmask bits.

Signed-off-by: Harald Freudenberger <freude@xxxxxxxxxxxxx>
Signed-off-by: Christian Borntraeger <borntraeger@xxxxxxxxxx>
---
 drivers/s390/crypto/ap_bus.c | 153 ++++++++++++++++++++++++++++++++---
 1 file changed, 143 insertions(+), 10 deletions(-)

diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index b36a4e17a734..c47d1f2fe0d8 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -70,6 +70,7 @@ static struct ap_rights {
 	DECLARE_BITMAP(apm, AP_DEVICES);
 	DECLARE_BITMAP(aqm, AP_DOMAINS);
 } ap_rights;
+static DEFINE_MUTEX(ap_rights_mutex);
 
 static struct ap_config_info *ap_configuration;
 static bool initialised;
@@ -681,6 +682,34 @@ static struct bus_type ap_bus_type = {
 	.pm = &ap_bus_pm_ops,
 };
 
+static int __ap_revice_reserved(struct device *dev, void *dummy)
+{
+	int rc, card, queue, devres, drvres;
+
+	if (is_queue_dev(dev)) {
+		card = AP_QID_CARD(to_ap_queue(dev)->qid);
+		queue = AP_QID_QUEUE(to_ap_queue(dev)->qid);
+		mutex_lock(&ap_rights_mutex);
+		devres = test_bit_inv(card, ap_rights.apm)
+			&& test_bit_inv(queue, ap_rights.aqm);
+		mutex_unlock(&ap_rights_mutex);
+		drvres = to_ap_drv(dev->driver)->flags
+			& AP_DRIVER_FLAG_DEFAULT;
+		if (!!devres != !!drvres) {
+			AP_DBF(DBF_DEBUG, "reprobing queue=%02x.%04x\n",
+			       card, queue);
+			rc = device_reprobe(dev);
+		}
+	}
+
+	return 0;
+}
+
+static void ap_bus_revise_bindings(void)
+{
+	bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_revice_reserved);
+}
+
 int ap_owned_by_def_drv(int card, int queue)
 {
 	int rc = 0;
@@ -688,10 +717,14 @@ int ap_owned_by_def_drv(int card, int queue)
 	if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS)
 		return -EINVAL;
 
+	mutex_lock(&ap_rights_mutex);
+
 	if (test_bit_inv(card, ap_rights.apm)
 	    && test_bit_inv(queue, ap_rights.aqm))
 		rc = 1;
 
+	mutex_unlock(&ap_rights_mutex);
+
 	return rc;
 }
 EXPORT_SYMBOL(ap_owned_by_def_drv);
@@ -700,6 +733,8 @@ int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, unsigned long *aqm)
 {
 	int card, queue, rc = 0;
 
+	mutex_lock(&ap_rights_mutex);
+
 	for (card = 0; !rc && card < AP_DEVICES; card++)
 		if (test_bit_inv(card, apm) &&
 		    test_bit_inv(card, ap_rights.apm))
@@ -708,6 +743,8 @@ int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, unsigned long *aqm)
 				    test_bit_inv(queue, ap_rights.aqm))
 					rc = 1;
 
+	mutex_unlock(&ap_rights_mutex);
+
 	return rc;
 }
 EXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv);
@@ -726,8 +763,10 @@ static int ap_device_probe(struct device *dev)
 		 */
 		card = AP_QID_CARD(to_ap_queue(dev)->qid);
 		queue = AP_QID_QUEUE(to_ap_queue(dev)->qid);
+		mutex_lock(&ap_rights_mutex);
 		devres = test_bit_inv(card, ap_rights.apm)
 			&& test_bit_inv(queue, ap_rights.aqm);
+		mutex_unlock(&ap_rights_mutex);
 		drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT;
 		if ((devres && !drvres) || (!devres && drvres))
 			return -ENODEV;
@@ -991,23 +1030,117 @@ static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL);
 
 static ssize_t ap_apmask_show(struct bus_type *bus, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE,
-			"0x%016lx%016lx%016lx%016lx\n",
-			ap_rights.apm[0], ap_rights.apm[1],
-			ap_rights.apm[2], ap_rights.apm[3]);
+	int rc;
+
+	if (mutex_lock_interruptible(&ap_rights_mutex))
+		return -ERESTARTSYS;
+	rc = snprintf(buf, PAGE_SIZE,
+		      "0x%016lx%016lx%016lx%016lx\n",
+		      ap_rights.apm[0], ap_rights.apm[1],
+		      ap_rights.apm[2], ap_rights.apm[3]);
+	mutex_unlock(&ap_rights_mutex);
+
+	return rc;
 }
 
-static BUS_ATTR(apmask, 0444, ap_apmask_show, NULL);
+static ssize_t ap_apmask_store(struct bus_type *bus, const char *buf,
+			       size_t count)
+{
+	int i;
+
+	if (*buf == '+' || *buf == '-') {
+		if (kstrtoint(buf, 0, &i))
+			return -EINVAL;
+		if (i <= -AP_DEVICES || i >= AP_DEVICES)
+			return -EINVAL;
+		if (mutex_lock_interruptible(&ap_rights_mutex))
+			return -ERESTARTSYS;
+		if (*buf == '-')
+			clear_bit_inv(-i, ap_rights.apm);
+		else
+			set_bit_inv(i, ap_rights.apm);
+	} else {
+		DECLARE_BITMAP(apm, AP_DEVICES);
+
+		i = hex2bitmap(buf, apm, AP_DEVICES);
+		if (i)
+			return i;
+		if (mutex_lock_interruptible(&ap_rights_mutex))
+			return -ERESTARTSYS;
+		for (i = 0; i < AP_DEVICES; i++)
+			if (test_bit_inv(i, apm)) {
+				if (!test_bit_inv(i, ap_rights.apm))
+					set_bit_inv(i, ap_rights.apm);
+			} else {
+				if (test_bit_inv(i, ap_rights.apm))
+					clear_bit_inv(i, ap_rights.apm);
+			}
+	}
+	mutex_unlock(&ap_rights_mutex);
+
+	ap_bus_revise_bindings();
+
+	return count;
+}
+
+static BUS_ATTR(apmask, 0644, ap_apmask_show, ap_apmask_store);
 
 static ssize_t ap_aqmask_show(struct bus_type *bus, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE,
-			"0x%016lx%016lx%016lx%016lx\n",
-			ap_rights.aqm[0], ap_rights.aqm[1],
-			ap_rights.aqm[2], ap_rights.aqm[3]);
+	int rc;
+
+	if (mutex_lock_interruptible(&ap_rights_mutex))
+		return -ERESTARTSYS;
+	rc = snprintf(buf, PAGE_SIZE,
+		      "0x%016lx%016lx%016lx%016lx\n",
+		      ap_rights.aqm[0], ap_rights.aqm[1],
+		      ap_rights.aqm[2], ap_rights.aqm[3]);
+	mutex_unlock(&ap_rights_mutex);
+
+	return rc;
 }
 
-static BUS_ATTR(aqmask, 0444, ap_aqmask_show, NULL);
+static ssize_t ap_aqmask_store(struct bus_type *bus, const char *buf,
+			       size_t count)
+{
+	int i;
+
+	if (*buf == '+' || *buf == '-') {
+		if (kstrtoint(buf, 0, &i))
+			return -EINVAL;
+		if (i <= -AP_DEVICES || i >= AP_DEVICES)
+			return -EINVAL;
+		if (mutex_lock_interruptible(&ap_rights_mutex))
+			return -ERESTARTSYS;
+		if (*buf == '-')
+			clear_bit_inv(-i, ap_rights.aqm);
+		else
+			set_bit_inv(i, ap_rights.aqm);
+	} else {
+		DECLARE_BITMAP(aqm, AP_DEVICES);
+
+		i = hex2bitmap(buf, aqm, AP_DEVICES);
+		if (i)
+			return i;
+		if (mutex_lock_interruptible(&ap_rights_mutex))
+			return -ERESTARTSYS;
+		for (i = 0; i < AP_DEVICES; i++)
+			if (test_bit_inv(i, aqm)) {
+				if (!test_bit_inv(i, ap_rights.aqm))
+					set_bit_inv(i, ap_rights.aqm);
+			} else {
+				if (test_bit_inv(i, ap_rights.aqm))
+					clear_bit_inv(i, ap_rights.aqm);
+			}
+	}
+	mutex_unlock(&ap_rights_mutex);
+
+	ap_bus_revise_bindings();
+
+	return count;
+}
+
+static BUS_ATTR(aqmask, 0644, ap_aqmask_show, ap_aqmask_store);
 
 static struct bus_attribute *const ap_bus_attrs[] = {
 	&bus_attr_ap_domain,
-- 
2.17.0




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux