diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2007-04-27 10:01:39 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:42 -0400 |
commit | ef99516c9646802c3d38c3eb83de302e05b3c1b5 (patch) | |
tree | 48f9126ee7df357d45c253e1b879e3c0ead4dce4 /drivers/s390/cio/device.c | |
parent | 8c4941c53b14e5a08ed2f270e9f087b410a9abcc (diff) |
[S390] cio: Unregister ccw devices directly.
We used to unregister ccw devices not directly from the I/O
subchannel remove function in order to avoid lifelocks on the
css bus semaphore. This semaphore is gone, and there is no reason
to not unregister the ccw device directly (it is even better since
it is more in keeping with the goal of immediate disconnect).
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 | 56 |
1 files changed, 12 insertions, 44 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 3b56f373da3a..03355902c582 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -290,16 +290,10 @@ int ccw_device_is_orphan(struct ccw_device *cdev) | |||
290 | return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent)); | 290 | return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent)); |
291 | } | 291 | } |
292 | 292 | ||
293 | static void ccw_device_unregister(struct work_struct *work) | 293 | static void ccw_device_unregister(struct ccw_device *cdev) |
294 | { | 294 | { |
295 | struct ccw_device_private *priv; | ||
296 | struct ccw_device *cdev; | ||
297 | |||
298 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
299 | cdev = priv->cdev; | ||
300 | if (test_and_clear_bit(1, &cdev->private->registered)) | 295 | if (test_and_clear_bit(1, &cdev->private->registered)) |
301 | device_unregister(&cdev->dev); | 296 | device_del(&cdev->dev); |
302 | put_device(&cdev->dev); | ||
303 | } | 297 | } |
304 | 298 | ||
305 | static void | 299 | static void |
@@ -316,11 +310,8 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) | |||
316 | spin_lock_irqsave(cdev->ccwlock, flags); | 310 | spin_lock_irqsave(cdev->ccwlock, flags); |
317 | cdev->private->state = DEV_STATE_NOT_OPER; | 311 | cdev->private->state = DEV_STATE_NOT_OPER; |
318 | spin_unlock_irqrestore(cdev->ccwlock, flags); | 312 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
319 | if (get_device(&cdev->dev)) { | 313 | ccw_device_unregister(cdev); |
320 | PREPARE_WORK(&cdev->private->kick_work, | 314 | put_device(&cdev->dev); |
321 | ccw_device_unregister); | ||
322 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
323 | } | ||
324 | return ; | 315 | return ; |
325 | } | 316 | } |
326 | sch = to_subchannel(cdev->dev.parent); | 317 | sch = to_subchannel(cdev->dev.parent); |
@@ -555,17 +546,10 @@ static struct attribute_group ccwdev_attr_group = { | |||
555 | .attrs = ccwdev_attrs, | 546 | .attrs = ccwdev_attrs, |
556 | }; | 547 | }; |
557 | 548 | ||
558 | static int | 549 | struct attribute_group *ccwdev_attr_groups[] = { |
559 | device_add_files (struct device *dev) | 550 | &ccwdev_attr_group, |
560 | { | 551 | NULL, |
561 | return sysfs_create_group(&dev->kobj, &ccwdev_attr_group); | 552 | }; |
562 | } | ||
563 | |||
564 | static void | ||
565 | device_remove_files(struct device *dev) | ||
566 | { | ||
567 | sysfs_remove_group(&dev->kobj, &ccwdev_attr_group); | ||
568 | } | ||
569 | 553 | ||
570 | /* this is a simple abstraction for device_register that sets the | 554 | /* this is a simple abstraction for device_register that sets the |
571 | * correct bus type and adds the bus specific files */ | 555 | * correct bus type and adds the bus specific files */ |
@@ -580,10 +564,6 @@ static int ccw_device_register(struct ccw_device *cdev) | |||
580 | return ret; | 564 | return ret; |
581 | 565 | ||
582 | set_bit(1, &cdev->private->registered); | 566 | set_bit(1, &cdev->private->registered); |
583 | if ((ret = device_add_files(dev))) { | ||
584 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
585 | device_del(dev); | ||
586 | } | ||
587 | return ret; | 567 | return ret; |
588 | } | 568 | } |
589 | 569 | ||
@@ -655,10 +635,6 @@ ccw_device_add_changed(struct work_struct *work) | |||
655 | return; | 635 | return; |
656 | } | 636 | } |
657 | set_bit(1, &cdev->private->registered); | 637 | set_bit(1, &cdev->private->registered); |
658 | if (device_add_files(&cdev->dev)) { | ||
659 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
660 | device_unregister(&cdev->dev); | ||
661 | } | ||
662 | } | 638 | } |
663 | 639 | ||
664 | void ccw_device_do_unreg_rereg(struct work_struct *work) | 640 | void ccw_device_do_unreg_rereg(struct work_struct *work) |
@@ -671,9 +647,7 @@ void ccw_device_do_unreg_rereg(struct work_struct *work) | |||
671 | cdev = priv->cdev; | 647 | cdev = priv->cdev; |
672 | sch = to_subchannel(cdev->dev.parent); | 648 | sch = to_subchannel(cdev->dev.parent); |
673 | 649 | ||
674 | device_remove_files(&cdev->dev); | 650 | ccw_device_unregister(cdev); |
675 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
676 | device_del(&cdev->dev); | ||
677 | PREPARE_WORK(&cdev->private->kick_work, | 651 | PREPARE_WORK(&cdev->private->kick_work, |
678 | ccw_device_add_changed); | 652 | ccw_device_add_changed); |
679 | queue_work(ccw_device_work, &cdev->private->kick_work); | 653 | queue_work(ccw_device_work, &cdev->private->kick_work); |
@@ -712,6 +686,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
712 | cdev->dev.parent = &sch->dev; | 686 | cdev->dev.parent = &sch->dev; |
713 | cdev->dev.release = ccw_device_release; | 687 | cdev->dev.release = ccw_device_release; |
714 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | 688 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); |
689 | cdev->dev.groups = ccwdev_attr_groups; | ||
715 | /* Do first half of device_register. */ | 690 | /* Do first half of device_register. */ |
716 | device_initialize(&cdev->dev); | 691 | device_initialize(&cdev->dev); |
717 | if (!get_device(&sch->dev)) { | 692 | if (!get_device(&sch->dev)) { |
@@ -1141,15 +1116,8 @@ io_subchannel_remove (struct subchannel *sch) | |||
1141 | sch->dev.driver_data = NULL; | 1116 | sch->dev.driver_data = NULL; |
1142 | cdev->private->state = DEV_STATE_NOT_OPER; | 1117 | cdev->private->state = DEV_STATE_NOT_OPER; |
1143 | spin_unlock_irqrestore(cdev->ccwlock, flags); | 1118 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
1144 | /* | 1119 | ccw_device_unregister(cdev); |
1145 | * Put unregistration on workqueue to avoid livelocks on the css bus | 1120 | put_device(&cdev->dev); |
1146 | * semaphore. | ||
1147 | */ | ||
1148 | if (get_device(&cdev->dev)) { | ||
1149 | PREPARE_WORK(&cdev->private->kick_work, | ||
1150 | ccw_device_unregister); | ||
1151 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
1152 | } | ||
1153 | return 0; | 1121 | return 0; |
1154 | } | 1122 | } |
1155 | 1123 | ||