[S390] vmur: Use wait queue instead of mutex to serialize open
authorFrank Munzert <munzert@de.ibm.com>
Thu, 17 Apr 2008 05:46:06 +0000 (07:46 +0200)
committerHeiko Carstens <heiko.carstens@de.ibm.com>
Thu, 17 Apr 2008 05:46:59 +0000 (07:46 +0200)
If user space opens a unit record device node then vmur is leaving the kernel
with lock open_mutex still held to prevent other processes from opening the
device simultaneously. This causes lockdep to complain about a lock held when
returning to user space.
Now the mutex is replaced by a wait queue to serialize device open.

Signed-off-by: Frank Munzert <munzert@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
drivers/s390/char/vmur.c
drivers/s390/char/vmur.h

index 7689b500a1046ffbddfd0426c7229847959bc0f0..83ae9a852f00c2dc5c4e2fc9be7eb81e974770de 100644 (file)
@@ -100,7 +100,8 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
        urd->reclen = cdev->id.driver_info;
        ccw_device_get_id(cdev, &urd->dev_id);
        mutex_init(&urd->io_mutex);
-       mutex_init(&urd->open_mutex);
+       init_waitqueue_head(&urd->wait);
+       spin_lock_init(&urd->open_lock);
        atomic_set(&urd->ref_count,  1);
        urd->cdev = cdev;
        get_device(&cdev->dev);
@@ -678,17 +679,21 @@ static int ur_open(struct inode *inode, struct file *file)
        if (!urd)
                return -ENXIO;
 
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&urd->open_mutex)) {
+       spin_lock(&urd->open_lock);
+       while (urd->open_flag) {
+               spin_unlock(&urd->open_lock);
+               if (file->f_flags & O_NONBLOCK) {
                        rc = -EBUSY;
                        goto fail_put;
                }
-       } else {
-               if (mutex_lock_interruptible(&urd->open_mutex)) {
+               if (wait_event_interruptible(urd->wait, urd->open_flag == 0)) {
                        rc = -ERESTARTSYS;
                        goto fail_put;
                }
+               spin_lock(&urd->open_lock);
        }
+       urd->open_flag++;
+       spin_unlock(&urd->open_lock);
 
        TRACE("ur_open\n");
 
@@ -720,7 +725,9 @@ static int ur_open(struct inode *inode, struct file *file)
 fail_urfile_free:
        urfile_free(urf);
 fail_unlock:
-       mutex_unlock(&urd->open_mutex);
+       spin_lock(&urd->open_lock);
+       urd->open_flag--;
+       spin_unlock(&urd->open_lock);
 fail_put:
        urdev_put(urd);
        return rc;
@@ -731,7 +738,10 @@ static int ur_release(struct inode *inode, struct file *file)
        struct urfile *urf = file->private_data;
 
        TRACE("ur_release\n");
-       mutex_unlock(&urf->urd->open_mutex);
+       spin_lock(&urf->urd->open_lock);
+       urf->urd->open_flag--;
+       spin_unlock(&urf->urd->open_lock);
+       wake_up_interruptible(&urf->urd->wait);
        urdev_put(urf->urd);
        urfile_free(urf);
        return 0;
index fa959644735a7495451a3ea3dedaf920097033c3..fa320ad4593d790fb34af20f27afb9c3825e8af4 100644 (file)
@@ -62,7 +62,6 @@ struct file_control_block {
 struct urdev {
        struct ccw_device *cdev;        /* Backpointer to ccw device */
        struct mutex io_mutex;          /* Serialises device IO */
-       struct mutex open_mutex;        /* Serialises access to device */
        struct completion *io_done;     /* do_ur_io waits; irq completes */
        struct device *device;
        struct cdev *char_device;
@@ -71,6 +70,9 @@ struct urdev {
        int class;                      /* VM device class */
        int io_request_rc;              /* return code from I/O request */
        atomic_t ref_count;             /* reference counter */
+       wait_queue_head_t wait;         /* wait queue to serialize open */
+       int open_flag;                  /* "urdev is open" flag */
+       spinlock_t open_lock;           /* serialize critical sections */
 };
 
 /*