projects/linux·blob master · refs

366 lines · 8.0 KiB

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