return err;
}
+static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
+{
+ int err;
+ sector_t sec;
+ loff_t sz;
+
+ err = -ENXIO;
+ if (unlikely(lo->lo_state != Lo_bound))
+ goto out;
+ err = figure_loop_size(lo);
+ if (unlikely(err))
+ goto out;
+ sec = get_capacity(lo->lo_disk);
+ /* the width of sector_t may be narrow for bit-shift */
+ sz = sec;
+ sz <<= 9;
+ mutex_lock(&bdev->bd_mutex);
+ bd_set_size(bdev, sz);
+ mutex_unlock(&bdev->bd_mutex);
+
+ out:
+ return err;
+}
+
static int lo_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
case LOOP_GET_STATUS64:
err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
break;
+ case LOOP_SET_CAPACITY:
+ err = -EPERM;
+ if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+ err = loop_set_capacity(lo, bdev);
+ break;
default:
err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
}
lo, (struct compat_loop_info __user *) arg);
mutex_unlock(&lo->lo_ctl_mutex);
break;
+ case LOOP_SET_CAPACITY:
case LOOP_CLR_FD:
case LOOP_GET_STATUS64:
case LOOP_SET_STATUS64:
static int lo_release(struct gendisk *disk, fmode_t mode)
{
struct loop_device *lo = disk->private_data;
+ int err;
mutex_lock(&lo->lo_ctl_mutex);
* In autoclear mode, stop the loop thread
* and remove configuration after last close.
*/
- loop_clr_fd(lo, NULL);
+ err = loop_clr_fd(lo, NULL);
+ if (!err)
+ goto out_unlocked;
} else {
/*
* Otherwise keep thread (if running) and config,
out:
mutex_unlock(&lo->lo_ctl_mutex);
-
+out_unlocked:
return 0;
}