[Devel] [PATCH 3/8] fuse: do not take fc->lock in fuse_request_send_background()

Kirill Tkhai ktkhai at virtuozzo.com
Wed Apr 3 18:37:16 MSK 2019


ms commit 63825b4e1da5

Currently, we take fc->lock there only to check for fc->connected.
But this flag is changed only on connection abort, which is very
rare operation.

So allow checking fc->connected under just fc->bg_lock and use this lock
(as well as fc->lock) when resetting fc->connected.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
Signed-off-by: Miklos Szeredi <mszeredi at redhat.com>
---
 fs/fuse/dev.c    |   73 +++++++++++++++++++++++++++---------------------------
 fs/fuse/file.c   |    4 ++-
 fs/fuse/fuse_i.h |    3 +-
 3 files changed, 41 insertions(+), 39 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 1ffc10ff18ba..1355f4a0a8e4 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -598,69 +598,70 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
 }
 EXPORT_SYMBOL_GPL(fuse_request_send);
 
-/*
- * Called under fc->lock
- *
- * fc->connected must have been checked previously
- */
-void fuse_request_send_background_nocheck(struct fuse_conn *fc,
-					  struct fuse_req *req)
+bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req)
 {
 	struct fuse_iqueue *fiq = req->fiq;
+	bool queued = false;
 
-	BUG_ON(!test_bit(FR_BACKGROUND, &req->flags));
-
+	WARN_ON(!test_bit(FR_BACKGROUND, &req->flags));
 	if (!test_bit(FR_WAITING, &req->flags)) {
 		__set_bit(FR_WAITING, &req->flags);
 		atomic_inc(&fc->num_waiting);
 	}
 	__set_bit(FR_ISREPLY, &req->flags);
 	spin_lock(&fc->bg_lock);
-	fc->num_background++;
-	if (fc->num_background == fc->max_background)
-		fc->blocked = 1;
-	if (fc->num_background == fc->congestion_threshold &&
-	    fc->bdi_initialized) {
-		set_bdi_congested(&fc->bdi, BLK_RW_SYNC);
-		set_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
-	}
+	if (likely(fc->connected)) {
+		fc->num_background++;
+		if (fc->num_background == fc->max_background)
+			fc->blocked = 1;
+		if (fc->num_background == fc->congestion_threshold && fc->sb) {
+			set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
+			set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
+		}
 
-	if (test_bit(FR_NONBLOCKING, &req->flags)) {
-		fc->active_background++;
-		spin_lock(&fiq->waitq.lock);
-		req->in.h.unique = fuse_get_unique(fiq);
-		queue_request(fiq, req);
-		spin_unlock(&fiq->waitq.lock);
-		goto unlock;
-	}
+		if (test_bit(FR_NONBLOCKING, &req->flags)) {
+			fc->active_background++;
+			spin_lock(&fiq->waitq.lock);
+			req->in.h.unique = fuse_get_unique(fiq);
+			queue_request(fiq, req);
+			spin_unlock(&fiq->waitq.lock);
+			queued = true;
+			goto unlock;
+		}
 
-	list_add_tail(&req->list, &fc->bg_queue);
-	flush_bg_queue(fc, fiq);
+		list_add_tail(&req->list, &fc->bg_queue);
+		flush_bg_queue(fc, fiq);
+		queued = true;
+        }
 unlock:
 	spin_unlock(&fc->bg_lock);
+	return queued;
 }
 
 void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
 {
-	BUG_ON(!req->end);
+	bool fail;
+	WARN_ON(!req->end);
 
 	if (fc->kio.op && !fc->kio.op->req_send(fc, req, true, false))
 		return;
 
 	spin_lock(&fc->lock);
-	if (req->page_cache && req->ff &&
-	    test_bit(FUSE_S_FAIL_IMMEDIATELY, &req->ff->ff_state)) {
+	fail = (req->page_cache && req->ff &&
+		test_bit(FUSE_S_FAIL_IMMEDIATELY, &req->ff->ff_state));
+	spin_unlock(&fc->lock);
+
+	if (fail) {
+		/* FIXME */
 		BUG_ON(req->in.h.opcode != FUSE_READ);
 		req->out.h.error = -EIO;
 		__clear_bit(FR_BACKGROUND, &req->flags);
 		__clear_bit(FR_PENDING, &req->flags);
-		spin_unlock(&fc->lock);
 		request_end(fc, req);
-	} else if (fc->connected) {
-		fuse_request_send_background_nocheck(fc, req);
-		spin_unlock(&fc->lock);
-	} else {
-		spin_unlock(&fc->lock);
+		return;
+	}
+
+	if (!fuse_request_queue_background(fc, req)) {
 		req->out.h.error = -ENOTCONN;
 		req->end(fc, req);
 		fuse_put_request(fc, req);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index edc314bd7156..6bffa1eef4dd 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1941,6 +1941,7 @@ __acquires(fc->lock)
 	loff_t size = i_size_read(req->inode);
 	struct fuse_write_in *inarg = &req->misc.write.in;
 	__u64 data_size = req->num_pages * PAGE_CACHE_SIZE;
+	bool queued;
 
 	if (!fc->connected ||
 	    test_bit(FUSE_S_FAIL_IMMEDIATELY, &req->ff->ff_state))
@@ -1957,7 +1958,8 @@ __acquires(fc->lock)
 
 	req->in.args[1].size = inarg->size;
 	fi->writectr++;
-	fuse_request_send_background_nocheck(fc, req);
+	queued = fuse_request_queue_background(fc, req);
+	WARN_ON(!queued);
 	return;
 
  out_free:
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a6eb566f8789..ee8b367f2956 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -979,8 +979,7 @@ void fuse_request_check_and_send(struct fuse_conn *fc, struct fuse_req *req,
  */
 void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req);
 
-void fuse_request_send_background_nocheck(struct fuse_conn *fc,
-					  struct fuse_req *req);
+bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req);
 
 /* Abort all requests */
 void fuse_abort_conn(struct fuse_conn *fc);



More information about the Devel mailing list