Commit 3148ffbd authored by Omar Sandoval's avatar Omar Sandoval Committed by Jens Axboe
Browse files

loop: use killable lock in ioctls



Even after the previous patch to drop lo_ctl_mutex while calling
vfs_getattr(), there are other cases where we can end up sleeping for a
long time while holding lo_ctl_mutex. Let's avoid the uninterruptible
sleep from the ioctls.

Signed-off-by: default avatarOmar Sandoval <osandov@fb.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 2d1d4c1e
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -1360,7 +1360,10 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
	struct loop_device *lo = bdev->bd_disk->private_data;
	int err;

	mutex_lock_nested(&lo->lo_ctl_mutex, 1);
	err = mutex_lock_killable_nested(&lo->lo_ctl_mutex, 1);
	if (err)
		goto out_unlocked;

	switch (cmd) {
	case LOOP_SET_FD:
		err = loop_set_fd(lo, mode, bdev, arg);
@@ -1545,16 +1548,20 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,

	switch(cmd) {
	case LOOP_SET_STATUS:
		mutex_lock(&lo->lo_ctl_mutex);
		err = loop_set_status_compat(
			lo, (const struct compat_loop_info __user *) arg);
		err = mutex_lock_killable(&lo->lo_ctl_mutex);
		if (!err) {
			err = loop_set_status_compat(lo,
						     (const struct compat_loop_info __user *)arg);
			mutex_unlock(&lo->lo_ctl_mutex);
		}
		break;
	case LOOP_GET_STATUS:
		mutex_lock(&lo->lo_ctl_mutex);
		err = loop_get_status_compat(
			lo, (struct compat_loop_info __user *) arg);
		err = mutex_lock_killable(&lo->lo_ctl_mutex);
		if (!err) {
			err = loop_get_status_compat(lo,
						     (struct compat_loop_info __user *)arg);
			/* loop_get_status() unlocks lo_ctl_mutex */
		}
		break;
	case LOOP_SET_CAPACITY:
	case LOOP_CLR_FD:
@@ -1959,7 +1966,9 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd,
		ret = loop_lookup(&lo, parm);
		if (ret < 0)
			break;
		mutex_lock(&lo->lo_ctl_mutex);
		ret = mutex_lock_killable(&lo->lo_ctl_mutex);
		if (ret)
			break;
		if (lo->lo_state != Lo_unbound) {
			ret = -EBUSY;
			mutex_unlock(&lo->lo_ctl_mutex);