diff options
-rw-r--r-- | drivers/s390/cio/device.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index cba33aa1df79..91acea10840d 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -950,6 +950,14 @@ io_subchannel_register(struct work_struct *work) | |||
950 | priv = container_of(work, struct ccw_device_private, kick_work); | 950 | priv = container_of(work, struct ccw_device_private, kick_work); |
951 | cdev = priv->cdev; | 951 | cdev = priv->cdev; |
952 | sch = to_subchannel(cdev->dev.parent); | 952 | sch = to_subchannel(cdev->dev.parent); |
953 | /* | ||
954 | * Check if subchannel is still registered. It may have become | ||
955 | * unregistered if a machine check hit us after finishing | ||
956 | * device recognition but before the register work could be | ||
957 | * queued. | ||
958 | */ | ||
959 | if (!device_is_registered(&sch->dev)) | ||
960 | goto out_err; | ||
953 | css_update_ssd_info(sch); | 961 | css_update_ssd_info(sch); |
954 | /* | 962 | /* |
955 | * io_subchannel_register() will also be called after device | 963 | * io_subchannel_register() will also be called after device |
@@ -984,18 +992,16 @@ io_subchannel_register(struct work_struct *work) | |||
984 | spin_lock_irqsave(sch->lock, flags); | 992 | spin_lock_irqsave(sch->lock, flags); |
985 | sch_set_cdev(sch, NULL); | 993 | sch_set_cdev(sch, NULL); |
986 | spin_unlock_irqrestore(sch->lock, flags); | 994 | spin_unlock_irqrestore(sch->lock, flags); |
987 | /* Release reference for workqueue processing. */ | ||
988 | put_device(&cdev->dev); | ||
989 | /* Release initial device reference. */ | 995 | /* Release initial device reference. */ |
990 | put_device(&cdev->dev); | 996 | put_device(&cdev->dev); |
991 | if (atomic_dec_and_test(&ccw_device_init_count)) | 997 | goto out_err; |
992 | wake_up(&ccw_device_init_wq); | ||
993 | return; | ||
994 | } | 998 | } |
995 | put_device(&cdev->dev); | ||
996 | out: | 999 | out: |
997 | cdev->private->flags.recog_done = 1; | 1000 | cdev->private->flags.recog_done = 1; |
998 | wake_up(&cdev->private->wait_q); | 1001 | wake_up(&cdev->private->wait_q); |
1002 | out_err: | ||
1003 | /* Release reference for workqueue processing. */ | ||
1004 | put_device(&cdev->dev); | ||
999 | if (atomic_dec_and_test(&ccw_device_init_count)) | 1005 | if (atomic_dec_and_test(&ccw_device_init_count)) |
1000 | wake_up(&ccw_device_init_wq); | 1006 | wake_up(&ccw_device_init_wq); |
1001 | } | 1007 | } |