[Devel,vz7,11/46] fuse: use per req lock for lock/unlock_request()

Submitted by Maxim Patlasov on March 25, 2017, 2:15 a.m.

Details

Message ID 149040815221.25341.7407973919373977027.stgit@maxim-thinkpad
State New
Series "fuse: add multi-threading support"
Headers show

Commit Message

Maxim Patlasov March 25, 2017, 2:15 a.m.
Backport from ml:

commit dc00809a53edd15369906b90407a2d5b976289f5
Author: Miklos Szeredi <mszeredi@suse.cz>
Date:   Wed Jul 1 16:25:58 2015 +0200

    fuse: use per req lock for lock/unlock_request()

    Reuse req->waitq.lock for protecting FR_ABORTED and FR_LOCKED flags.

    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Reviewed-by: Ashish Samant <ashish.samant@oracle.com>

Signed-off-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
---
 fs/fuse/dev.c    |   41 ++++++++++++++++++++---------------------
 fs/fuse/fuse_i.h |    4 ++++
 2 files changed, 24 insertions(+), 21 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 29931bd..6d7db48 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -598,16 +598,16 @@  void fuse_force_forget(struct file *file, u64 nodeid)
  * anything that could cause a page-fault.  If the request was already
  * aborted bail out.
  */
-static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
+static int lock_request(struct fuse_req *req)
 {
 	int err = 0;
 	if (req) {
-		spin_lock(&fc->lock);
+		spin_lock(&req->waitq.lock);
 		if (test_bit(FR_ABORTED, &req->flags))
 			err = -ENOENT;
 		else
 			set_bit(FR_LOCKED, &req->flags);
-		spin_unlock(&fc->lock);
+		spin_unlock(&req->waitq.lock);
 	}
 	return err;
 }
@@ -616,22 +616,21 @@  static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
  * Unlock request.  If it was aborted while locked, caller is responsible
  * for unlocking and ending the request.
  */
-static int unlock_request(struct fuse_conn *fc, struct fuse_req *req)
+static int unlock_request(struct fuse_req *req)
 {
 	int err = 0;
 	if (req) {
-		spin_lock(&fc->lock);
+		spin_lock(&req->waitq.lock);
 		if (test_bit(FR_ABORTED, &req->flags))
 			err = -ENOENT;
 		else
 			clear_bit(FR_LOCKED, &req->flags);
-		spin_unlock(&fc->lock);
+		spin_unlock(&req->waitq.lock);
 	}
 	return err;
 }
 
 struct fuse_copy_state {
-	struct fuse_conn *fc;
 	int write;
 	struct fuse_req *req;
 	const struct iovec *iov;
@@ -648,12 +647,10 @@  struct fuse_copy_state {
 	unsigned move_pages:1;
 };
 
-static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
-			   int write,
+static void fuse_copy_init(struct fuse_copy_state *cs, int write,
 			   const struct iovec *iov, unsigned long nr_segs)
 {
 	memset(cs, 0, sizeof(*cs));
-	cs->fc = fc;
 	cs->write = write;
 	cs->iov = iov;
 	cs->nr_segs = nr_segs;
@@ -693,7 +690,7 @@  static int fuse_copy_fill(struct fuse_copy_state *cs)
 	unsigned long offset;
 	int err;
 
-	err = unlock_request(cs->fc, cs->req);
+	err = unlock_request(cs->req);
 	if (err)
 		return err;
 
@@ -754,7 +751,7 @@  static int fuse_copy_fill(struct fuse_copy_state *cs)
 		cs->addr += cs->len;
 	}
 
-	return lock_request(cs->fc, cs->req);
+	return lock_request(cs->req);
 }
 
 /* Do as much copy to/from userspace buffer as we can */
@@ -800,7 +797,7 @@  static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 	struct page *newpage;
 	struct pipe_buffer *buf = cs->pipebufs;
 
-	err = unlock_request(cs->fc, cs->req);
+	err = unlock_request(cs->req);
 	if (err)
 		return err;
 
@@ -857,12 +854,12 @@  static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 		lru_cache_add_file(newpage);
 
 	err = 0;
-	spin_lock(&cs->fc->lock);
+	spin_lock(&cs->req->waitq.lock);
 	if (test_bit(FR_ABORTED, &cs->req->flags))
 		err = -ENOENT;
 	else
 		*pagep = newpage;
-	spin_unlock(&cs->fc->lock);
+	spin_unlock(&cs->req->waitq.lock);
 
 	if (err) {
 		unlock_page(newpage);
@@ -882,7 +879,7 @@  out_fallback:
 	cs->mapaddr = buf->ops->map(cs->pipe, buf, 1);
 	cs->buf = cs->mapaddr + buf->offset;
 
-	err = lock_request(cs->fc, cs->req);
+	err = lock_request(cs->req);
 	if (err)
 		return err;
 
@@ -898,7 +895,7 @@  static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
 	if (cs->nr_segs == cs->pipe->buffers)
 		return -EIO;
 
-	err = unlock_request(cs->fc, cs->req);
+	err = unlock_request(cs->req);
 	if (err)
 		return err;
 
@@ -1320,7 +1317,7 @@  static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
 	if (!fc)
 		return -EPERM;
 
-	fuse_copy_init(&cs, fc, 1, iov, nr_segs);
+	fuse_copy_init(&cs, 1, iov, nr_segs);
 
 	return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs));
 }
@@ -1358,7 +1355,7 @@  static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
 	if (!bufs)
 		return -ENOMEM;
 
-	fuse_copy_init(&cs, fc, 1, NULL, 0);
+	fuse_copy_init(&cs, 1, NULL, 0);
 	cs.pipebufs = bufs;
 	cs.pipe = pipe;
 	ret = fuse_dev_do_read(fc, in, &cs, len);
@@ -1965,7 +1962,7 @@  static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
 	if (!fc)
 		return -EPERM;
 
-	fuse_copy_init(&cs, fc, 0, iov, nr_segs);
+	fuse_copy_init(&cs, 0, iov, nr_segs);
 
 	return fuse_dev_do_write(fc, &cs, iov_length(iov, nr_segs));
 }
@@ -2030,7 +2027,7 @@  static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
 	}
 	pipe_unlock(pipe);
 
-	fuse_copy_init(&cs, fc, 0, NULL, nbuf);
+	fuse_copy_init(&cs, 0, NULL, nbuf);
 	cs.pipebufs = bufs;
 	cs.pipe = pipe;
 
@@ -2104,9 +2101,11 @@  __acquires(fc->lock)
 
 	list_for_each_entry_safe(req, next, &fc->io, list) {
 		req->out.h.error = -ECONNABORTED;
+		spin_lock(&req->waitq.lock);
 		set_bit(FR_ABORTED, &req->flags);
 		if (!test_bit(FR_LOCKED, &req->flags))
 			list_move(&req->list, &to_end);
+		spin_unlock(&req->waitq.lock);
 	}
 	while (!list_empty(&to_end)) {
 		req = list_first_entry(&to_end, struct fuse_req, list);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 31062a0..b96b6e7 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -306,6 +306,10 @@  enum fuse_req_flag {
 
 /**
  * A request to the client
+ *
+ * .waitq.lock protects the following fields:
+ *   - FR_ABORTED
+ *   - FR_LOCKED (may also be modified under fc->lock, tested under both)
  */
 struct fuse_req {
 	/** This can be on either pending processing or io lists in