s390/dasd: fix refcount for PAV reassignment
authorStefan Haberland <stefan.haberland@de.ibm.com>
Tue, 15 Dec 2015 09:45:05 +0000 (10:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Mar 2016 23:06:23 +0000 (15:06 -0800)
commit 9d862ababb609439c5d6987f6d3ddd09e703aa0b upstream.

Add refcount to the DASD device when a summary unit check worker is
scheduled. This prevents that the device is set offline with worker
in place.

Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/s390/block/dasd_alias.c

index d52d7a23b2e7e7587d45df3469b832b08ca9f1bd..6a64e86e8ccd1655af18880a89c2b67d595e431a 100644 (file)
@@ -264,8 +264,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
                spin_unlock_irqrestore(&lcu->lock, flags);
                cancel_work_sync(&lcu->suc_data.worker);
                spin_lock_irqsave(&lcu->lock, flags);
-               if (device == lcu->suc_data.device)
+               if (device == lcu->suc_data.device) {
+                       dasd_put_device(device);
                        lcu->suc_data.device = NULL;
+               }
        }
        was_pending = 0;
        if (device == lcu->ruac_data.device) {
@@ -273,8 +275,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
                was_pending = 1;
                cancel_delayed_work_sync(&lcu->ruac_data.dwork);
                spin_lock_irqsave(&lcu->lock, flags);
-               if (device == lcu->ruac_data.device)
+               if (device == lcu->ruac_data.device) {
+                       dasd_put_device(device);
                        lcu->ruac_data.device = NULL;
+               }
        }
        private->lcu = NULL;
        spin_unlock_irqrestore(&lcu->lock, flags);
@@ -549,8 +553,10 @@ static void lcu_update_work(struct work_struct *work)
        if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "could not update"
                            " alias data in lcu (rc = %d), retry later", rc);
-               schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+               if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ))
+                       dasd_put_device(device);
        } else {
+               dasd_put_device(device);
                lcu->ruac_data.device = NULL;
                lcu->flags &= ~UPDATE_PENDING;
        }
@@ -593,8 +599,10 @@ static int _schedule_lcu_update(struct alias_lcu *lcu,
         */
        if (!usedev)
                return -EINVAL;
+       dasd_get_device(usedev);
        lcu->ruac_data.device = usedev;
-       schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+       if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0))
+               dasd_put_device(usedev);
        return 0;
 }
 
@@ -926,6 +934,7 @@ static void summary_unit_check_handling_work(struct work_struct *work)
        /* 3. read new alias configuration */
        _schedule_lcu_update(lcu, device);
        lcu->suc_data.device = NULL;
+       dasd_put_device(device);
        spin_unlock_irqrestore(&lcu->lock, flags);
 }
 
@@ -985,6 +994,8 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
        }
        lcu->suc_data.reason = reason;
        lcu->suc_data.device = device;
+       dasd_get_device(device);
        spin_unlock(&lcu->lock);
-       schedule_work(&lcu->suc_data.worker);
+       if (!schedule_work(&lcu->suc_data.worker))
+               dasd_put_device(device);
 };