diff options
author | Kirill Tkhai <ktkhai@virtuozzo.com> | 2018-08-27 11:29:37 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-09-28 10:43:22 -0400 |
commit | 2b30a533148af4f3865c0dcd619ad93ab3f4ba52 (patch) | |
tree | fd25fe80e8ff83649d05d6eda7328447909ba628 | |
parent | 2a23f2b8adbe4bd584f936f7ac17a99750eed9d7 (diff) |
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>
-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, | |||
125 | if (ret > 0) { | 125 | if (ret > 0) { |
126 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | 126 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); |
127 | if (fc) { | 127 | if (fc) { |
128 | spin_lock(&fc->lock); | ||
128 | fc->max_background = val; | 129 | fc->max_background = val; |
130 | fc->blocked = fc->num_background >= fc->max_background; | ||
131 | if (!fc->blocked) | ||
132 | wake_up(&fc->blocked_waitq); | ||
133 | spin_unlock(&fc->lock); | ||
129 | fuse_conn_put(fc); | 134 | fuse_conn_put(fc); |
130 | } | 135 | } |
131 | } | 136 | } |
@@ -155,18 +160,31 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file, | |||
155 | size_t count, loff_t *ppos) | 160 | size_t count, loff_t *ppos) |
156 | { | 161 | { |
157 | unsigned uninitialized_var(val); | 162 | unsigned uninitialized_var(val); |
163 | struct fuse_conn *fc; | ||
158 | ssize_t ret; | 164 | ssize_t ret; |
159 | 165 | ||
160 | ret = fuse_conn_limit_write(file, buf, count, ppos, &val, | 166 | ret = fuse_conn_limit_write(file, buf, count, ppos, &val, |
161 | max_user_congthresh); | 167 | max_user_congthresh); |
162 | if (ret > 0) { | 168 | if (ret <= 0) |
163 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | 169 | goto out; |
164 | if (fc) { | 170 | fc = fuse_ctl_file_conn_get(file); |
165 | fc->congestion_threshold = val; | 171 | if (!fc) |
166 | fuse_conn_put(fc); | 172 | goto out; |
173 | |||
174 | spin_lock(&fc->lock); | ||
175 | fc->congestion_threshold = val; | ||
176 | if (fc->sb) { | ||
177 | if (fc->num_background < fc->congestion_threshold) { | ||
178 | clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); | ||
179 | clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC); | ||
180 | } else { | ||
181 | set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); | ||
182 | set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC); | ||
167 | } | 183 | } |
168 | } | 184 | } |
169 | 185 | spin_unlock(&fc->lock); | |
186 | fuse_conn_put(fc); | ||
187 | out: | ||
170 | return ret; | 188 | return ret; |
171 | } | 189 | } |
172 | 190 | ||