aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2007-03-05 17:35:56 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2007-03-05 17:35:56 -0500
commitee04bbccdeb11bdbc54015be8dca30a0deeca5e4 (patch)
treedebc4b75f59aa188db3e7e3eedf7bcacb73a268b
parent482b05dd533da162fa8d04c61712fae297bea3e0 (diff)
[S390] cio: Fix locking when calling notify function.
Make sure we hold the device lock when we modify the ccw device structure but always call the notify function without the lock held. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/cio/device_fsm.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 51238e7555bb..8baa9cd3794c 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -334,20 +334,29 @@ ccw_device_oper_notify(struct work_struct *work)
334 struct ccw_device *cdev; 334 struct ccw_device *cdev;
335 struct subchannel *sch; 335 struct subchannel *sch;
336 int ret; 336 int ret;
337 unsigned long flags;
337 338
338 priv = container_of(work, struct ccw_device_private, kick_work); 339 priv = container_of(work, struct ccw_device_private, kick_work);
339 cdev = priv->cdev; 340 cdev = priv->cdev;
341 spin_lock_irqsave(cdev->ccwlock, flags);
340 sch = to_subchannel(cdev->dev.parent); 342 sch = to_subchannel(cdev->dev.parent);
341 ret = (sch->driver && sch->driver->notify) ? 343 if (sch->driver && sch->driver->notify) {
342 sch->driver->notify(&sch->dev, CIO_OPER) : 0; 344 spin_unlock_irqrestore(cdev->ccwlock, flags);
343 if (!ret) 345 ret = sch->driver->notify(&sch->dev, CIO_OPER);
344 /* Driver doesn't want device back. */ 346 spin_lock_irqsave(cdev->ccwlock, flags);
345 ccw_device_do_unreg_rereg(work); 347 } else
346 else { 348 ret = 0;
349 if (ret) {
347 /* Reenable channel measurements, if needed. */ 350 /* Reenable channel measurements, if needed. */
351 spin_unlock_irqrestore(cdev->ccwlock, flags);
348 cmf_reenable(cdev); 352 cmf_reenable(cdev);
353 spin_lock_irqsave(cdev->ccwlock, flags);
349 wake_up(&cdev->private->wait_q); 354 wake_up(&cdev->private->wait_q);
350 } 355 }
356 spin_unlock_irqrestore(cdev->ccwlock, flags);
357 if (!ret)
358 /* Driver doesn't want device back. */
359 ccw_device_do_unreg_rereg(work);
351} 360}
352 361
353/* 362/*
@@ -534,15 +543,21 @@ ccw_device_nopath_notify(struct work_struct *work)
534 struct ccw_device *cdev; 543 struct ccw_device *cdev;
535 struct subchannel *sch; 544 struct subchannel *sch;
536 int ret; 545 int ret;
546 unsigned long flags;
537 547
538 priv = container_of(work, struct ccw_device_private, kick_work); 548 priv = container_of(work, struct ccw_device_private, kick_work);
539 cdev = priv->cdev; 549 cdev = priv->cdev;
550 spin_lock_irqsave(cdev->ccwlock, flags);
540 sch = to_subchannel(cdev->dev.parent); 551 sch = to_subchannel(cdev->dev.parent);
541 /* Extra sanity. */ 552 /* Extra sanity. */
542 if (sch->lpm) 553 if (sch->lpm)
543 return; 554 goto out_unlock;
544 ret = (sch->driver && sch->driver->notify) ? 555 if (sch->driver && sch->driver->notify) {
545 sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0; 556 spin_unlock_irqrestore(cdev->ccwlock, flags);
557 ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
558 spin_lock_irqsave(cdev->ccwlock, flags);
559 } else
560 ret = 0;
546 if (!ret) { 561 if (!ret) {
547 if (get_device(&sch->dev)) { 562 if (get_device(&sch->dev)) {
548 /* Driver doesn't want to keep device. */ 563 /* Driver doesn't want to keep device. */
@@ -562,6 +577,8 @@ ccw_device_nopath_notify(struct work_struct *work)
562 cdev->private->state = DEV_STATE_DISCONNECTED; 577 cdev->private->state = DEV_STATE_DISCONNECTED;
563 wake_up(&cdev->private->wait_q); 578 wake_up(&cdev->private->wait_q);
564 } 579 }
580out_unlock:
581 spin_unlock_irqrestore(cdev->ccwlock, flags);
565} 582}
566 583
567void 584void
@@ -607,10 +624,13 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
607 default: 624 default:
608 /* Reset oper notify indication after verify error. */ 625 /* Reset oper notify indication after verify error. */
609 cdev->private->flags.donotify = 0; 626 cdev->private->flags.donotify = 0;
610 PREPARE_WORK(&cdev->private->kick_work, 627 if (cdev->online) {
611 ccw_device_nopath_notify); 628 PREPARE_WORK(&cdev->private->kick_work,
612 queue_work(ccw_device_notify_work, &cdev->private->kick_work); 629 ccw_device_nopath_notify);
613 ccw_device_done(cdev, DEV_STATE_NOT_OPER); 630 queue_work(ccw_device_notify_work,
631 &cdev->private->kick_work);
632 } else
633 ccw_device_done(cdev, DEV_STATE_NOT_OPER);
614 break; 634 break;
615 } 635 }
616} 636}
@@ -756,15 +776,22 @@ static void
756ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) 776ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
757{ 777{
758 struct subchannel *sch; 778 struct subchannel *sch;
779 int ret;
759 780
760 sch = to_subchannel(cdev->dev.parent); 781 sch = to_subchannel(cdev->dev.parent);
761 if (sch->driver->notify && 782 if (sch->driver->notify) {
762 sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) { 783 spin_unlock_irq(cdev->ccwlock);
763 ccw_device_set_timeout(cdev, 0); 784 ret = sch->driver->notify(&sch->dev,
764 cdev->private->flags.fake_irb = 0; 785 sch->lpm ? CIO_GONE : CIO_NO_PATH);
765 cdev->private->state = DEV_STATE_DISCONNECTED; 786 spin_lock_irq(cdev->ccwlock);
766 wake_up(&cdev->private->wait_q); 787 } else
767 return; 788 ret = 0;
789 if (ret) {
790 ccw_device_set_timeout(cdev, 0);
791 cdev->private->flags.fake_irb = 0;
792 cdev->private->state = DEV_STATE_DISCONNECTED;
793 wake_up(&cdev->private->wait_q);
794 return;
768 } 795 }
769 cdev->private->state = DEV_STATE_NOT_OPER; 796 cdev->private->state = DEV_STATE_NOT_OPER;
770 cio_disable_subchannel(sch); 797 cio_disable_subchannel(sch);