[S390] vmur: Use wait queue instead of mutex to serialize open
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>
This commit is contained in:
committed by
Heiko Carstens
parent
92bf435f38
commit
a695f16729
@@ -100,7 +100,8 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
|
|||||||
urd->reclen = cdev->id.driver_info;
|
urd->reclen = cdev->id.driver_info;
|
||||||
ccw_device_get_id(cdev, &urd->dev_id);
|
ccw_device_get_id(cdev, &urd->dev_id);
|
||||||
mutex_init(&urd->io_mutex);
|
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);
|
atomic_set(&urd->ref_count, 1);
|
||||||
urd->cdev = cdev;
|
urd->cdev = cdev;
|
||||||
get_device(&cdev->dev);
|
get_device(&cdev->dev);
|
||||||
@@ -678,17 +679,21 @@ static int ur_open(struct inode *inode, struct file *file)
|
|||||||
if (!urd)
|
if (!urd)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
spin_lock(&urd->open_lock);
|
||||||
|
while (urd->open_flag) {
|
||||||
|
spin_unlock(&urd->open_lock);
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (file->f_flags & O_NONBLOCK) {
|
||||||
if (!mutex_trylock(&urd->open_mutex)) {
|
|
||||||
rc = -EBUSY;
|
rc = -EBUSY;
|
||||||
goto fail_put;
|
goto fail_put;
|
||||||
}
|
}
|
||||||
} else {
|
if (wait_event_interruptible(urd->wait, urd->open_flag == 0)) {
|
||||||
if (mutex_lock_interruptible(&urd->open_mutex)) {
|
|
||||||
rc = -ERESTARTSYS;
|
rc = -ERESTARTSYS;
|
||||||
goto fail_put;
|
goto fail_put;
|
||||||
}
|
}
|
||||||
|
spin_lock(&urd->open_lock);
|
||||||
}
|
}
|
||||||
|
urd->open_flag++;
|
||||||
|
spin_unlock(&urd->open_lock);
|
||||||
|
|
||||||
TRACE("ur_open\n");
|
TRACE("ur_open\n");
|
||||||
|
|
||||||
@@ -720,7 +725,9 @@ static int ur_open(struct inode *inode, struct file *file)
|
|||||||
fail_urfile_free:
|
fail_urfile_free:
|
||||||
urfile_free(urf);
|
urfile_free(urf);
|
||||||
fail_unlock:
|
fail_unlock:
|
||||||
mutex_unlock(&urd->open_mutex);
|
spin_lock(&urd->open_lock);
|
||||||
|
urd->open_flag--;
|
||||||
|
spin_unlock(&urd->open_lock);
|
||||||
fail_put:
|
fail_put:
|
||||||
urdev_put(urd);
|
urdev_put(urd);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -731,7 +738,10 @@ static int ur_release(struct inode *inode, struct file *file)
|
|||||||
struct urfile *urf = file->private_data;
|
struct urfile *urf = file->private_data;
|
||||||
|
|
||||||
TRACE("ur_release\n");
|
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);
|
urdev_put(urf->urd);
|
||||||
urfile_free(urf);
|
urfile_free(urf);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -62,7 +62,6 @@ struct file_control_block {
|
|||||||
struct urdev {
|
struct urdev {
|
||||||
struct ccw_device *cdev; /* Backpointer to ccw device */
|
struct ccw_device *cdev; /* Backpointer to ccw device */
|
||||||
struct mutex io_mutex; /* Serialises device IO */
|
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 completion *io_done; /* do_ur_io waits; irq completes */
|
||||||
struct device *device;
|
struct device *device;
|
||||||
struct cdev *char_device;
|
struct cdev *char_device;
|
||||||
@@ -71,6 +70,9 @@ struct urdev {
|
|||||||
int class; /* VM device class */
|
int class; /* VM device class */
|
||||||
int io_request_rc; /* return code from I/O request */
|
int io_request_rc; /* return code from I/O request */
|
||||||
atomic_t ref_count; /* reference counter */
|
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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user