s390/cio: ensure that a chpid is registered only once
authorSebastian Ott <sebott@linux.ibm.com>
Wed, 13 Jun 2018 14:26:23 +0000 (16:26 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 17 Jul 2018 05:27:51 +0000 (07:27 +0200)
Improve locking in chp_new to make sure that we don't register
the same chpid twice. Chpid registration was synchronized via
the machine check handler thread but we also have codepaths to
look for new chpids triggered independent of that thread (during
IPL or resume from hibernate).

Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/chp.c
drivers/s390/cio/css.c

index afbdee74147dd01553ce136bd2a1f3e5f349ad37..51038ec309c12ef3f3eae351d332ed7a13694eda 100644 (file)
@@ -471,14 +471,17 @@ int chp_new(struct chp_id chpid)
 {
        struct channel_subsystem *css = css_by_id(chpid.cssid);
        struct channel_path *chp;
-       int ret;
+       int ret = 0;
 
+       mutex_lock(&css->mutex);
        if (chp_is_registered(chpid))
-               return 0;
-       chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);
-       if (!chp)
-               return -ENOMEM;
+               goto out;
 
+       chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);
+       if (!chp) {
+               ret = -ENOMEM;
+               goto out;
+       }
        /* fill in status, etc. */
        chp->chpid = chpid;
        chp->state = 1;
@@ -505,21 +508,20 @@ int chp_new(struct chp_id chpid)
                put_device(&chp->dev);
                goto out;
        }
-       mutex_lock(&css->mutex);
+
        if (css->cm_enabled) {
                ret = chp_add_cmg_attr(chp);
                if (ret) {
                        device_unregister(&chp->dev);
-                       mutex_unlock(&css->mutex);
                        goto out;
                }
        }
        css->chps[chpid.id] = chp;
-       mutex_unlock(&css->mutex);
        goto out;
 out_free:
        kfree(chp);
 out:
+       mutex_unlock(&css->mutex);
        return ret;
 }
 
@@ -585,8 +587,7 @@ static void chp_process_crw(struct crw *crw0, struct crw *crw1,
        switch (crw0->erc) {
        case CRW_ERC_IPARM: /* Path has come. */
        case CRW_ERC_INIT:
-               if (!chp_is_registered(chpid))
-                       chp_new(chpid);
+               chp_new(chpid);
                chsc_chp_online(chpid);
                break;
        case CRW_ERC_PERRI: /* Path has gone. */
index 9263a0fb385845588ceb7a80a5f6a2edc9449556..830a83ec49871ec2ac77037eb6a162ef80e91de6 100644 (file)
@@ -244,8 +244,7 @@ static void ssd_register_chpids(struct chsc_ssd_info *ssd)
        for (i = 0; i < 8; i++) {
                mask = 0x80 >> i;
                if (ssd->path_mask & mask)
-                       if (!chp_is_registered(ssd->chpid[i]))
-                               chp_new(ssd->chpid[i]);
+                       chp_new(ssd->chpid[i]);
        }
 }