Commit 0c3796c2 authored by Martijn Coenen's avatar Martijn Coenen Committed by Jens Axboe

loop: Factor out configuring loop from status

Factor out this code into a separate function, so it can be reused by
other code more easily.
Signed-off-by: default avatarMartijn Coenen <maco@android.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 0a6ed1b5
...@@ -1251,75 +1251,43 @@ static int loop_clr_fd(struct loop_device *lo) ...@@ -1251,75 +1251,43 @@ static int loop_clr_fd(struct loop_device *lo)
return __loop_clr_fd(lo, false); return __loop_clr_fd(lo, false);
} }
/**
* loop_set_status_from_info - configure device from loop_info
* @lo: struct loop_device to configure
* @info: struct loop_info64 to configure the device with
*
* Configures the loop device parameters according to the passed
* in loop_info64 configuration.
*/
static int static int
loop_set_status(struct loop_device *lo, const struct loop_info64 *info) loop_set_status_from_info(struct loop_device *lo,
const struct loop_info64 *info)
{ {
int err; int err;
struct loop_func_table *xfer; struct loop_func_table *xfer;
kuid_t uid = current_uid(); kuid_t uid = current_uid();
struct block_device *bdev;
bool partscan = false;
bool size_changed = false;
err = mutex_lock_killable(&loop_ctl_mutex);
if (err)
return err;
if (lo->lo_encrypt_key_size &&
!uid_eq(lo->lo_key_owner, uid) &&
!capable(CAP_SYS_ADMIN)) {
err = -EPERM;
goto out_unlock;
}
if (lo->lo_state != Lo_bound) {
err = -ENXIO;
goto out_unlock;
}
if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) {
err = -EINVAL;
goto out_unlock;
}
if (lo->lo_offset != info->lo_offset ||
lo->lo_sizelimit != info->lo_sizelimit) {
size_changed = true;
sync_blockdev(lo->lo_device);
kill_bdev(lo->lo_device);
}
/* I/O need to be drained during transfer transition */ if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
blk_mq_freeze_queue(lo->lo_queue); return -EINVAL;
if (size_changed && lo->lo_device->bd_inode->i_mapping->nrpages) {
/* If any pages were dirtied after kill_bdev(), try again */
err = -EAGAIN;
pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n",
__func__, lo->lo_number, lo->lo_file_name,
lo->lo_device->bd_inode->i_mapping->nrpages);
goto out_unfreeze;
}
err = loop_release_xfer(lo); err = loop_release_xfer(lo);
if (err) if (err)
goto out_unfreeze; return err;
if (info->lo_encrypt_type) { if (info->lo_encrypt_type) {
unsigned int type = info->lo_encrypt_type; unsigned int type = info->lo_encrypt_type;
if (type >= MAX_LO_CRYPT) { if (type >= MAX_LO_CRYPT)
err = -EINVAL; return -EINVAL;
goto out_unfreeze;
}
xfer = xfer_funcs[type]; xfer = xfer_funcs[type];
if (xfer == NULL) { if (xfer == NULL)
err = -EINVAL; return -EINVAL;
goto out_unfreeze;
}
} else } else
xfer = NULL; xfer = NULL;
err = loop_init_xfer(lo, xfer, info); err = loop_init_xfer(lo, xfer, info);
if (err) if (err)
goto out_unfreeze; return err;
lo->lo_offset = info->lo_offset; lo->lo_offset = info->lo_offset;
lo->lo_sizelimit = info->lo_sizelimit; lo->lo_sizelimit = info->lo_sizelimit;
...@@ -1346,6 +1314,55 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) ...@@ -1346,6 +1314,55 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
lo->lo_key_owner = uid; lo->lo_key_owner = uid;
} }
return 0;
}
static int
loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
{
int err;
struct block_device *bdev;
kuid_t uid = current_uid();
bool partscan = false;
bool size_changed = false;
err = mutex_lock_killable(&loop_ctl_mutex);
if (err)
return err;
if (lo->lo_encrypt_key_size &&
!uid_eq(lo->lo_key_owner, uid) &&
!capable(CAP_SYS_ADMIN)) {
err = -EPERM;
goto out_unlock;
}
if (lo->lo_state != Lo_bound) {
err = -ENXIO;
goto out_unlock;
}
if (lo->lo_offset != info->lo_offset ||
lo->lo_sizelimit != info->lo_sizelimit) {
size_changed = true;
sync_blockdev(lo->lo_device);
kill_bdev(lo->lo_device);
}
/* I/O need to be drained during transfer transition */
blk_mq_freeze_queue(lo->lo_queue);
if (size_changed && lo->lo_device->bd_inode->i_mapping->nrpages) {
/* If any pages were dirtied after kill_bdev(), try again */
err = -EAGAIN;
pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n",
__func__, lo->lo_number, lo->lo_file_name,
lo->lo_device->bd_inode->i_mapping->nrpages);
goto out_unfreeze;
}
err = loop_set_status_from_info(lo, info);
if (err)
goto out_unfreeze;
if (size_changed) { if (size_changed) {
loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit, loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit,
lo->lo_backing_file); lo->lo_backing_file);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment