[RHEL7,COMMIT] ms/fuse: do not take fc->lock in fuse_request_send_background()

Submitted by Konstantin Khorenko on April 30, 2019, 11:35 a.m.

Details

Message ID 201904301135.x3UBZZZD021115@finist-ce7.sw.ru
State New
Series "fuse:Backport of ms locking patches part 2"
Headers show

Commit Message

Konstantin Khorenko April 30, 2019, 11:35 a.m.
The commit is pushed to "branch-rh7-3.10.0-957.12.1.vz7.95.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.12.1.vz7.95.2
------>
commit 086bce82f96e484eceb680618439655663c8d426
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Tue Apr 30 14:35:34 2019 +0300

    ms/fuse: do not take fc->lock in fuse_request_send_background()
    
    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@virtuozzo.com>
    Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
    
    =====================
    Patchset description:
    
    fuse: Backport of ms locking patches part 2
    
    Here is backport of locking patches: introducing of fc->bg_lock and fi->lock.
    
    This may need additional changes for kio and NOT verified for fast-path.
    
    Reviewed-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
    
    Kirill Tkhai (9):
          fuse: introduce fc->bg_lock
          fuse: Remove bogus list_del_init() from-fuse_request_send_background
          fuse: do not take fc->lock in fuse_request_send_background()
          fuse: Add fuse_inode argument to fuse_prepare_release()
          fuse: Convert fc->attr_version into atomic64_t
          fuse: Introduce fi->lock to protect write related fields
          fuse: Protect fi->nlookup with fi->lock
          fuse: Protect ff->reserved_req via corresponding fi->lock
          fuse: do not take fc->lock in fuse_request_send_background() - fixup
---
 fs/fuse/dev.c    | 73 ++++++++++++++++++++++++++++----------------------------
 fs/fuse/file.c   |  4 +++-
 fs/fuse/fuse_i.h |  3 +--
 3 files changed, 41 insertions(+), 39 deletions(-)

Patch hide | download patch | download mbox

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);