Commit 4e56296d authored by Ralph Wuerthner's avatar Ralph Wuerthner Committed by Martin Schwidefsky

[S390] zcrypt device registration/unregistration race.

Fix a race condition during AP device registration and unregistration.
Signed-off-by: default avatarRalph Wuerthner <rwuerthn@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent f1ee3281
...@@ -449,8 +449,6 @@ static int ap_device_probe(struct device *dev) ...@@ -449,8 +449,6 @@ static int ap_device_probe(struct device *dev)
ap_dev->drv = ap_drv; ap_dev->drv = ap_drv;
rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
if (rc)
ap_dev->unregistered = 1;
return rc; return rc;
} }
...@@ -487,14 +485,7 @@ static int ap_device_remove(struct device *dev) ...@@ -487,14 +485,7 @@ static int ap_device_remove(struct device *dev)
struct ap_device *ap_dev = to_ap_dev(dev); struct ap_device *ap_dev = to_ap_dev(dev);
struct ap_driver *ap_drv = ap_dev->drv; struct ap_driver *ap_drv = ap_dev->drv;
spin_lock_bh(&ap_dev->lock); ap_flush_queue(ap_dev);
__ap_flush_queue(ap_dev);
/**
* set ->unregistered to 1 while holding the lock. This prevents
* new messages to be put on the queue from now on.
*/
ap_dev->unregistered = 1;
spin_unlock_bh(&ap_dev->lock);
if (ap_drv->remove) if (ap_drv->remove)
ap_drv->remove(ap_dev); ap_drv->remove(ap_dev);
return 0; return 0;
...@@ -763,6 +754,7 @@ static void ap_scan_bus(void *data) ...@@ -763,6 +754,7 @@ static void ap_scan_bus(void *data)
break; break;
ap_dev->qid = qid; ap_dev->qid = qid;
ap_dev->queue_depth = queue_depth; ap_dev->queue_depth = queue_depth;
ap_dev->unregistered = 1;
spin_lock_init(&ap_dev->lock); spin_lock_init(&ap_dev->lock);
INIT_LIST_HEAD(&ap_dev->pendingq); INIT_LIST_HEAD(&ap_dev->pendingq);
INIT_LIST_HEAD(&ap_dev->requestq); INIT_LIST_HEAD(&ap_dev->requestq);
...@@ -784,7 +776,12 @@ static void ap_scan_bus(void *data) ...@@ -784,7 +776,12 @@ static void ap_scan_bus(void *data)
/* Add device attributes. */ /* Add device attributes. */
rc = sysfs_create_group(&ap_dev->device.kobj, rc = sysfs_create_group(&ap_dev->device.kobj,
&ap_dev_attr_group); &ap_dev_attr_group);
if (rc) if (!rc) {
spin_lock_bh(&ap_dev->lock);
ap_dev->unregistered = 0;
spin_unlock_bh(&ap_dev->lock);
}
else
device_unregister(&ap_dev->device); device_unregister(&ap_dev->device);
} }
} }
...@@ -970,6 +967,8 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) ...@@ -970,6 +967,8 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
rc = __ap_queue_message(ap_dev, ap_msg); rc = __ap_queue_message(ap_dev, ap_msg);
if (!rc) if (!rc)
wake_up(&ap_poll_wait); wake_up(&ap_poll_wait);
if (rc == -ENODEV)
ap_dev->unregistered = 1;
} else { } else {
ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
rc = 0; rc = 0;
...@@ -1028,6 +1027,8 @@ static int __ap_poll_all(struct device *dev, void *data) ...@@ -1028,6 +1027,8 @@ static int __ap_poll_all(struct device *dev, void *data)
spin_lock(&ap_dev->lock); spin_lock(&ap_dev->lock);
if (!ap_dev->unregistered) { if (!ap_dev->unregistered) {
rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data); rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data);
if (rc)
ap_dev->unregistered = 1;
} else } else
rc = 0; rc = 0;
spin_unlock(&ap_dev->lock); spin_unlock(&ap_dev->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment