diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 77 |
1 files changed, 38 insertions, 39 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f229d6962643..458c62ca0fec 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/parser.h> | 18 | #include <linux/parser.h> |
20 | #include <linux/statfs.h> | 19 | #include <linux/statfs.h> |
21 | 20 | ||
@@ -25,11 +24,6 @@ MODULE_LICENSE("GPL"); | |||
25 | 24 | ||
26 | spinlock_t fuse_lock; | 25 | spinlock_t fuse_lock; |
27 | static kmem_cache_t *fuse_inode_cachep; | 26 | static kmem_cache_t *fuse_inode_cachep; |
28 | static int mount_count; | ||
29 | |||
30 | static int mount_max = 1000; | ||
31 | module_param(mount_max, int, 0644); | ||
32 | MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)"); | ||
33 | 27 | ||
34 | #define FUSE_SUPER_MAGIC 0x65735546 | 28 | #define FUSE_SUPER_MAGIC 0x65735546 |
35 | 29 | ||
@@ -37,6 +31,7 @@ struct fuse_mount_data { | |||
37 | int fd; | 31 | int fd; |
38 | unsigned rootmode; | 32 | unsigned rootmode; |
39 | unsigned user_id; | 33 | unsigned user_id; |
34 | unsigned flags; | ||
40 | }; | 35 | }; |
41 | 36 | ||
42 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 37 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
@@ -89,8 +84,8 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | |||
89 | 84 | ||
90 | static void fuse_clear_inode(struct inode *inode) | 85 | static void fuse_clear_inode(struct inode *inode) |
91 | { | 86 | { |
92 | struct fuse_conn *fc = get_fuse_conn(inode); | 87 | if (inode->i_sb->s_flags & MS_ACTIVE) { |
93 | if (fc) { | 88 | struct fuse_conn *fc = get_fuse_conn(inode); |
94 | struct fuse_inode *fi = get_fuse_inode(inode); | 89 | struct fuse_inode *fi = get_fuse_inode(inode); |
95 | fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); | 90 | fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); |
96 | fi->forget_req = NULL; | 91 | fi->forget_req = NULL; |
@@ -195,14 +190,19 @@ static void fuse_put_super(struct super_block *sb) | |||
195 | { | 190 | { |
196 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 191 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
197 | 192 | ||
193 | down_write(&fc->sbput_sem); | ||
194 | while (!list_empty(&fc->background)) | ||
195 | fuse_release_background(list_entry(fc->background.next, | ||
196 | struct fuse_req, bg_entry)); | ||
197 | |||
198 | spin_lock(&fuse_lock); | 198 | spin_lock(&fuse_lock); |
199 | mount_count --; | 199 | fc->mounted = 0; |
200 | fc->sb = NULL; | ||
201 | fc->user_id = 0; | 200 | fc->user_id = 0; |
201 | fc->flags = 0; | ||
202 | /* Flush all readers on this fs */ | 202 | /* Flush all readers on this fs */ |
203 | wake_up_all(&fc->waitq); | 203 | wake_up_all(&fc->waitq); |
204 | up_write(&fc->sbput_sem); | ||
204 | fuse_release_conn(fc); | 205 | fuse_release_conn(fc); |
205 | *get_fuse_conn_super_p(sb) = NULL; | ||
206 | spin_unlock(&fuse_lock); | 206 | spin_unlock(&fuse_lock); |
207 | } | 207 | } |
208 | 208 | ||
@@ -249,7 +249,6 @@ enum { | |||
249 | OPT_USER_ID, | 249 | OPT_USER_ID, |
250 | OPT_DEFAULT_PERMISSIONS, | 250 | OPT_DEFAULT_PERMISSIONS, |
251 | OPT_ALLOW_OTHER, | 251 | OPT_ALLOW_OTHER, |
252 | OPT_ALLOW_ROOT, | ||
253 | OPT_KERNEL_CACHE, | 252 | OPT_KERNEL_CACHE, |
254 | OPT_ERR | 253 | OPT_ERR |
255 | }; | 254 | }; |
@@ -260,7 +259,6 @@ static match_table_t tokens = { | |||
260 | {OPT_USER_ID, "user_id=%u"}, | 259 | {OPT_USER_ID, "user_id=%u"}, |
261 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, | 260 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, |
262 | {OPT_ALLOW_OTHER, "allow_other"}, | 261 | {OPT_ALLOW_OTHER, "allow_other"}, |
263 | {OPT_ALLOW_ROOT, "allow_root"}, | ||
264 | {OPT_KERNEL_CACHE, "kernel_cache"}, | 262 | {OPT_KERNEL_CACHE, "kernel_cache"}, |
265 | {OPT_ERR, NULL} | 263 | {OPT_ERR, NULL} |
266 | }; | 264 | }; |
@@ -298,6 +296,18 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | |||
298 | d->user_id = value; | 296 | d->user_id = value; |
299 | break; | 297 | break; |
300 | 298 | ||
299 | case OPT_DEFAULT_PERMISSIONS: | ||
300 | d->flags |= FUSE_DEFAULT_PERMISSIONS; | ||
301 | break; | ||
302 | |||
303 | case OPT_ALLOW_OTHER: | ||
304 | d->flags |= FUSE_ALLOW_OTHER; | ||
305 | break; | ||
306 | |||
307 | case OPT_KERNEL_CACHE: | ||
308 | d->flags |= FUSE_KERNEL_CACHE; | ||
309 | break; | ||
310 | |||
301 | default: | 311 | default: |
302 | return 0; | 312 | return 0; |
303 | } | 313 | } |
@@ -313,6 +323,12 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
313 | struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); | 323 | struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); |
314 | 324 | ||
315 | seq_printf(m, ",user_id=%u", fc->user_id); | 325 | seq_printf(m, ",user_id=%u", fc->user_id); |
326 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) | ||
327 | seq_puts(m, ",default_permissions"); | ||
328 | if (fc->flags & FUSE_ALLOW_OTHER) | ||
329 | seq_puts(m, ",allow_other"); | ||
330 | if (fc->flags & FUSE_KERNEL_CACHE) | ||
331 | seq_puts(m, ",kernel_cache"); | ||
316 | return 0; | 332 | return 0; |
317 | } | 333 | } |
318 | 334 | ||
@@ -330,7 +346,8 @@ static void free_conn(struct fuse_conn *fc) | |||
330 | /* Must be called with the fuse lock held */ | 346 | /* Must be called with the fuse lock held */ |
331 | void fuse_release_conn(struct fuse_conn *fc) | 347 | void fuse_release_conn(struct fuse_conn *fc) |
332 | { | 348 | { |
333 | if (!fc->sb && !fc->file) | 349 | fc->count--; |
350 | if (!fc->count) | ||
334 | free_conn(fc); | 351 | free_conn(fc); |
335 | } | 352 | } |
336 | 353 | ||
@@ -342,14 +359,13 @@ static struct fuse_conn *new_conn(void) | |||
342 | if (fc != NULL) { | 359 | if (fc != NULL) { |
343 | int i; | 360 | int i; |
344 | memset(fc, 0, sizeof(*fc)); | 361 | memset(fc, 0, sizeof(*fc)); |
345 | fc->sb = NULL; | ||
346 | fc->file = NULL; | ||
347 | fc->user_id = 0; | ||
348 | init_waitqueue_head(&fc->waitq); | 362 | init_waitqueue_head(&fc->waitq); |
349 | INIT_LIST_HEAD(&fc->pending); | 363 | INIT_LIST_HEAD(&fc->pending); |
350 | INIT_LIST_HEAD(&fc->processing); | 364 | INIT_LIST_HEAD(&fc->processing); |
351 | INIT_LIST_HEAD(&fc->unused_list); | 365 | INIT_LIST_HEAD(&fc->unused_list); |
366 | INIT_LIST_HEAD(&fc->background); | ||
352 | sema_init(&fc->outstanding_sem, 0); | 367 | sema_init(&fc->outstanding_sem, 0); |
368 | init_rwsem(&fc->sbput_sem); | ||
353 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { | 369 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { |
354 | struct fuse_req *req = fuse_request_alloc(); | 370 | struct fuse_req *req = fuse_request_alloc(); |
355 | if (!req) { | 371 | if (!req) { |
@@ -380,8 +396,10 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) | |||
380 | fc = ERR_PTR(-EINVAL); | 396 | fc = ERR_PTR(-EINVAL); |
381 | } else { | 397 | } else { |
382 | file->private_data = fc; | 398 | file->private_data = fc; |
383 | fc->sb = sb; | 399 | *get_fuse_conn_super_p(sb) = fc; |
384 | fc->file = file; | 400 | fc->mounted = 1; |
401 | fc->connected = 1; | ||
402 | fc->count = 2; | ||
385 | } | 403 | } |
386 | spin_unlock(&fuse_lock); | 404 | spin_unlock(&fuse_lock); |
387 | return fc; | 405 | return fc; |
@@ -407,17 +425,6 @@ static struct super_operations fuse_super_operations = { | |||
407 | .show_options = fuse_show_options, | 425 | .show_options = fuse_show_options, |
408 | }; | 426 | }; |
409 | 427 | ||
410 | static int inc_mount_count(void) | ||
411 | { | ||
412 | int success = 0; | ||
413 | spin_lock(&fuse_lock); | ||
414 | mount_count ++; | ||
415 | if (mount_max == -1 || mount_count <= mount_max) | ||
416 | success = 1; | ||
417 | spin_unlock(&fuse_lock); | ||
418 | return success; | ||
419 | } | ||
420 | |||
421 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) | 428 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) |
422 | { | 429 | { |
423 | struct fuse_conn *fc; | 430 | struct fuse_conn *fc; |
@@ -444,14 +451,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
444 | if (IS_ERR(fc)) | 451 | if (IS_ERR(fc)) |
445 | return PTR_ERR(fc); | 452 | return PTR_ERR(fc); |
446 | 453 | ||
454 | fc->flags = d.flags; | ||
447 | fc->user_id = d.user_id; | 455 | fc->user_id = d.user_id; |
448 | 456 | ||
449 | *get_fuse_conn_super_p(sb) = fc; | ||
450 | |||
451 | err = -ENFILE; | ||
452 | if (!inc_mount_count() && current->uid != 0) | ||
453 | goto err; | ||
454 | |||
455 | err = -ENOMEM; | 457 | err = -ENOMEM; |
456 | root = get_root_inode(sb, d.rootmode); | 458 | root = get_root_inode(sb, d.rootmode); |
457 | if (root == NULL) | 459 | if (root == NULL) |
@@ -467,11 +469,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
467 | 469 | ||
468 | err: | 470 | err: |
469 | spin_lock(&fuse_lock); | 471 | spin_lock(&fuse_lock); |
470 | mount_count --; | ||
471 | fc->sb = NULL; | ||
472 | fuse_release_conn(fc); | 472 | fuse_release_conn(fc); |
473 | spin_unlock(&fuse_lock); | 473 | spin_unlock(&fuse_lock); |
474 | *get_fuse_conn_super_p(sb) = NULL; | ||
475 | return err; | 474 | return err; |
476 | } | 475 | } |
477 | 476 | ||