s390/qeth: lock the card while changing its hsuid
authorJulian Wiedmann <jwi@linux.ibm.com>
Mon, 23 Dec 2019 14:03:22 +0000 (15:03 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 25 Dec 2019 06:41:06 +0000 (22:41 -0800)
qeth_l3_dev_hsuid_store() initially checks the card state, but doesn't
take the conf_mutex to ensure that the card stays in this state while
being reconfigured.

Rework the code to take this lock, and drop a redundant state check in a
helper function.

Fixes: b333293058aa ("qeth: add support for af_iucv HiperSockets transport")
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l3_sys.c

index 324cf22..c64ef55 100644 (file)
@@ -3425,11 +3425,6 @@ int qeth_configure_cq(struct qeth_card *card, enum qeth_cq cq)
                        goto out;
                }
 
-               if (card->state != CARD_STATE_DOWN) {
-                       rc = -1;
-                       goto out;
-               }
-
                qeth_free_qdio_queues(card);
                card->options.cq = cq;
                rc = 0;
index f9067ed..e8c848f 100644 (file)
@@ -242,21 +242,33 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        struct qeth_card *card = dev_get_drvdata(dev);
+       int rc = 0;
        char *tmp;
-       int rc;
 
        if (!IS_IQD(card))
                return -EPERM;
-       if (card->state != CARD_STATE_DOWN)
-               return -EPERM;
-       if (card->options.sniffer)
-               return -EPERM;
-       if (card->options.cq == QETH_CQ_NOTAVAILABLE)
-               return -EPERM;
+
+       mutex_lock(&card->conf_mutex);
+       if (card->state != CARD_STATE_DOWN) {
+               rc = -EPERM;
+               goto out;
+       }
+
+       if (card->options.sniffer) {
+               rc = -EPERM;
+               goto out;
+       }
+
+       if (card->options.cq == QETH_CQ_NOTAVAILABLE) {
+               rc = -EPERM;
+               goto out;
+       }
 
        tmp = strsep((char **)&buf, "\n");
-       if (strlen(tmp) > 8)
-               return -EINVAL;
+       if (strlen(tmp) > 8) {
+               rc = -EINVAL;
+               goto out;
+       }
 
        if (card->options.hsuid[0])
                /* delete old ip address */
@@ -267,11 +279,13 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
                card->options.hsuid[0] = '\0';
                memcpy(card->dev->perm_addr, card->options.hsuid, 9);
                qeth_configure_cq(card, QETH_CQ_DISABLED);
-               return count;
+               goto out;
        }
 
-       if (qeth_configure_cq(card, QETH_CQ_ENABLED))
-               return -EPERM;
+       if (qeth_configure_cq(card, QETH_CQ_ENABLED)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        snprintf(card->options.hsuid, sizeof(card->options.hsuid),
                 "%-8s", tmp);
@@ -280,6 +294,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
 
        rc = qeth_l3_modify_hsuid(card, true);
 
+out:
+       mutex_unlock(&card->conf_mutex);
        return rc ? rc : count;
 }