diff options
author | Kirill Tkhai <ktkhai@virtuozzo.com> | 2018-08-27 17:29:37 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-09-28 16:43:22 +0200 |
commit | 2b30a533148af4f3865c0dcd619ad93ab3f4ba52 (patch) | |
tree | fd25fe80e8ff83649d05d6eda7328447909ba628 /fs/fuse | |
parent | fuse: use READ_ONCE on congestion_threshold and max_background (diff) | |
download | linux-2b30a533148af4f3865c0dcd619ad93ab3f4ba52.tar.xz linux-2b30a533148af4f3865c0dcd619ad93ab3f4ba52.zip |
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>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/control.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index acc35819aae6..eaa0e2b21623 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -125,7 +125,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); } } @@ -155,18 +160,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; } |