[Devel] [PATCH 1/2] fs/fuse kio: cosmetic changes in pcs_fuse_prep_rw()

Pavel Butsykin pbutsykin at virtuozzo.com
Fri May 31 16:44:54 MSK 2019


This is preparation patch with cosmetic changes in pcs_fuse_prep_rw(),
it will be needed for the next patch.

At first glance it seems there is no reason in performing pcs_fuse_prep_io()
under di->lock, but it makes sense when kio request is queued to di->size.queue.
If we release di->lock before pcs_fuse_prep_io(), then non-initialized request
can begin to be processed in fuse_size_grow_work(). The same goes for
inode_dio_begin(). This patch makes this point a little more obvious.

Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 117 +++++++++++++++++++++++--------------
 1 file changed, 74 insertions(+), 43 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index acba12ede5f3..d97854ade4e8 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -857,18 +857,34 @@ static bool kqueue_insert(struct pcs_dentry_info *di, struct fuse_file *ff,
 	return true;
 }
 
+static inline int req_wait_grow_queue(struct pcs_fuse_req *r,
+				      struct fuse_file *ff, u16 type,
+				      off_t offset, size_t size)
+{
+	struct pcs_dentry_info *di = get_pcs_inode(r->req.io_inode);
+
+	if (!kqueue_insert(di, ff, &r->req))
+		return -EIO;
+
+	pcs_fuse_prep_io(r, type, offset, size, 0);
+	inode_dio_begin(r->req.io_inode);
+	wait_grow(r, di, offset + size);
+	return 1;
+}
+
 /*
  * Check i size boundary and deffer request if necessary
  * Ret code
  * 0: ready for submission
- * -1: should fail request
+ * -EIO: should fail request
+ * -EPERM: Nope
  * 1: request placed to pended queue
 */
 static int pcs_fuse_prep_rw(struct pcs_fuse_req *r, struct fuse_file *ff)
 {
-	struct fuse_inode *fi = get_fuse_inode(r->req.io_inode);
-	struct pcs_dentry_info *di = pcs_inode_from_fuse(fi);
-	int ret = 0;
+	struct fuse_req *req = &r->req;
+	struct pcs_dentry_info *di = get_pcs_inode(req->io_inode);
+	int ret;
 
 	spin_lock(&di->lock);
 	/* Deffer all requests if shrink requested to prevent livelock */
@@ -880,38 +896,45 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r, struct fuse_file *ff)
 		}
 		wait_shrink(r, di);
 		ret = 1;
-		goto out;
+		goto pending;
 	}
-	if (r->req.in.h.opcode == FUSE_READ) {
+
+	switch (req->in.h.opcode) {
+	case FUSE_READ: {
 		size_t size;
-		struct fuse_read_in *in = &r->req.misc.read.in;
+		struct fuse_read_in *in = &req->misc.read.in;
 
 		size = in->size;
 		if (in->offset + in->size > di->fileinfo.attr.size) {
 			if (in->offset >= di->fileinfo.attr.size) {
-				r->req.out.args[0].size = 0;
+				req->out.args[0].size = 0;
 				ret = -EPERM;
-				goto out;
+				goto fail;
 			}
 			size = di->fileinfo.attr.size - in->offset;
 		}
+		spin_unlock(&di->lock);
+
 		pcs_fuse_prep_io(r, PCS_REQ_T_READ, in->offset, size, 0);
-	} else if (r->req.in.h.opcode == FUSE_WRITE) {
-		struct fuse_write_in *in = &r->req.misc.write.in;
+		break;
+	}
+	case FUSE_WRITE: {
+		struct fuse_write_in *in = &req->misc.write.in;
 
 		if (in->offset + in->size > di->fileinfo.attr.size) {
-			if (!kqueue_insert(di, ff, &r->req)) {
-				ret = -EIO;
-				goto out;
-			}
-			wait_grow(r, di, in->offset + in->size);
-			ret = 1;
+			ret = req_wait_grow_queue(r, ff, PCS_REQ_T_WRITE,
+						  in->offset, in->size);
+			goto pending;
 		}
+		spin_unlock(&di->lock);
+
 		pcs_fuse_prep_io(r, PCS_REQ_T_WRITE, in->offset, in->size, 0);
-	} else if (r->req.in.h.opcode == FUSE_IOCTL) {
+		break;
+	}
+	case FUSE_IOCTL: {
 		size_t size;
-		struct fiemap const *in = r->req.in.args[1].value;
-		struct fiemap *out = r->req.out.args[1].value;
+		struct fiemap const *in = req->in.args[1].value;
+		struct fiemap *out = req->out.args[1].value;
 
 		*out = *in;
 		out->fm_mapped_extents = 0;
@@ -920,40 +943,48 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r, struct fuse_file *ff)
 		if (in->fm_start + size > di->fileinfo.attr.size) {
 			if (in->fm_start >= di->fileinfo.attr.size) {
 				ret = -EPERM;
-				goto out;
+				goto fail;
 			}
 			size = di->fileinfo.attr.size - in->fm_start;
 		}
-		pcs_fuse_prep_io(r, PCS_REQ_T_FIEMAP, in->fm_start, in->fm_extent_count*sizeof(struct fiemap_extent),
+		spin_unlock(&di->lock);
+
+		pcs_fuse_prep_io(r, PCS_REQ_T_FIEMAP, in->fm_start,
+				 in->fm_extent_count*sizeof(struct fiemap_extent),
 				 in->fm_extent_count);
 		r->exec.io.req.size = size;
-	} else {
-		struct fuse_fallocate_in const *in = r->req.in.args[0].value;
-
-		if (in->offset + in->length > di->fileinfo.attr.size) {
-			if (!kqueue_insert(di, ff, &r->req)) {
-				ret = -EIO;
-				goto out;
-			}
-			wait_grow(r, di, in->offset + in->length);
-			ret = 1;
-		}
+		break;
+	}
+	case FUSE_FALLOCATE: {
+		struct fuse_fallocate_in const *in = req->in.args[0].value;
+		u16 type;
 
 		if (in->mode & FALLOC_FL_PUNCH_HOLE)
-			pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_HOLE, in->offset, in->length, 0);
+			type = PCS_REQ_T_WRITE_HOLE;
 		else if (in->mode & FALLOC_FL_ZERO_RANGE)
-			pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_ZERO, in->offset, in->length, 0);
+			type = PCS_REQ_T_WRITE_ZERO;
 		else {
-			if (ret) {
-				pcs_fuse_prep_fallocate(r);
-			} else {
-				ret = -EPERM;
-				goto out;
-			}
+			ret = -EPERM;
+			goto fail;
 		}
+
+		if (in->offset + in->length > di->fileinfo.attr.size) {
+			ret = req_wait_grow_queue(r, ff, type, in->offset,
+						  in->length);
+			goto pending;
+		}
+		spin_unlock(&di->lock);
+
+		pcs_fuse_prep_io(r, type, in->offset, in->length, 0);
+		break;
+	}
+	default:
+		BUG();
 	}
-	inode_dio_begin(r->req.io_inode);
-out:
+	inode_dio_begin(req->io_inode);
+	return 0;
+fail:
+pending:
 	spin_unlock(&di->lock);
 	return ret;
 }
-- 
2.15.1



More information about the Devel mailing list