diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 123 |
1 files changed, 105 insertions, 18 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fc4203570370..12450d2b320e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -22,7 +22,7 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | |||
22 | MODULE_DESCRIPTION("Filesystem in Userspace"); | 22 | MODULE_DESCRIPTION("Filesystem in Userspace"); |
23 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
24 | 24 | ||
25 | static kmem_cache_t *fuse_inode_cachep; | 25 | static struct kmem_cache *fuse_inode_cachep; |
26 | struct list_head fuse_conn_list; | 26 | struct list_head fuse_conn_list; |
27 | DEFINE_MUTEX(fuse_mutex); | 27 | DEFINE_MUTEX(fuse_mutex); |
28 | 28 | ||
@@ -39,6 +39,7 @@ struct fuse_mount_data { | |||
39 | unsigned group_id_present : 1; | 39 | unsigned group_id_present : 1; |
40 | unsigned flags; | 40 | unsigned flags; |
41 | unsigned max_read; | 41 | unsigned max_read; |
42 | unsigned blksize; | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 45 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
@@ -46,7 +47,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
46 | struct inode *inode; | 47 | struct inode *inode; |
47 | struct fuse_inode *fi; | 48 | struct fuse_inode *fi; |
48 | 49 | ||
49 | inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); | 50 | inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); |
50 | if (!inode) | 51 | if (!inode) |
51 | return NULL; | 52 | return NULL; |
52 | 53 | ||
@@ -205,10 +206,23 @@ static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) | |||
205 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); | 206 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); |
206 | } | 207 | } |
207 | 208 | ||
209 | static void fuse_send_destroy(struct fuse_conn *fc) | ||
210 | { | ||
211 | struct fuse_req *req = fc->destroy_req; | ||
212 | if (req && fc->conn_init) { | ||
213 | fc->destroy_req = NULL; | ||
214 | req->in.h.opcode = FUSE_DESTROY; | ||
215 | req->force = 1; | ||
216 | request_send(fc, req); | ||
217 | fuse_put_request(fc, req); | ||
218 | } | ||
219 | } | ||
220 | |||
208 | static void fuse_put_super(struct super_block *sb) | 221 | static void fuse_put_super(struct super_block *sb) |
209 | { | 222 | { |
210 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 223 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
211 | 224 | ||
225 | fuse_send_destroy(fc); | ||
212 | spin_lock(&fc->lock); | 226 | spin_lock(&fc->lock); |
213 | fc->connected = 0; | 227 | fc->connected = 0; |
214 | fc->blocked = 0; | 228 | fc->blocked = 0; |
@@ -274,6 +288,7 @@ enum { | |||
274 | OPT_DEFAULT_PERMISSIONS, | 288 | OPT_DEFAULT_PERMISSIONS, |
275 | OPT_ALLOW_OTHER, | 289 | OPT_ALLOW_OTHER, |
276 | OPT_MAX_READ, | 290 | OPT_MAX_READ, |
291 | OPT_BLKSIZE, | ||
277 | OPT_ERR | 292 | OPT_ERR |
278 | }; | 293 | }; |
279 | 294 | ||
@@ -285,14 +300,16 @@ static match_table_t tokens = { | |||
285 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, | 300 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, |
286 | {OPT_ALLOW_OTHER, "allow_other"}, | 301 | {OPT_ALLOW_OTHER, "allow_other"}, |
287 | {OPT_MAX_READ, "max_read=%u"}, | 302 | {OPT_MAX_READ, "max_read=%u"}, |
303 | {OPT_BLKSIZE, "blksize=%u"}, | ||
288 | {OPT_ERR, NULL} | 304 | {OPT_ERR, NULL} |
289 | }; | 305 | }; |
290 | 306 | ||
291 | static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | 307 | static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) |
292 | { | 308 | { |
293 | char *p; | 309 | char *p; |
294 | memset(d, 0, sizeof(struct fuse_mount_data)); | 310 | memset(d, 0, sizeof(struct fuse_mount_data)); |
295 | d->max_read = ~0; | 311 | d->max_read = ~0; |
312 | d->blksize = 512; | ||
296 | 313 | ||
297 | while ((p = strsep(&opt, ",")) != NULL) { | 314 | while ((p = strsep(&opt, ",")) != NULL) { |
298 | int token; | 315 | int token; |
@@ -345,6 +362,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | |||
345 | d->max_read = value; | 362 | d->max_read = value; |
346 | break; | 363 | break; |
347 | 364 | ||
365 | case OPT_BLKSIZE: | ||
366 | if (!is_bdev || match_int(&args[0], &value)) | ||
367 | return 0; | ||
368 | d->blksize = value; | ||
369 | break; | ||
370 | |||
348 | default: | 371 | default: |
349 | return 0; | 372 | return 0; |
350 | } | 373 | } |
@@ -400,6 +423,8 @@ static struct fuse_conn *new_conn(void) | |||
400 | void fuse_conn_put(struct fuse_conn *fc) | 423 | void fuse_conn_put(struct fuse_conn *fc) |
401 | { | 424 | { |
402 | if (atomic_dec_and_test(&fc->count)) { | 425 | if (atomic_dec_and_test(&fc->count)) { |
426 | if (fc->destroy_req) | ||
427 | fuse_request_free(fc->destroy_req); | ||
403 | mutex_destroy(&fc->inst_mutex); | 428 | mutex_destroy(&fc->inst_mutex); |
404 | kfree(fc); | 429 | kfree(fc); |
405 | } | 430 | } |
@@ -456,6 +481,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
456 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); | 481 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); |
457 | fc->minor = arg->minor; | 482 | fc->minor = arg->minor; |
458 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | 483 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; |
484 | fc->conn_init = 1; | ||
459 | } | 485 | } |
460 | fuse_put_request(fc, req); | 486 | fuse_put_request(fc, req); |
461 | fc->blocked = 0; | 487 | fc->blocked = 0; |
@@ -500,15 +526,23 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
500 | struct dentry *root_dentry; | 526 | struct dentry *root_dentry; |
501 | struct fuse_req *init_req; | 527 | struct fuse_req *init_req; |
502 | int err; | 528 | int err; |
529 | int is_bdev = sb->s_bdev != NULL; | ||
503 | 530 | ||
504 | if (sb->s_flags & MS_MANDLOCK) | 531 | if (sb->s_flags & MS_MANDLOCK) |
505 | return -EINVAL; | 532 | return -EINVAL; |
506 | 533 | ||
507 | if (!parse_fuse_opt((char *) data, &d)) | 534 | if (!parse_fuse_opt((char *) data, &d, is_bdev)) |
508 | return -EINVAL; | 535 | return -EINVAL; |
509 | 536 | ||
510 | sb->s_blocksize = PAGE_CACHE_SIZE; | 537 | if (is_bdev) { |
511 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 538 | #ifdef CONFIG_BLOCK |
539 | if (!sb_set_blocksize(sb, d.blksize)) | ||
540 | return -EINVAL; | ||
541 | #endif | ||
542 | } else { | ||
543 | sb->s_blocksize = PAGE_CACHE_SIZE; | ||
544 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | ||
545 | } | ||
512 | sb->s_magic = FUSE_SUPER_MAGIC; | 546 | sb->s_magic = FUSE_SUPER_MAGIC; |
513 | sb->s_op = &fuse_super_operations; | 547 | sb->s_op = &fuse_super_operations; |
514 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 548 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
@@ -547,6 +581,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
547 | if (!init_req) | 581 | if (!init_req) |
548 | goto err_put_root; | 582 | goto err_put_root; |
549 | 583 | ||
584 | if (is_bdev) { | ||
585 | fc->destroy_req = fuse_request_alloc(); | ||
586 | if (!fc->destroy_req) | ||
587 | goto err_put_root; | ||
588 | } | ||
589 | |||
550 | mutex_lock(&fuse_mutex); | 590 | mutex_lock(&fuse_mutex); |
551 | err = -EINVAL; | 591 | err = -EINVAL; |
552 | if (file->private_data) | 592 | if (file->private_data) |
@@ -598,10 +638,47 @@ static struct file_system_type fuse_fs_type = { | |||
598 | .kill_sb = kill_anon_super, | 638 | .kill_sb = kill_anon_super, |
599 | }; | 639 | }; |
600 | 640 | ||
641 | #ifdef CONFIG_BLOCK | ||
642 | static int fuse_get_sb_blk(struct file_system_type *fs_type, | ||
643 | int flags, const char *dev_name, | ||
644 | void *raw_data, struct vfsmount *mnt) | ||
645 | { | ||
646 | return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, | ||
647 | mnt); | ||
648 | } | ||
649 | |||
650 | static struct file_system_type fuseblk_fs_type = { | ||
651 | .owner = THIS_MODULE, | ||
652 | .name = "fuseblk", | ||
653 | .get_sb = fuse_get_sb_blk, | ||
654 | .kill_sb = kill_block_super, | ||
655 | .fs_flags = FS_REQUIRES_DEV, | ||
656 | }; | ||
657 | |||
658 | static inline int register_fuseblk(void) | ||
659 | { | ||
660 | return register_filesystem(&fuseblk_fs_type); | ||
661 | } | ||
662 | |||
663 | static inline void unregister_fuseblk(void) | ||
664 | { | ||
665 | unregister_filesystem(&fuseblk_fs_type); | ||
666 | } | ||
667 | #else | ||
668 | static inline int register_fuseblk(void) | ||
669 | { | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static inline void unregister_fuseblk(void) | ||
674 | { | ||
675 | } | ||
676 | #endif | ||
677 | |||
601 | static decl_subsys(fuse, NULL, NULL); | 678 | static decl_subsys(fuse, NULL, NULL); |
602 | static decl_subsys(connections, NULL, NULL); | 679 | static decl_subsys(connections, NULL, NULL); |
603 | 680 | ||
604 | static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, | 681 | static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep, |
605 | unsigned long flags) | 682 | unsigned long flags) |
606 | { | 683 | { |
607 | struct inode * inode = foo; | 684 | struct inode * inode = foo; |
@@ -617,24 +694,34 @@ static int __init fuse_fs_init(void) | |||
617 | 694 | ||
618 | err = register_filesystem(&fuse_fs_type); | 695 | err = register_filesystem(&fuse_fs_type); |
619 | if (err) | 696 | if (err) |
620 | printk("fuse: failed to register filesystem\n"); | 697 | goto out; |
621 | else { | ||
622 | fuse_inode_cachep = kmem_cache_create("fuse_inode", | ||
623 | sizeof(struct fuse_inode), | ||
624 | 0, SLAB_HWCACHE_ALIGN, | ||
625 | fuse_inode_init_once, NULL); | ||
626 | if (!fuse_inode_cachep) { | ||
627 | unregister_filesystem(&fuse_fs_type); | ||
628 | err = -ENOMEM; | ||
629 | } | ||
630 | } | ||
631 | 698 | ||
699 | err = register_fuseblk(); | ||
700 | if (err) | ||
701 | goto out_unreg; | ||
702 | |||
703 | fuse_inode_cachep = kmem_cache_create("fuse_inode", | ||
704 | sizeof(struct fuse_inode), | ||
705 | 0, SLAB_HWCACHE_ALIGN, | ||
706 | fuse_inode_init_once, NULL); | ||
707 | err = -ENOMEM; | ||
708 | if (!fuse_inode_cachep) | ||
709 | goto out_unreg2; | ||
710 | |||
711 | return 0; | ||
712 | |||
713 | out_unreg2: | ||
714 | unregister_fuseblk(); | ||
715 | out_unreg: | ||
716 | unregister_filesystem(&fuse_fs_type); | ||
717 | out: | ||
632 | return err; | 718 | return err; |
633 | } | 719 | } |
634 | 720 | ||
635 | static void fuse_fs_cleanup(void) | 721 | static void fuse_fs_cleanup(void) |
636 | { | 722 | { |
637 | unregister_filesystem(&fuse_fs_type); | 723 | unregister_filesystem(&fuse_fs_type); |
724 | unregister_fuseblk(); | ||
638 | kmem_cache_destroy(fuse_inode_cachep); | 725 | kmem_cache_destroy(fuse_inode_cachep); |
639 | } | 726 | } |
640 | 727 | ||