From 6b3e18ada19c05395dd2e91f4bfeb5cc620c62f4 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 21 Jul 2020 14:36:19 +0200 Subject: Kernel 5.4 --- loop_file_fmt_raw.c | 27 +++++++++--------- loop_main.c | 81 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/loop_file_fmt_raw.c b/loop_file_fmt_raw.c index 134a794..baa5602 100644 --- a/loop_file_fmt_raw.c +++ b/loop_file_fmt_raw.c @@ -78,7 +78,7 @@ static int raw_file_fmt_read_transfer(struct loop_file_fmt *lo_fmt, b.bv_offset = 0; b.bv_len = bvec.bv_len; - iov_iter_bvec(&i, ITER_BVEC, &b, 1, b.bv_len); + iov_iter_bvec(&i, READ, &b, 1, b.bv_len); len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); if (len < 0) { ret = len; @@ -125,7 +125,7 @@ static int raw_file_fmt_read(struct loop_file_fmt *lo_fmt, pos = __raw_file_fmt_rq_get_pos(lo_fmt, rq); rq_for_each_segment(bvec, rq, iter) { - iov_iter_bvec(&i, ITER_BVEC, &bvec, 1, bvec.bv_len); + iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len); len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); if (len < 0) return len; @@ -171,13 +171,15 @@ static int __raw_file_fmt_rw_aio(struct loop_file_fmt *lo_fmt, bool rw) { struct iov_iter iter; + struct req_iterator rq_iter; struct bio_vec *bvec; struct bio *bio = rq->bio; struct file *file; + struct bio_vec tmp; struct loop_device *lo; struct loop_cmd *cmd; unsigned int offset; - int segments = 0; + int nr_bvec = 0; int ret; loff_t pos; @@ -186,13 +188,12 @@ static int __raw_file_fmt_rw_aio(struct loop_file_fmt *lo_fmt, cmd = blk_mq_rq_to_pdu(rq); pos = __raw_file_fmt_rq_get_pos(lo_fmt, rq); + rq_for_each_bvec(tmp, rq, rq_iter) + nr_bvec++; + if (rq->bio != rq->biotail) { - struct req_iterator iter; - struct bio_vec tmp; - __rq_for_each_bio(bio, rq) - segments += bio_segments(bio); - bvec = kmalloc_array(segments, sizeof(struct bio_vec), + bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec), GFP_NOIO); if (!bvec) return -EIO; @@ -201,10 +202,10 @@ static int __raw_file_fmt_rw_aio(struct loop_file_fmt *lo_fmt, /* * The bios of the request may be started from the middle of * the 'bvec' because of bio splitting, so we can't directly - * copy bio->bi_iov_vec to new bvec. The rq_for_each_segment + * copy bio->bi_iov_vec to new bvec. The rq_for_each_bvec * API will take care of all details for us. */ - rq_for_each_segment(tmp, rq, iter) { + rq_for_each_bvec(tmp, rq, rq_iter) { *bvec = tmp; bvec++; } @@ -218,12 +219,10 @@ static int __raw_file_fmt_rw_aio(struct loop_file_fmt *lo_fmt, */ offset = bio->bi_iter.bi_bvec_done; bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); - segments = bio_segments(bio); } atomic_set(&cmd->ref, 2); - iov_iter_bvec(&iter, ITER_BVEC | rw, bvec, - segments, blk_rq_bytes(rq)); + iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq)); iter.iov_offset = offset; cmd->iocb.ki_pos = pos; @@ -260,7 +259,7 @@ static int __raw_file_fmt_write_bvec(struct file *file, struct iov_iter i; ssize_t bw; - iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len); + iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len); file_start_write(file); bw = vfs_iter_write(file, &i, ppos, 0); diff --git a/loop_main.c b/loop_main.c index 365f66b..1e13c8f 100644 --- a/loop_main.c +++ b/loop_main.c @@ -79,6 +79,7 @@ #include #include #include +#include #include "loop_file_fmt.h" #include "loop_main.h" @@ -241,7 +242,6 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit) lo->lo_offset = offset; if (lo->lo_sizelimit != sizelimit) lo->lo_sizelimit = sizelimit; - set_capacity(lo->lo_disk, x); bd_set_size(bdev, (loff_t)get_capacity(bdev->bd_disk) << 9); /* let user-space know about the new size */ @@ -307,7 +307,6 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) default: WARN_ON_ONCE(1); return -EIO; - break; } } @@ -473,31 +472,14 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) return ret; } -static ssize_t __print_file_fmt_type(__u32 file_fmt_type, char* buf) { - switch(file_fmt_type) { - case LO_FILE_FMT_RAW: - sprintf(buf, "%s\n", "RAW"); - break; - case LO_FILE_FMT_QCOW: - sprintf(buf, "%s\n", "QCOW"); - break; - case LO_FILE_FMT_VDI: - sprintf(buf, "%s\n", "VDI"); - break; - case LO_FILE_FMT_VMDK: - sprintf(buf, "%s\n", "VMDK"); - break; - default: - sprintf(buf, "%s\n", "ERROR: Unsupported loop file format!"); - break; - } - - return strlen(buf); -} - static ssize_t loop_attr_file_fmt_type_show(struct loop_device *lo, char *buf) { - return __print_file_fmt_type(lo->lo_fmt->file_fmt_type, buf); + ssize_t len = 0; + + len = loop_file_fmt_print_type(lo->lo_fmt->file_fmt_type, buf); + len += sprintf(buf + len, "\n"); + + return len; } static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) @@ -621,12 +603,31 @@ static int loop_prepare_queue(struct loop_device *lo) return 0; } +static void loop_update_rotational(struct loop_device *lo) +{ + struct file *file = lo->lo_backing_file; + struct inode *file_inode = file->f_mapping->host; + struct block_device *file_bdev = file_inode->i_sb->s_bdev; + struct request_queue *q = lo->lo_queue; + bool nonrot = true; + + /* not all filesystems (e.g. tmpfs) have a sb->s_bdev */ + if (file_bdev) + nonrot = blk_queue_nonrot(bdev_get_queue(file_bdev)); + + if (nonrot) + blk_queue_flag_set(QUEUE_FLAG_NONROT, q); + else + blk_queue_flag_clear(QUEUE_FLAG_NONROT, q); +} + static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { struct file *file; struct inode *inode; struct address_space *mapping; + struct block_device *claimed_bdev = NULL; int lo_flags = 0; int error; loff_t size; @@ -640,9 +641,21 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, if (!file) goto out; + /* + * If we don't hold exclusive handle for the device, upgrade to it + * here to avoid changing device under exclusive owner. + */ + if (!(mode & FMODE_EXCL)) { + claimed_bdev = bd_start_claiming(bdev, loop_set_fd); + if (IS_ERR(claimed_bdev)) { + error = PTR_ERR(claimed_bdev); + goto out_putf; + } + } + error = mutex_lock_killable(&loop_ctl_mutex); if (error) - goto out_putf; + goto out_bdev; error = -EBUSY; if (lo->lo_state != Lo_unbound) @@ -674,6 +687,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync) blk_queue_write_cache(lo->lo_queue, true, false); + loop_update_rotational(lo); loop_update_dio(lo); error = loop_file_fmt_init(lo->lo_fmt, LO_FILE_FMT_RAW); @@ -710,10 +724,15 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, mutex_unlock(&loop_ctl_mutex); if (partscan) loop_reread_partitions(lo, bdev); + if (claimed_bdev) + bd_abort_claiming(bdev, claimed_bdev, loop_set_fd); return 0; out_unlock: mutex_unlock(&loop_ctl_mutex); +out_bdev: + if (claimed_bdev) + bd_abort_claiming(bdev, claimed_bdev, loop_set_fd); out_putf: fput(file); out: @@ -1013,7 +1032,6 @@ loop_set_status(struct loop_device *lo, const struct xloop_info64 *info) lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_init[0] = info->lo_init[0]; lo->lo_init[1] = info->lo_init[1]; - lo->lo_fmt->file_fmt_type = info->lo_file_fmt_type; if (info->lo_encrypt_key_size) { memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, info->lo_encrypt_key_size); @@ -1468,7 +1486,6 @@ loop_info64_to_compat(const struct xloop_info64 *info64, if (err) return -EFAULT; - return 0; } @@ -1671,8 +1688,8 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, /* always use the first bio's css */ #ifdef CONFIG_BLK_CGROUP - if (cmd->use_aio && rq->bio && rq->bio->bi_css) { - cmd->css = rq->bio->bi_css; + if (cmd->use_aio && rq->bio && rq->bio->bi_blkg) { + cmd->css = &bio_blkcg(rq->bio)->css; css_get(cmd->css); } else #endif @@ -1759,7 +1776,7 @@ static int loop_add(struct loop_device **l, int i) lo->tag_set.queue_depth = 128; lo->tag_set.numa_node = NUMA_NO_NODE; lo->tag_set.cmd_size = sizeof(struct loop_cmd); - lo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE; + lo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; lo->tag_set.driver_data = lo; err = blk_mq_alloc_tag_set(&lo->tag_set); @@ -1767,7 +1784,7 @@ static int loop_add(struct loop_device **l, int i) goto out_free_idr; lo->lo_queue = blk_mq_init_queue(&lo->tag_set); - if (IS_ERR_OR_NULL(lo->lo_queue)) { + if (IS_ERR(lo->lo_queue)) { err = PTR_ERR(lo->lo_queue); goto out_cleanup_tags; } -- cgit v1.2.3-55-g7522