[Devel] [PATCH RHEL7 COMMIT] fs/fuse kio_pcs: split kpcs_req_send()

Konstantin Khorenko khorenko at virtuozzo.com
Tue Oct 9 12:19:01 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-862.14.4.vz7.72.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.14.4.vz7.72.4
------>
commit c849be3b4414fdcbff6a53bfa88ad0797c3ffb4d
Author: Pavel Butsykin <pbutsykin at virtuozzo.com>
Date:   Tue Oct 9 12:18:59 2018 +0300

    fs/fuse kio_pcs: split kpcs_req_send()
    
    Cosmetic patch, aimed at improving code readability.
    
    Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
    Reviewed-by: Kirill Tkhai <ktkhai at virtuozzo.com>
    
    =====================
    Patchset description:
    
    Fuse: Fix IOCB_CMD_UNMAP_ITER handling to prevent cache inconsistency
    
    https://pmc.acronis.com/browse/VSTOR-15447
    
    Ploop can asynchronously unmap regions by sending IOCB_CMD_UNMAP_ITER, but this
    command isn't quite correctly interpreted in Fuse. Moreover, in Fast-path mode,
    fallocate(FALLOC_FL_PUNCH_HOLE|FALLOC_FL_ZERO_RANGE) falls to fuse user daemon
    and it can lead to data corruption.
    
    Let's fix it.
    
    Pavel Butsykin (4):
      fs/fuse: fix mutually exclusive flags in fuse_send_unmap()
      fs/fuse: initialize req->io_inode in fuse_send_unmap()
      fs/fuse kio_pcs: split kpcs_req_send()
      fs/fuse kio_pcs: prevention of falling kio reqs to usermode
---
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 104 +++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 44 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 0d2ce6b8828c..3143d24d7544 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -1028,65 +1028,55 @@ static void _pcs_grow_end(struct fuse_conn *fc, struct fuse_req *req)
 	kpcs_setattr_end(fc, req);
 }
 
-static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bool lk)
+static void pcs_kio_setattr_handle(struct fuse_req *req)
 {
-	struct pcs_fuse_cluster *pfc = (struct pcs_fuse_cluster*)fc->kio.ctx;
 	struct fuse_inode *fi = get_fuse_inode(req->io_inode);
+	struct pcs_fuse_req *r = pcs_req_from_fuse(req);
+	struct fuse_setattr_in *inarg = (void*) req->in.args[0].value;
+	struct pcs_dentry_info *di;
 
-	if (!fc->initialized || fc->conn_error)
-		return 1;
+	if (!(inarg->valid & FATTR_SIZE))
+		return;
 
-	BUG_ON(!pfc);
-	/* HYPOTHESIS #1
-	 * IFAIU at this point request can not belongs to any list
-	 * so I cant avoid grab fc->lock here at all
-	 */
-	BUG_ON(!list_empty(&req->list));
+	BUG_ON(!fi);
 
-	TRACE(" Enter req:%p op:%d end:%p bg:%d lk:%d\n", req, req->in.h.opcode, req->end, bg, lk);
+	di = pcs_inode_from_fuse(fi);
+	spin_lock(&di->lock);
+	if (inarg->size < di->fileinfo.attr.size) {
+		BUG_ON(di->size.op != PCS_SIZE_INACTION);
+		di->size.op = PCS_SIZE_SHRINK;
+	}
+	spin_unlock(&di->lock);
 
-	if (!fi || !fi->private)
-		return 1;
+	r->end = req->end;
+	if (di->size.op == PCS_SIZE_SHRINK) {
+		BUG_ON(!mutex_is_locked(&req->io_inode->i_mutex));
+		/* wait for aio reads in flight */
+		inode_dio_wait(req->io_inode);
+		/*
+		 * Writebackcache was flushed already so it is safe to
+		 * drop pcs_mapping
+		 */
+		pcs_map_invalidate_tail(&di->mapping, inarg->size);
+		req->end = _pcs_shrink_end;
+	} else
+		req->end = _pcs_grow_end;
+}
 
+static int pcs_kio_classify_req(struct fuse_conn *fc, struct fuse_req *req)
+{
 	switch (req->in.h.opcode) {
-	case FUSE_SETATTR: {
-		struct pcs_fuse_req *r = pcs_req_from_fuse(req);
-		struct fuse_setattr_in *inarg = (void*) req->in.args[0].value;
-		struct pcs_dentry_info *di;
-
-		if (!(inarg->valid & FATTR_SIZE))
-			return 1;
-
-		di = pcs_inode_from_fuse(fi);
-		spin_lock(&di->lock);
-		if (inarg->size < di->fileinfo.attr.size) {
-			BUG_ON(di->size.op != PCS_SIZE_INACTION);
-			di->size.op = PCS_SIZE_SHRINK;
-		}
-		spin_unlock(&di->lock);
-		r->end = req->end;
-		if (di->size.op == PCS_SIZE_SHRINK) {
-			BUG_ON(!mutex_is_locked(&req->io_inode->i_mutex));
-			/* wait for aio reads in flight */
-			inode_dio_wait(req->io_inode);
-			/*
-			 * Writebackcache was flushed already so it is safe to
-			 * drop pcs_mapping
-			 */
-			pcs_map_invalidate_tail(&di->mapping, inarg->size);
-			req->end = _pcs_shrink_end;
-		} else
-			req->end = _pcs_grow_end;
-		return 1;
-	}
 	case FUSE_READ:
 	case FUSE_WRITE:
 	case FUSE_FSYNC:
 	case FUSE_FLUSH:
 	case FUSE_FALLOCATE:
 		break;
+	case FUSE_SETATTR:
+		pcs_kio_setattr_handle(req);
+		return 1;
 	case FUSE_IOCTL: {
-		struct fuse_ioctl_in const * inarg = req->in.args[0].value;
+		struct fuse_ioctl_in const *inarg = req->in.args[0].value;
 
 		if (inarg->cmd != FS_IOC_FIEMAP)
 			return 1;
@@ -1097,6 +1087,32 @@ static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bo
 		return 1;
 	}
 
+	return 0;
+}
+
+static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bool lk)
+{
+	struct pcs_fuse_cluster *pfc = (struct pcs_fuse_cluster*)fc->kio.ctx;
+	struct fuse_inode *fi = get_fuse_inode(req->io_inode);
+
+	if (!fc->initialized || fc->conn_error)
+		return 1;
+
+	BUG_ON(!pfc);
+	/* HYPOTHESIS #1
+	 * IFAIU at this point request can not belongs to any list
+	 * so I cant avoid grab fc->lock here at all
+	 */
+	BUG_ON(!list_empty(&req->list));
+
+	TRACE(" Enter req:%p op:%d end:%p bg:%d lk:%d\n", req, req->in.h.opcode, req->end, bg, lk);
+
+	if (!fi || !fi->private)
+		return 1;
+
+	if (pcs_kio_classify_req(fc, req))
+		return 1;
+
 	/* request_end below will do fuse_put_request() */
 	if (!bg)
 		atomic_inc(&req->count);



More information about the Devel mailing list