diff options
author | Ralph Wuerthner <rwuerthn@de.ibm.com> | 2006-10-04 14:02:05 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-10-04 14:02:05 -0400 |
commit | 4e56296d471a827fdd244cfdb6a1e62fc3af7af0 (patch) | |
tree | 8532577922b2dfe337701544305c19726c82443f /drivers/s390/crypto | |
parent | f1ee3281bedbbca70a1f53bc715ea6f27c616052 (diff) |
[S390] zcrypt device registration/unregistration race.
Fix a race condition during AP device registration and unregistration.
Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 6ed0985c0c91..cd30f37fceae 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -449,8 +449,6 @@ static int ap_device_probe(struct device *dev) | |||
449 | 449 | ||
450 | ap_dev->drv = ap_drv; | 450 | ap_dev->drv = ap_drv; |
451 | rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; | 451 | rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; |
452 | if (rc) | ||
453 | ap_dev->unregistered = 1; | ||
454 | return rc; | 452 | return rc; |
455 | } | 453 | } |
456 | 454 | ||
@@ -487,14 +485,7 @@ static int ap_device_remove(struct device *dev) | |||
487 | struct ap_device *ap_dev = to_ap_dev(dev); | 485 | struct ap_device *ap_dev = to_ap_dev(dev); |
488 | struct ap_driver *ap_drv = ap_dev->drv; | 486 | struct ap_driver *ap_drv = ap_dev->drv; |
489 | 487 | ||
490 | spin_lock_bh(&ap_dev->lock); | 488 | ap_flush_queue(ap_dev); |
491 | __ap_flush_queue(ap_dev); | ||
492 | /** | ||
493 | * set ->unregistered to 1 while holding the lock. This prevents | ||
494 | * new messages to be put on the queue from now on. | ||
495 | */ | ||
496 | ap_dev->unregistered = 1; | ||
497 | spin_unlock_bh(&ap_dev->lock); | ||
498 | if (ap_drv->remove) | 489 | if (ap_drv->remove) |
499 | ap_drv->remove(ap_dev); | 490 | ap_drv->remove(ap_dev); |
500 | return 0; | 491 | return 0; |
@@ -763,6 +754,7 @@ static void ap_scan_bus(void *data) | |||
763 | break; | 754 | break; |
764 | ap_dev->qid = qid; | 755 | ap_dev->qid = qid; |
765 | ap_dev->queue_depth = queue_depth; | 756 | ap_dev->queue_depth = queue_depth; |
757 | ap_dev->unregistered = 1; | ||
766 | spin_lock_init(&ap_dev->lock); | 758 | spin_lock_init(&ap_dev->lock); |
767 | INIT_LIST_HEAD(&ap_dev->pendingq); | 759 | INIT_LIST_HEAD(&ap_dev->pendingq); |
768 | INIT_LIST_HEAD(&ap_dev->requestq); | 760 | INIT_LIST_HEAD(&ap_dev->requestq); |
@@ -784,7 +776,12 @@ static void ap_scan_bus(void *data) | |||
784 | /* Add device attributes. */ | 776 | /* Add device attributes. */ |
785 | rc = sysfs_create_group(&ap_dev->device.kobj, | 777 | rc = sysfs_create_group(&ap_dev->device.kobj, |
786 | &ap_dev_attr_group); | 778 | &ap_dev_attr_group); |
787 | if (rc) | 779 | if (!rc) { |
780 | spin_lock_bh(&ap_dev->lock); | ||
781 | ap_dev->unregistered = 0; | ||
782 | spin_unlock_bh(&ap_dev->lock); | ||
783 | } | ||
784 | else | ||
788 | device_unregister(&ap_dev->device); | 785 | device_unregister(&ap_dev->device); |
789 | } | 786 | } |
790 | } | 787 | } |
@@ -970,6 +967,8 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) | |||
970 | rc = __ap_queue_message(ap_dev, ap_msg); | 967 | rc = __ap_queue_message(ap_dev, ap_msg); |
971 | if (!rc) | 968 | if (!rc) |
972 | wake_up(&ap_poll_wait); | 969 | wake_up(&ap_poll_wait); |
970 | if (rc == -ENODEV) | ||
971 | ap_dev->unregistered = 1; | ||
973 | } else { | 972 | } else { |
974 | ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); | 973 | ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); |
975 | rc = 0; | 974 | rc = 0; |
@@ -1028,6 +1027,8 @@ static int __ap_poll_all(struct device *dev, void *data) | |||
1028 | spin_lock(&ap_dev->lock); | 1027 | spin_lock(&ap_dev->lock); |
1029 | if (!ap_dev->unregistered) { | 1028 | if (!ap_dev->unregistered) { |
1030 | rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data); | 1029 | rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data); |
1030 | if (rc) | ||
1031 | ap_dev->unregistered = 1; | ||
1031 | } else | 1032 | } else |
1032 | rc = 0; | 1033 | rc = 0; |
1033 | spin_unlock(&ap_dev->lock); | 1034 | spin_unlock(&ap_dev->lock); |