[RHEL7,COMMIT] ms/fuse: add locking to max_background and congestion_threshold changes

Submitted by Konstantin Khorenko on Oct. 4, 2018, 9:31 a.m.

Details

Message ID 201810040931.w949VK9P023015@finist_ce7.work
State New
Series "ms/fuse: add locking to max_background and congestion_threshold changes"
Headers show

Commit Message

Konstantin Khorenko Oct. 4, 2018, 9:31 a.m.
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.2
------>
commit f33c7bdcf475e5cbbd9bccc8438d4b7ff10c0d12
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Thu Oct 4 12:31:20 2018 +0300

    ms/fuse: add locking to max_background and congestion_threshold changes
    
    Functions sequences like request_end()->flush_bg_queue() require that
    max_background and congestion_threshold are constant during their
    execution. Otherwise, checks like
    
        if (fc->num_background == fc->max_background)
    
    made in different time may behave not like expected.
    
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    
    Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
    =====================
    Patchset description:
    
    Relax lock contention and ms fixes
    
    https://pmc.acronis.com/browse/VSTOR-9810
    
    Port some ms fixes and begin first round of relaxing fc->lock contention.
    
    Kirill Tkhai (5):
          fuse: Fix use-after-free in fuse_dev_do_read()
          fuse: Fix use-after-free in fuse_dev_do_write()
          fuse: use list_first_entry() in flush_bg_queue()
          fuse: use READ_ONCE on congestion_threshold and max_background
          fuse: add locking to max_background and congestion_threshold changes
    
    Miklos Szeredi (2):
          fuse: set FR_SENT while locked
          fuse: fix blocked_waitq wakeup
---
 fs/fuse/control.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 9a072ff3c0cd..db733f4318d4 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -126,7 +126,12 @@  static ssize_t fuse_conn_max_background_write(struct file *file,
 	if (ret > 0) {
 		struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
 		if (fc) {
+			spin_lock(&fc->lock);
 			fc->max_background = val;
+			fc->blocked = fc->num_background >= fc->max_background;
+			if (!fc->blocked)
+				wake_up(&fc->blocked_waitq);
+			spin_unlock(&fc->lock);
 			fuse_conn_put(fc);
 		}
 	}
@@ -156,18 +161,31 @@  static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
 						    size_t count, loff_t *ppos)
 {
 	unsigned uninitialized_var(val);
+	struct fuse_conn *fc;
 	ssize_t ret;
 
 	ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
 				    max_user_congthresh);
-	if (ret > 0) {
-		struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
-		if (fc) {
-			fc->congestion_threshold = val;
-			fuse_conn_put(fc);
+	if (ret <= 0)
+		goto out;
+	fc = fuse_ctl_file_conn_get(file);
+	if (!fc)
+		goto out;
+
+	spin_lock(&fc->lock);
+	fc->congestion_threshold = val;
+	if (fc->sb) {
+		if (fc->num_background < fc->congestion_threshold) {
+			clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
+			clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
+		} else {
+			set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
+			set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
 		}
 	}
-
+	spin_unlock(&fc->lock);
+	fuse_conn_put(fc);
+out:
 	return ret;
 }