diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-12-25 07:39:08 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:39:08 -0500 |
commit | 5fb6b8544d9ccd2ed478af777f9e99e342eb8886 (patch) | |
tree | 21d3819588970ea7e0421d79df088332fcadbb17 /drivers/s390/cio/device.c | |
parent | 6eff208f479d6fe99fd92c0e6bf7e930bb45cd30 (diff) |
[S390] cio: Only register ccw_device for registered subchannel.
There is a race between io_subchannel_register() and
io_subchannel_sch_event() which may cause a subchannel to be
unregistered because it is no longer operational before
io_subchannel_register() had run. We need to check whether the
subchannel is still registered before the ccw device can be
registered and just bail out if it is not.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device.c')
-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 | } |