<div dir="ltr"><div dir="ltr"><div>From: Harald Freudenberger <<a href="mailto:freude@linux.ibm.com">freude@linux.ibm.com</a>></div><div><br></div><div>BugLink: <a href="http://bugs.launchpad.net/bugs/1799184">http://bugs.launchpad.net/bugs/1799184</a></div><div><br></div><div>The sysfs attributes /sys/bus/ap/apmask and /sys/bus/ap/aqmask</div><div>and the kernel command line arguments ap.apm and ap.aqm get</div><div>an improvement of the value parsing with this patch:</div><div><br></div><div>The mask values are bitmaps in big endian order starting with bit 0.</div><div>So adapter number 0 is the leftmost bit, mask is 0x8000... The sysfs</div><div>attributes and the kernel command line accept 2 different formats:</div><div> - Absolute hex string starting with 0x like "0x12345678" does set</div><div>   the mask starting from left to right. If the given string is shorter</div><div>   than the mask it is padded with 0s on the right. If the string is</div><div>   longer than the mask an error comes back (EINVAL).</div><div> - Relative format - a concatenation (done with ',') of the terms</div><div>   +<bitnr>[-<bitnr>] or -<bitnr>[-<bitnr>]. <bitnr> may be any</div><div>   valid number (hex, decimal or octal) in the range 0...255.</div><div>   Here are some examples:</div><div>     "+0-15,+32,-128,-0xFF"</div><div>     "-0-255,+1-16,+0x128"</div><div><br></div><div>Signed-off-by: Harald Freudenberger <<a href="mailto:freude@linux.ibm.com">freude@linux.ibm.com</a>></div><div>Signed-off-by: Martin Schwidefsky <<a href="mailto:schwidefsky@de.ibm.com">schwidefsky@de.ibm.com</a>></div><div>(cherry-picked from commit 3d8f60d38e249f989a7fca9c2370c31c3d5487e1)</div><div>Signed-off-by: Frank Heimes <<a href="mailto:frank.heimes@canonical.com">frank.heimes@canonical.com</a>></div><div><br></div><div>---</div><div><br></div><div>diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c</div><div>index 30d7898..ec891bc 100644</div><div>--- a/drivers/s390/crypto/ap_bus.c</div><div>+++ b/drivers/s390/crypto/ap_bus.c</div><div>@@ -857,9 +857,13 @@ void ap_bus_force_rescan(void)</div><div> EXPORT_SYMBOL(ap_bus_force_rescan);</div><div> </div><div> /*</div><div>- * AP bus attributes.</div><div>+ * hex2bitmap() - parse hex mask string and set bitmap.</div><div>+ * Valid strings are "0x012345678" with at least one valid hex number.</div><div>+ * Rest of the bitmap to the right is padded with 0. No spaces allowed</div><div>+ * within the string, the leading 0x may be omitted.</div><div>+ * Returns the bitmask with exactly the bits set as given by the hex</div><div>+ * string (both in big endian order).</div><div>  */</div><div>-</div><div> static int hex2bitmap(const char *str, unsigned long *bitmap, int bits)</div><div> {</div><div>        int i, n, b;</div><div>@@ -883,12 +887,133 @@ static int hex2bitmap(const char *str, unsigned long *bitmap, int bits)</div><div>                i += 4;</div><div>        }</div><div> </div><div>-       if (i < 4 || isxdigit(*str))</div><div>+       if (*str == '\n')</div><div>+               str++;</div><div>+       if (*str)</div><div>+               return -EINVAL;</div><div>+       return 0;</div><div>+}</div><div>+</div><div>+/*</div><div>+ * str2clrsetmasks() - parse bitmask argument and set the clear and</div><div>+ * the set bitmap mask. A concatenation (done with ',') of these terms</div><div>+ * is recognized:</div><div>+ *   +<bitnr>[-<bitnr>] or -<bitnr>[-<bitnr>]</div><div>+ * <bitnr> may be any valid number (hex, decimal or octal) in the range</div><div>+ * 0...bits-1; the leading + or - is required. Here are some examples:</div><div>+ *   +0-15,+32,-128,-0xFF</div><div>+ *   -0-255,+1-16,+0x128</div><div>+ *   +1,+2,+3,+4,-5,-7-10</div><div>+ * Returns a clear and a set bitmask. Every positive value in the string</div><div>+ * results in a bit set in the set mask and every negative value in the</div><div>+ * string results in a bit SET in the clear mask. As a bit may be touched</div><div>+ * more than once, the last 'operation' wins: +0-255,-128 = all but bit</div><div>+ * 128 set in the set mask, only bit 128 set in the clear mask.</div><div>+ */</div><div>+static int str2clrsetmasks(const char *str,</div><div>+                          unsigned long *clrmap,</div><div>+                          unsigned long *setmap,</div><div>+                          int bits)</div><div>+{</div><div>+       int a, i, z;</div><div>+       char *np, sign;</div><div>+</div><div>+       /* bits needs to be a multiple of 8 */</div><div>+       if (bits & 0x07)</div><div>                return -EINVAL;</div><div> </div><div>+       memset(clrmap, 0, bits / 8);</div><div>+       memset(setmap, 0, bits / 8);</div><div>+</div><div>+       while (*str) {</div><div>+               sign = *str++;</div><div>+               if (sign != '+' && sign != '-')</div><div>+                       return -EINVAL;</div><div>+               a = z = simple_strtoul(str, &np, 0);</div><div>+               if (str == np || a >= bits)</div><div>+                       return -EINVAL;</div><div>+               str = np;</div><div>+               if (*str == '-') {</div><div>+                       z = simple_strtoul(++str, &np, 0);</div><div>+                       if (str == np || a > z || z >= bits)</div><div>+                               return -EINVAL;</div><div>+                       str = np;</div><div>+               }</div><div>+               for (i = a; i <= z; i++)</div><div>+                       if (sign == '+') {</div><div>+                               set_bit_inv(i, setmap);</div><div>+                               clear_bit_inv(i, clrmap);</div><div>+                       } else {</div><div>+                               clear_bit_inv(i, setmap);</div><div>+                               set_bit_inv(i, clrmap);</div><div>+                       }</div><div>+               while (*str == ',' || *str == '\n')</div><div>+                       str++;</div><div>+       }</div><div>+</div><div>        return 0;</div><div> }</div><div> </div><div>+/*</div><div>+ * process_mask_arg() - parse a bitmap string and clear/set the</div><div>+ * bits in the bitmap accordingly. The string may be given as</div><div>+ * absolute value, a hex string like 0x1F2E3D4C5B6A" simple over-</div><div>+ * writing the current content of the bitmap. Or as relative string</div><div>+ * like "+1-16,-32,-0x40,+128" where only single bits or ranges of</div><div>+ * bits are cleared or set. Distinction is done based on the very</div><div>+ * first character which may be '+' or '-' for the relative string</div><div>+ * and othewise assume to be an absolute value string. If parsing fails</div><div>+ * a negative errno value is returned. All arguments and bitmaps are</div><div>+ * big endian order.</div><div>+ */</div><div>+static int process_mask_arg(const char *str,</div><div>+                           unsigned long *bitmap, int bits,</div><div>+                           struct mutex *lock)</div><div>+{</div><div>+       int i;</div><div>+</div><div>+       /* bits needs to be a multiple of 8 */</div><div>+       if (bits & 0x07)</div><div>+               return -EINVAL;</div><div>+</div><div>+       if (*str == '+' || *str == '-') {</div><div>+               DECLARE_BITMAP(clrm, bits);</div><div>+               DECLARE_BITMAP(setm, bits);</div><div>+</div><div>+               i = str2clrsetmasks(str, clrm, setm, bits);</div><div>+               if (i)</div><div>+                       return i;</div><div>+               if (mutex_lock_interruptible(lock))</div><div>+                       return -ERESTARTSYS;</div><div>+               for (i = 0; i < bits; i++) {</div><div>+                       if (test_bit_inv(i, clrm))</div><div>+                               clear_bit_inv(i, bitmap);</div><div>+                       if (test_bit_inv(i, setm))</div><div>+                               set_bit_inv(i, bitmap);</div><div>+               }</div><div>+       } else {</div><div>+               DECLARE_BITMAP(setm, bits);</div><div>+</div><div>+               i = hex2bitmap(str, setm, bits);</div><div>+               if (i)</div><div>+                       return i;</div><div>+               if (mutex_lock_interruptible(lock))</div><div>+                       return -ERESTARTSYS;</div><div>+               for (i = 0; i < bits; i++)</div><div>+                       if (test_bit_inv(i, setm))</div><div>+                               set_bit_inv(i, bitmap);</div><div>+                       else</div><div>+                               clear_bit_inv(i, bitmap);</div><div>+       }</div><div>+       mutex_unlock(lock);</div><div>+</div><div>+       return 0;</div><div>+}</div><div>+</div><div>+/*</div><div>+ * AP bus attributes.</div><div>+ */</div><div>+</div><div> static ssize_t ap_domain_show(struct bus_type *bus, char *buf)</div><div> {</div><div>        return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index);</div><div>@@ -1054,34 +1179,11 @@ static ssize_t apmask_show(struct bus_type *bus, char *buf)</div><div> static ssize_t apmask_store(struct bus_type *bus, const char *buf,</div><div>                            size_t count)</div><div> {</div><div>-       int i;</div><div>-</div><div>-       if (*buf == '+' || *buf == '-') {</div><div>-               if (kstrtoint(buf, 0, &i))</div><div>-                       return -EINVAL;</div><div>-               if (i <= -AP_DEVICES || i >= AP_DEVICES)</div><div>-                       return -EINVAL;</div><div>-               if (mutex_lock_interruptible(&ap_perms_mutex))</div><div>-                       return -ERESTARTSYS;</div><div>-               if (*buf == '-')</div><div>-                       clear_bit_inv(-i, ap_perms.apm);</div><div>-               else</div><div>-                       set_bit_inv(i, ap_perms.apm);</div><div>-       } else {</div><div>-               DECLARE_BITMAP(apm, AP_DEVICES);</div><div>+       int rc;</div><div> </div><div>-               i = hex2bitmap(buf, apm, AP_DEVICES);</div><div>-               if (i)</div><div>-                       return i;</div><div>-               if (mutex_lock_interruptible(&ap_perms_mutex))</div><div>-                       return -ERESTARTSYS;</div><div>-               for (i = 0; i < AP_DEVICES; i++)</div><div>-                       if (test_bit_inv(i, apm))</div><div>-                               set_bit_inv(i, ap_perms.apm);</div><div>-                       else</div><div>-                               clear_bit_inv(i, ap_perms.apm);</div><div>-       }</div><div>-       mutex_unlock(&ap_perms_mutex);</div><div>+       rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);</div><div>+       if (rc)</div><div>+               return rc;</div><div> </div><div>        ap_bus_revise_bindings();</div><div> </div><div>@@ -1108,34 +1210,11 @@ static ssize_t aqmask_show(struct bus_type *bus, char *buf)</div><div> static ssize_t aqmask_store(struct bus_type *bus, const char *buf,</div><div>                            size_t count)</div><div> {</div><div>-       int i;</div><div>-</div><div>-       if (*buf == '+' || *buf == '-') {</div><div>-               if (kstrtoint(buf, 0, &i))</div><div>-                       return -EINVAL;</div><div>-               if (i <= -AP_DEVICES || i >= AP_DEVICES)</div><div>-                       return -EINVAL;</div><div>-               if (mutex_lock_interruptible(&ap_perms_mutex))</div><div>-                       return -ERESTARTSYS;</div><div>-               if (*buf == '-')</div><div>-                       clear_bit_inv(-i, ap_perms.aqm);</div><div>-               else</div><div>-                       set_bit_inv(i, ap_perms.aqm);</div><div>-       } else {</div><div>-               DECLARE_BITMAP(aqm, AP_DEVICES);</div><div>+       int rc;</div><div> </div><div>-               i = hex2bitmap(buf, aqm, AP_DEVICES);</div><div>-               if (i)</div><div>-                       return i;</div><div>-               if (mutex_lock_interruptible(&ap_perms_mutex))</div><div>-                       return -ERESTARTSYS;</div><div>-               for (i = 0; i < AP_DEVICES; i++)</div><div>-                       if (test_bit_inv(i, aqm))</div><div>-                               set_bit_inv(i, ap_perms.aqm);</div><div>-                       else</div><div>-                               clear_bit_inv(i, ap_perms.aqm);</div><div>-       }</div><div>-       mutex_unlock(&ap_perms_mutex);</div><div>+       rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);</div><div>+       if (rc)</div><div>+               return rc;</div><div> </div><div>        ap_bus_revise_bindings();</div><div> </div><div>@@ -1436,32 +1515,22 @@ static int __init ap_debug_init(void)</div><div> </div><div> static void __init ap_perms_init(void)</div><div> {</div><div>-       int i, rc;</div><div>-</div><div>-       /* start with all resources useable */</div><div>+       /* all resources useable if no kernel parameter string given */</div><div>        memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm));</div><div>        memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm));</div><div> </div><div>-       /* process kernel parameters apm and aqm if given */</div><div>+       /* apm kernel parameter string */</div><div>        if (apm_str) {</div><div>-               DECLARE_BITMAP(apm, AP_DEVICES);</div><div>-</div><div>-               rc = hex2bitmap(apm_str, apm, AP_DEVICES);</div><div>-               if (rc == 0) {</div><div>-                       for (i = 0; i < AP_DEVICES; i++)</div><div>-                               if (!test_bit_inv(i, apm))</div><div>-                                       clear_bit_inv(i, ap_perms.apm);</div><div>-               }</div><div>+               memset(&ap_perms.apm, 0, sizeof(ap_perms.apm));</div><div>+               process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES,</div><div>+                                &ap_perms_mutex);</div><div>        }</div><div>-       if (aqm_str) {</div><div>-               DECLARE_BITMAP(aqm, AP_DOMAINS);</div><div> </div><div>-               rc = hex2bitmap(aqm_str, aqm, AP_DOMAINS);</div><div>-               if (rc == 0) {</div><div>-                       for (i = 0; i < AP_DOMAINS; i++)</div><div>-                               if (!test_bit_inv(i, aqm))</div><div>-                                       clear_bit_inv(i, ap_perms.aqm);</div><div>-               }</div><div>+       /* aqm kernel parameter string */</div><div>+       if (aqm_str) {</div><div>+               memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm));</div><div>+               process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS,</div><div>+                                &ap_perms_mutex);</div><div>        }</div><div> }</div><div><br></div></div></div>