[RHEL7,COMMIT] fuse kio: Round down extent start in fiemap_process_one()

Submitted by Konstantin Khorenko on Nov. 24, 2018, 2:49 p.m.

Details

Message ID 201811241449.wAOEnXhS030012@finist-ce7.sw.ru
State New
Series "fuse kio: Round down extent start in fiemap_process_one()"
Headers show

Commit Message

Konstantin Khorenko Nov. 24, 2018, 2:49 p.m.
The commit is pushed to "branch-rh7-3.10.0-862.20.2.vz7.73.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.20.2.vz7.73.8
------>
commit e195927ada4bd9afb1a00015b113d48726606e14
Author: Alexey Kuznetsov <kuznet@virtuozzo.com>
Date:   Sat Nov 24 17:49:33 2018 +0300

    fuse kio: Round down extent start in fiemap_process_one()
    
    Argument fiemap::fm_start are passed directly from userspace,
    and it doesn't have to be aligned to dentry size. If so,
    we submit a request with a chunk, which is not equal to map
    start, and the BUG_ON() inside map_submit() fires:
    
    [516315.236213] kernel BUG at fs/fuse/kio/pcs/pcs_map.c:2326!
    [516315.248305] RIP: 0010:[<ffffffffc06d8588>]  [<ffffffffc06d8588>] map_submit+0x2e8/0x310 [fuse_kio_pcs]
    [516315.257547] Call Trace:
    [516315.258523]  [<ffffffffc06dab4c>] pcs_cc_process_ireq_chunk+0x7c/0xa0 [fuse_kio_pcs]
    [516315.259538]  [<ffffffffc06dadea>] fiemap_work_func+0x27a/0x2e0 [fuse_kio_pcs]
    [516315.260559]  [<ffffffff968b7532>] process_one_work+0x182/0x440
    [516315.261577]  [<ffffffff968b86e6>] worker_thread+0x126/0x3c0
    [516315.262600]  [<ffffffff968b85c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    [516315.263635]  [<ffffffff968bf681>] kthread+0xd1/0xe0
    [516315.264665]  [<ffffffff968bf5b0>] ? create_kthread+0x60/0x60
    [516315.265700]  [<ffffffff96f54677>] ret_from_fork_nospec_begin+0x21/0x21
    [516315.266750]  [<ffffffff968bf5b0>] ? create_kthread+0x60/0x60
    
    This patch aligns requested chunk down to dentry size, as this is
    the behavior described in fiemap documentation:
    
      > the logical offset of the 1st returned extent may start before fm_start,
      > and the range covered by the last returned extent may end after fm_length.
    
    https://pmc.acronis.com/browse/VSTOR-15535
    
    Signed-off-by: Alexey Kuznetsov <kuznet@virtuozzo.com>
    [ktkhai: comment written]
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_cluster.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/kio/pcs/pcs_cluster.c b/fs/fuse/kio/pcs/pcs_cluster.c
index ee66adda3c2d..5df263f01f98 100644
--- a/fs/fuse/kio/pcs/pcs_cluster.c
+++ b/fs/fuse/kio/pcs/pcs_cluster.c
@@ -83,7 +83,9 @@  struct fiemap_iterator
 	char			*buffer;
 	unsigned int		fiemap_max;
 	u32			*mapped;
+	int			first_iter;
 
+	u64			pos;
 	struct pcs_int_request	ireq;
 	pcs_api_iorequest_t	apireq;
 	struct iov_iter		it;
@@ -190,15 +192,12 @@  static void fiemap_process_one(struct fiemap_iterator *fiter)
 	struct pcs_int_request *sreq;
 	u64 pos, end;
 
-	pos = fiter->apireq.pos;
+	pos = fiter->pos;
 	end = orig_ireq->apireq.req->pos + orig_ireq->apireq.req->size;
 
-	/*
-	 * We reuse zeroed fiter->apireq.size to detect first
-	 * iteration of the fiter. In this case we do not have
-	 * completed extents and just skip this business.
-	 */
-	if (fiter->apireq.size != 0) {
+	if (fiter->first_iter) {
+		fiter->first_iter = 0;
+	} else {
 		/* Xfer previous chunk and advance pos */
 		if (pcs_if_error(&fiter->ireq.error)) {
 			fiter->orig_ireq->error = fiter->ireq.error;
@@ -208,6 +207,7 @@  static void fiemap_process_one(struct fiemap_iterator *fiter)
 			xfer_fiemap_extents(fiter, pos, fiter->buffer,
 					    fiter->ireq.apireq.aux);
 		pos += fiter->apireq.size;
+		fiter->pos = pos;
 	}
 
 	if (pos >= end)
@@ -234,10 +234,12 @@  static void fiemap_process_one(struct fiemap_iterator *fiter)
 	sreq->iochunk.flow = pcs_flow_record(&di->mapping.ftab, 0, pos, end-pos, &di->cluster->maps.ftab);
 	sreq->iochunk.cmd = PCS_REQ_T_FIEMAP;
 	sreq->iochunk.cs_index = 0;
-	sreq->iochunk.chunk = pos;
-	sreq->iochunk.offset = 0;
+	sreq->iochunk.chunk = round_down(pos, DENTRY_CHUNK_SIZE(di));
+	sreq->iochunk.offset = pos - sreq->iochunk.chunk;
 	sreq->iochunk.dio_offset = 0;
 	sreq->iochunk.size = end - pos;
+	if (sreq->iochunk.offset + sreq->iochunk.size > DENTRY_CHUNK_SIZE(di))
+		fiter->apireq.size = sreq->iochunk.size = DENTRY_CHUNK_SIZE(di) - sreq->iochunk.offset;
 	sreq->iochunk.csl = NULL;
 	sreq->iochunk.banned_cs.val = 0;
 	sreq->iochunk.msg.destructor = NULL;
@@ -308,9 +310,8 @@  static void process_ireq_fiemap(struct pcs_int_request *orig_ireq)
 	orig_ireq->apireq.req->get_iter(orig_ireq->apireq.req->datasource, 0, it);
 	fiter->mapped = &((struct fiemap*)it->data)->fm_mapped_extents;
 
-	/* fiemap_process_one() uses this 0 to detect first iteration */
-	fiter->apireq.size = 0;
-	fiter->apireq.pos = orig_ireq->apireq.req->pos;
+	fiter->first_iter = 1;
+	fiter->pos = orig_ireq->apireq.req->pos;
 
 	queue_fiter_work(fiter);
 }