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>
This commit is contained in:
Kirill Tkhai 2018-08-27 18:29:37 +03:00 committed by Miklos Szeredi
parent 2a23f2b8ad
commit 2b30a53314

View file

@ -125,7 +125,12 @@ static ssize_t fuse_conn_max_background_write(struct file *file,
if (ret > 0) { if (ret > 0) {
struct fuse_conn *fc = fuse_ctl_file_conn_get(file); struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
if (fc) { if (fc) {
spin_lock(&fc->lock);
fc->max_background = val; 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); 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) size_t count, loff_t *ppos)
{ {
unsigned uninitialized_var(val); unsigned uninitialized_var(val);
struct fuse_conn *fc;
ssize_t ret; ssize_t ret;
ret = fuse_conn_limit_write(file, buf, count, ppos, &val, ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
max_user_congthresh); max_user_congthresh);
if (ret > 0) { if (ret <= 0)
struct fuse_conn *fc = fuse_ctl_file_conn_get(file); goto out;
if (fc) { fc = fuse_ctl_file_conn_get(file);
fc->congestion_threshold = val; if (!fc)
fuse_conn_put(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; return ret;
} }