Branch data Line data Source code
1 : : /*
2 : : FUSE: Filesystem in Userspace
3 : : Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
4 : :
5 : : This program can be distributed under the terms of the GNU GPL.
6 : : See the file COPYING.
7 : : */
8 : :
9 : : #include "fuse_i.h"
10 : :
11 : : #include <linux/init.h>
12 : : #include <linux/module.h>
13 : : #include <linux/fs_context.h>
14 : :
15 : : #define FUSE_CTL_SUPER_MAGIC 0x65735543
16 : :
17 : : /*
18 : : * This is non-NULL when the single instance of the control filesystem
19 : : * exists. Protected by fuse_mutex
20 : : */
21 : : static struct super_block *fuse_control_sb;
22 : :
23 : 0 : static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
24 : : {
25 : : struct fuse_conn *fc;
26 : 0 : mutex_lock(&fuse_mutex);
27 : 0 : fc = file_inode(file)->i_private;
28 [ # # ]: 0 : if (fc)
29 : 0 : fc = fuse_conn_get(fc);
30 : 0 : mutex_unlock(&fuse_mutex);
31 : 0 : return fc;
32 : : }
33 : :
34 : 0 : static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
35 : : size_t count, loff_t *ppos)
36 : : {
37 : 0 : struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
38 [ # # ]: 0 : if (fc) {
39 [ # # ]: 0 : if (fc->abort_err)
40 : 0 : fc->aborted = true;
41 : 0 : fuse_abort_conn(fc);
42 : 0 : fuse_conn_put(fc);
43 : : }
44 : 0 : return count;
45 : : }
46 : :
47 : 0 : static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
48 : : size_t len, loff_t *ppos)
49 : : {
50 : : char tmp[32];
51 : : size_t size;
52 : :
53 [ # # ]: 0 : if (!*ppos) {
54 : : long value;
55 : 0 : struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
56 [ # # ]: 0 : if (!fc)
57 : : return 0;
58 : :
59 : 0 : value = atomic_read(&fc->num_waiting);
60 : 0 : file->private_data = (void *)value;
61 : 0 : fuse_conn_put(fc);
62 : : }
63 : 0 : size = sprintf(tmp, "%ld\n", (long)file->private_data);
64 : 0 : return simple_read_from_buffer(buf, len, ppos, tmp, size);
65 : : }
66 : :
67 : 0 : static ssize_t fuse_conn_limit_read(struct file *file, char __user *buf,
68 : : size_t len, loff_t *ppos, unsigned val)
69 : : {
70 : : char tmp[32];
71 : 0 : size_t size = sprintf(tmp, "%u\n", val);
72 : :
73 : 0 : return simple_read_from_buffer(buf, len, ppos, tmp, size);
74 : : }
75 : :
76 : 0 : static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf,
77 : : size_t count, loff_t *ppos, unsigned *val,
78 : : unsigned global_limit)
79 : : {
80 : : unsigned long t;
81 : : unsigned limit = (1 << 16) - 1;
82 : : int err;
83 : :
84 [ # # ]: 0 : if (*ppos)
85 : : return -EINVAL;
86 : :
87 : 0 : err = kstrtoul_from_user(buf, count, 0, &t);
88 [ # # ]: 0 : if (err)
89 : : return err;
90 : :
91 [ # # ]: 0 : if (!capable(CAP_SYS_ADMIN))
92 : 0 : limit = min(limit, global_limit);
93 : :
94 [ # # ]: 0 : if (t > limit)
95 : : return -EINVAL;
96 : :
97 : 0 : *val = t;
98 : :
99 : 0 : return count;
100 : : }
101 : :
102 : 0 : static ssize_t fuse_conn_max_background_read(struct file *file,
103 : : char __user *buf, size_t len,
104 : : loff_t *ppos)
105 : : {
106 : : struct fuse_conn *fc;
107 : : unsigned val;
108 : :
109 : 0 : fc = fuse_ctl_file_conn_get(file);
110 [ # # ]: 0 : if (!fc)
111 : : return 0;
112 : :
113 : : val = READ_ONCE(fc->max_background);
114 : 0 : fuse_conn_put(fc);
115 : :
116 : 0 : return fuse_conn_limit_read(file, buf, len, ppos, val);
117 : : }
118 : :
119 : 0 : static ssize_t fuse_conn_max_background_write(struct file *file,
120 : : const char __user *buf,
121 : : size_t count, loff_t *ppos)
122 : : {
123 : : unsigned uninitialized_var(val);
124 : : ssize_t ret;
125 : :
126 : 0 : ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
127 : : max_user_bgreq);
128 [ # # ]: 0 : if (ret > 0) {
129 : 0 : struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
130 [ # # ]: 0 : if (fc) {
131 : : spin_lock(&fc->bg_lock);
132 : 0 : fc->max_background = val;
133 : 0 : fc->blocked = fc->num_background >= fc->max_background;
134 [ # # ]: 0 : if (!fc->blocked)
135 : 0 : wake_up(&fc->blocked_waitq);
136 : : spin_unlock(&fc->bg_lock);
137 : 0 : fuse_conn_put(fc);
138 : : }
139 : : }
140 : :
141 : 0 : return ret;
142 : : }
143 : :
144 : 0 : static ssize_t fuse_conn_congestion_threshold_read(struct file *file,
145 : : char __user *buf, size_t len,
146 : : loff_t *ppos)
147 : : {
148 : : struct fuse_conn *fc;
149 : : unsigned val;
150 : :
151 : 0 : fc = fuse_ctl_file_conn_get(file);
152 [ # # ]: 0 : if (!fc)
153 : : return 0;
154 : :
155 : : val = READ_ONCE(fc->congestion_threshold);
156 : 0 : fuse_conn_put(fc);
157 : :
158 : 0 : return fuse_conn_limit_read(file, buf, len, ppos, val);
159 : : }
160 : :
161 : 0 : static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
162 : : const char __user *buf,
163 : : size_t count, loff_t *ppos)
164 : : {
165 : : unsigned uninitialized_var(val);
166 : : struct fuse_conn *fc;
167 : : ssize_t ret;
168 : :
169 : 0 : ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
170 : : max_user_congthresh);
171 [ # # ]: 0 : if (ret <= 0)
172 : : goto out;
173 : 0 : fc = fuse_ctl_file_conn_get(file);
174 [ # # ]: 0 : if (!fc)
175 : : goto out;
176 : :
177 : : spin_lock(&fc->bg_lock);
178 : 0 : fc->congestion_threshold = val;
179 [ # # ]: 0 : if (fc->sb) {
180 [ # # ]: 0 : if (fc->num_background < fc->congestion_threshold) {
181 : 0 : clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
182 : 0 : clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
183 : : } else {
184 : 0 : set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
185 : 0 : set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
186 : : }
187 : : }
188 : : spin_unlock(&fc->bg_lock);
189 : 0 : fuse_conn_put(fc);
190 : : out:
191 : 0 : return ret;
192 : : }
193 : :
194 : : static const struct file_operations fuse_ctl_abort_ops = {
195 : : .open = nonseekable_open,
196 : : .write = fuse_conn_abort_write,
197 : : .llseek = no_llseek,
198 : : };
199 : :
200 : : static const struct file_operations fuse_ctl_waiting_ops = {
201 : : .open = nonseekable_open,
202 : : .read = fuse_conn_waiting_read,
203 : : .llseek = no_llseek,
204 : : };
205 : :
206 : : static const struct file_operations fuse_conn_max_background_ops = {
207 : : .open = nonseekable_open,
208 : : .read = fuse_conn_max_background_read,
209 : : .write = fuse_conn_max_background_write,
210 : : .llseek = no_llseek,
211 : : };
212 : :
213 : : static const struct file_operations fuse_conn_congestion_threshold_ops = {
214 : : .open = nonseekable_open,
215 : : .read = fuse_conn_congestion_threshold_read,
216 : : .write = fuse_conn_congestion_threshold_write,
217 : : .llseek = no_llseek,
218 : : };
219 : :
220 : 2020 : static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
221 : : struct fuse_conn *fc,
222 : : const char *name,
223 : : int mode, int nlink,
224 : : const struct inode_operations *iop,
225 : : const struct file_operations *fop)
226 : : {
227 : : struct dentry *dentry;
228 : : struct inode *inode;
229 : :
230 [ - + ]: 2020 : BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES);
231 : 2020 : dentry = d_alloc_name(parent, name);
232 [ + - ]: 2020 : if (!dentry)
233 : : return NULL;
234 : :
235 : 2020 : inode = new_inode(fuse_control_sb);
236 [ - + ]: 2020 : if (!inode) {
237 : 0 : dput(dentry);
238 : 0 : return NULL;
239 : : }
240 : :
241 : 2020 : inode->i_ino = get_next_ino();
242 : 2020 : inode->i_mode = mode;
243 : 2020 : inode->i_uid = fc->user_id;
244 : 2020 : inode->i_gid = fc->group_id;
245 : 2020 : inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
246 : : /* setting ->i_op to NULL is not allowed */
247 [ + + ]: 2020 : if (iop)
248 : 404 : inode->i_op = iop;
249 : 2020 : inode->i_fop = fop;
250 : 2020 : set_nlink(inode, nlink);
251 : 2020 : inode->i_private = fc;
252 : 2020 : d_add(dentry, inode);
253 : :
254 : 2020 : fc->ctl_dentry[fc->ctl_ndents++] = dentry;
255 : :
256 : 2020 : return dentry;
257 : : }
258 : :
259 : : /*
260 : : * Add a connection to the control filesystem (if it exists). Caller
261 : : * must hold fuse_mutex
262 : : */
263 : 728 : int fuse_ctl_add_conn(struct fuse_conn *fc)
264 : : {
265 : : struct dentry *parent;
266 : : char name[32];
267 : :
268 [ + + ]: 728 : if (!fuse_control_sb)
269 : : return 0;
270 : :
271 : 404 : parent = fuse_control_sb->s_root;
272 : 404 : inc_nlink(d_inode(parent));
273 : 404 : sprintf(name, "%u", fc->dev);
274 : 404 : parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
275 : : &simple_dir_inode_operations,
276 : : &simple_dir_operations);
277 [ + - ]: 404 : if (!parent)
278 : : goto err;
279 : :
280 [ + - ]: 404 : if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1,
281 [ + - ]: 404 : NULL, &fuse_ctl_waiting_ops) ||
282 : 404 : !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1,
283 [ + - ]: 404 : NULL, &fuse_ctl_abort_ops) ||
284 : 404 : !fuse_ctl_add_dentry(parent, fc, "max_background", S_IFREG | 0600,
285 [ - + ]: 404 : 1, NULL, &fuse_conn_max_background_ops) ||
286 : 404 : !fuse_ctl_add_dentry(parent, fc, "congestion_threshold",
287 : : S_IFREG | 0600, 1, NULL,
288 : : &fuse_conn_congestion_threshold_ops))
289 : : goto err;
290 : :
291 : : return 0;
292 : :
293 : : err:
294 : 0 : fuse_ctl_remove_conn(fc);
295 : 0 : return -ENOMEM;
296 : : }
297 : :
298 : : /*
299 : : * Remove a connection from the control filesystem (if it exists).
300 : : * Caller must hold fuse_mutex
301 : : */
302 : 0 : void fuse_ctl_remove_conn(struct fuse_conn *fc)
303 : : {
304 : : int i;
305 : :
306 [ # # ]: 0 : if (!fuse_control_sb)
307 : 0 : return;
308 : :
309 [ # # ]: 0 : for (i = fc->ctl_ndents - 1; i >= 0; i--) {
310 : 0 : struct dentry *dentry = fc->ctl_dentry[i];
311 : 0 : d_inode(dentry)->i_private = NULL;
312 [ # # ]: 0 : if (!i) {
313 : : /* Get rid of submounts: */
314 : 0 : d_invalidate(dentry);
315 : : }
316 : 0 : dput(dentry);
317 : : }
318 : 0 : drop_nlink(d_inode(fuse_control_sb->s_root));
319 : : }
320 : :
321 : 404 : static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx)
322 : : {
323 : : static const struct tree_descr empty_descr = {""};
324 : : struct fuse_conn *fc;
325 : : int err;
326 : :
327 : 404 : err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr);
328 [ + - ]: 404 : if (err)
329 : : return err;
330 : :
331 : 404 : mutex_lock(&fuse_mutex);
332 [ - + ]: 404 : BUG_ON(fuse_control_sb);
333 : 404 : fuse_control_sb = sb;
334 [ + + ]: 728 : list_for_each_entry(fc, &fuse_conn_list, entry) {
335 : 324 : err = fuse_ctl_add_conn(fc);
336 [ - + ]: 324 : if (err) {
337 : 0 : fuse_control_sb = NULL;
338 : 0 : mutex_unlock(&fuse_mutex);
339 : 0 : return err;
340 : : }
341 : : }
342 : 404 : mutex_unlock(&fuse_mutex);
343 : :
344 : 404 : return 0;
345 : : }
346 : :
347 : 404 : static int fuse_ctl_get_tree(struct fs_context *fc)
348 : : {
349 : 404 : return get_tree_single(fc, fuse_ctl_fill_super);
350 : : }
351 : :
352 : : static const struct fs_context_operations fuse_ctl_context_ops = {
353 : : .get_tree = fuse_ctl_get_tree,
354 : : };
355 : :
356 : 404 : static int fuse_ctl_init_fs_context(struct fs_context *fc)
357 : : {
358 : 404 : fc->ops = &fuse_ctl_context_ops;
359 : 404 : return 0;
360 : : }
361 : :
362 : 0 : static void fuse_ctl_kill_sb(struct super_block *sb)
363 : : {
364 : : struct fuse_conn *fc;
365 : :
366 : 0 : mutex_lock(&fuse_mutex);
367 : 0 : fuse_control_sb = NULL;
368 [ # # ]: 0 : list_for_each_entry(fc, &fuse_conn_list, entry)
369 : 0 : fc->ctl_ndents = 0;
370 : 0 : mutex_unlock(&fuse_mutex);
371 : :
372 : 0 : kill_litter_super(sb);
373 : 0 : }
374 : :
375 : : static struct file_system_type fuse_ctl_fs_type = {
376 : : .owner = THIS_MODULE,
377 : : .name = "fusectl",
378 : : .init_fs_context = fuse_ctl_init_fs_context,
379 : : .kill_sb = fuse_ctl_kill_sb,
380 : : };
381 : : MODULE_ALIAS_FS("fusectl");
382 : :
383 : 404 : int __init fuse_ctl_init(void)
384 : : {
385 : 404 : return register_filesystem(&fuse_ctl_fs_type);
386 : : }
387 : :
388 : 0 : void __exit fuse_ctl_cleanup(void)
389 : : {
390 : 0 : unregister_filesystem(&fuse_ctl_fs_type);
391 : 0 : }
|