diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 193 |
1 files changed, 188 insertions, 5 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 79b615873838..d2249f174e20 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/statfs.h> | 18 | #include <linux/statfs.h> |
19 | #include <linux/random.h> | 19 | #include <linux/random.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/exportfs.h> | ||
21 | 22 | ||
22 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | 23 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); |
23 | MODULE_DESCRIPTION("Filesystem in Userspace"); | 24 | MODULE_DESCRIPTION("Filesystem in Userspace"); |
@@ -488,7 +489,12 @@ static struct fuse_conn *new_conn(struct super_block *sb) | |||
488 | err = bdi_init(&fc->bdi); | 489 | err = bdi_init(&fc->bdi); |
489 | if (err) | 490 | if (err) |
490 | goto error_kfree; | 491 | goto error_kfree; |
491 | err = bdi_register_dev(&fc->bdi, fc->dev); | 492 | if (sb->s_bdev) { |
493 | err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk", | ||
494 | MAJOR(fc->dev), MINOR(fc->dev)); | ||
495 | } else { | ||
496 | err = bdi_register_dev(&fc->bdi, fc->dev); | ||
497 | } | ||
492 | if (err) | 498 | if (err) |
493 | goto error_bdi_destroy; | 499 | goto error_bdi_destroy; |
494 | /* | 500 | /* |
@@ -547,6 +553,174 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | |||
547 | return fuse_iget(sb, 1, 0, &attr, 0, 0); | 553 | return fuse_iget(sb, 1, 0, &attr, 0, 0); |
548 | } | 554 | } |
549 | 555 | ||
556 | struct fuse_inode_handle | ||
557 | { | ||
558 | u64 nodeid; | ||
559 | u32 generation; | ||
560 | }; | ||
561 | |||
562 | static struct dentry *fuse_get_dentry(struct super_block *sb, | ||
563 | struct fuse_inode_handle *handle) | ||
564 | { | ||
565 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
566 | struct inode *inode; | ||
567 | struct dentry *entry; | ||
568 | int err = -ESTALE; | ||
569 | |||
570 | if (handle->nodeid == 0) | ||
571 | goto out_err; | ||
572 | |||
573 | inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); | ||
574 | if (!inode) { | ||
575 | struct fuse_entry_out outarg; | ||
576 | struct qstr name; | ||
577 | |||
578 | if (!fc->export_support) | ||
579 | goto out_err; | ||
580 | |||
581 | name.len = 1; | ||
582 | name.name = "."; | ||
583 | err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg, | ||
584 | &inode); | ||
585 | if (err && err != -ENOENT) | ||
586 | goto out_err; | ||
587 | if (err || !inode) { | ||
588 | err = -ESTALE; | ||
589 | goto out_err; | ||
590 | } | ||
591 | err = -EIO; | ||
592 | if (get_node_id(inode) != handle->nodeid) | ||
593 | goto out_iput; | ||
594 | } | ||
595 | err = -ESTALE; | ||
596 | if (inode->i_generation != handle->generation) | ||
597 | goto out_iput; | ||
598 | |||
599 | entry = d_alloc_anon(inode); | ||
600 | err = -ENOMEM; | ||
601 | if (!entry) | ||
602 | goto out_iput; | ||
603 | |||
604 | if (get_node_id(inode) != FUSE_ROOT_ID) { | ||
605 | entry->d_op = &fuse_dentry_operations; | ||
606 | fuse_invalidate_entry_cache(entry); | ||
607 | } | ||
608 | |||
609 | return entry; | ||
610 | |||
611 | out_iput: | ||
612 | iput(inode); | ||
613 | out_err: | ||
614 | return ERR_PTR(err); | ||
615 | } | ||
616 | |||
617 | static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, | ||
618 | int connectable) | ||
619 | { | ||
620 | struct inode *inode = dentry->d_inode; | ||
621 | bool encode_parent = connectable && !S_ISDIR(inode->i_mode); | ||
622 | int len = encode_parent ? 6 : 3; | ||
623 | u64 nodeid; | ||
624 | u32 generation; | ||
625 | |||
626 | if (*max_len < len) | ||
627 | return 255; | ||
628 | |||
629 | nodeid = get_fuse_inode(inode)->nodeid; | ||
630 | generation = inode->i_generation; | ||
631 | |||
632 | fh[0] = (u32)(nodeid >> 32); | ||
633 | fh[1] = (u32)(nodeid & 0xffffffff); | ||
634 | fh[2] = generation; | ||
635 | |||
636 | if (encode_parent) { | ||
637 | struct inode *parent; | ||
638 | |||
639 | spin_lock(&dentry->d_lock); | ||
640 | parent = dentry->d_parent->d_inode; | ||
641 | nodeid = get_fuse_inode(parent)->nodeid; | ||
642 | generation = parent->i_generation; | ||
643 | spin_unlock(&dentry->d_lock); | ||
644 | |||
645 | fh[3] = (u32)(nodeid >> 32); | ||
646 | fh[4] = (u32)(nodeid & 0xffffffff); | ||
647 | fh[5] = generation; | ||
648 | } | ||
649 | |||
650 | *max_len = len; | ||
651 | return encode_parent ? 0x82 : 0x81; | ||
652 | } | ||
653 | |||
654 | static struct dentry *fuse_fh_to_dentry(struct super_block *sb, | ||
655 | struct fid *fid, int fh_len, int fh_type) | ||
656 | { | ||
657 | struct fuse_inode_handle handle; | ||
658 | |||
659 | if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3) | ||
660 | return NULL; | ||
661 | |||
662 | handle.nodeid = (u64) fid->raw[0] << 32; | ||
663 | handle.nodeid |= (u64) fid->raw[1]; | ||
664 | handle.generation = fid->raw[2]; | ||
665 | return fuse_get_dentry(sb, &handle); | ||
666 | } | ||
667 | |||
668 | static struct dentry *fuse_fh_to_parent(struct super_block *sb, | ||
669 | struct fid *fid, int fh_len, int fh_type) | ||
670 | { | ||
671 | struct fuse_inode_handle parent; | ||
672 | |||
673 | if (fh_type != 0x82 || fh_len < 6) | ||
674 | return NULL; | ||
675 | |||
676 | parent.nodeid = (u64) fid->raw[3] << 32; | ||
677 | parent.nodeid |= (u64) fid->raw[4]; | ||
678 | parent.generation = fid->raw[5]; | ||
679 | return fuse_get_dentry(sb, &parent); | ||
680 | } | ||
681 | |||
682 | static struct dentry *fuse_get_parent(struct dentry *child) | ||
683 | { | ||
684 | struct inode *child_inode = child->d_inode; | ||
685 | struct fuse_conn *fc = get_fuse_conn(child_inode); | ||
686 | struct inode *inode; | ||
687 | struct dentry *parent; | ||
688 | struct fuse_entry_out outarg; | ||
689 | struct qstr name; | ||
690 | int err; | ||
691 | |||
692 | if (!fc->export_support) | ||
693 | return ERR_PTR(-ESTALE); | ||
694 | |||
695 | name.len = 2; | ||
696 | name.name = ".."; | ||
697 | err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode), | ||
698 | &name, &outarg, &inode); | ||
699 | if (err && err != -ENOENT) | ||
700 | return ERR_PTR(err); | ||
701 | if (err || !inode) | ||
702 | return ERR_PTR(-ESTALE); | ||
703 | |||
704 | parent = d_alloc_anon(inode); | ||
705 | if (!parent) { | ||
706 | iput(inode); | ||
707 | return ERR_PTR(-ENOMEM); | ||
708 | } | ||
709 | if (get_node_id(inode) != FUSE_ROOT_ID) { | ||
710 | parent->d_op = &fuse_dentry_operations; | ||
711 | fuse_invalidate_entry_cache(parent); | ||
712 | } | ||
713 | |||
714 | return parent; | ||
715 | } | ||
716 | |||
717 | static const struct export_operations fuse_export_operations = { | ||
718 | .fh_to_dentry = fuse_fh_to_dentry, | ||
719 | .fh_to_parent = fuse_fh_to_parent, | ||
720 | .encode_fh = fuse_encode_fh, | ||
721 | .get_parent = fuse_get_parent, | ||
722 | }; | ||
723 | |||
550 | static const struct super_operations fuse_super_operations = { | 724 | static const struct super_operations fuse_super_operations = { |
551 | .alloc_inode = fuse_alloc_inode, | 725 | .alloc_inode = fuse_alloc_inode, |
552 | .destroy_inode = fuse_destroy_inode, | 726 | .destroy_inode = fuse_destroy_inode, |
@@ -576,6 +750,13 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
576 | fc->no_lock = 1; | 750 | fc->no_lock = 1; |
577 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) | 751 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) |
578 | fc->atomic_o_trunc = 1; | 752 | fc->atomic_o_trunc = 1; |
753 | if (arg->minor >= 9) { | ||
754 | /* LOOKUP has dependency on proto version */ | ||
755 | if (arg->flags & FUSE_EXPORT_SUPPORT) | ||
756 | fc->export_support = 1; | ||
757 | } | ||
758 | if (arg->flags & FUSE_BIG_WRITES) | ||
759 | fc->big_writes = 1; | ||
579 | } else { | 760 | } else { |
580 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 761 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
581 | fc->no_lock = 1; | 762 | fc->no_lock = 1; |
@@ -584,7 +765,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
584 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); | 765 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); |
585 | fc->minor = arg->minor; | 766 | fc->minor = arg->minor; |
586 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | 767 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; |
587 | fc->max_write = min_t(unsigned, 4096, fc->max_write); | 768 | fc->max_write = max_t(unsigned, 4096, fc->max_write); |
588 | fc->conn_init = 1; | 769 | fc->conn_init = 1; |
589 | } | 770 | } |
590 | fuse_put_request(fc, req); | 771 | fuse_put_request(fc, req); |
@@ -599,7 +780,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
599 | arg->major = FUSE_KERNEL_VERSION; | 780 | arg->major = FUSE_KERNEL_VERSION; |
600 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 781 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
601 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 782 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
602 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC; | 783 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | |
784 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES; | ||
603 | req->in.h.opcode = FUSE_INIT; | 785 | req->in.h.opcode = FUSE_INIT; |
604 | req->in.numargs = 1; | 786 | req->in.numargs = 1; |
605 | req->in.args[0].size = sizeof(*arg); | 787 | req->in.args[0].size = sizeof(*arg); |
@@ -644,6 +826,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
644 | sb->s_magic = FUSE_SUPER_MAGIC; | 826 | sb->s_magic = FUSE_SUPER_MAGIC; |
645 | sb->s_op = &fuse_super_operations; | 827 | sb->s_op = &fuse_super_operations; |
646 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 828 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
829 | sb->s_export_op = &fuse_export_operations; | ||
647 | 830 | ||
648 | file = fget(d.fd); | 831 | file = fget(d.fd); |
649 | if (!file) | 832 | if (!file) |
@@ -659,7 +842,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
659 | fc->flags = d.flags; | 842 | fc->flags = d.flags; |
660 | fc->user_id = d.user_id; | 843 | fc->user_id = d.user_id; |
661 | fc->group_id = d.group_id; | 844 | fc->group_id = d.group_id; |
662 | fc->max_read = min_t(unsigned, 4096, d.max_read); | 845 | fc->max_read = max_t(unsigned, 4096, d.max_read); |
663 | 846 | ||
664 | /* Used by get_root_inode() */ | 847 | /* Used by get_root_inode() */ |
665 | sb->s_fs_info = fc; | 848 | sb->s_fs_info = fc; |
@@ -773,7 +956,7 @@ static inline void unregister_fuseblk(void) | |||
773 | } | 956 | } |
774 | #endif | 957 | #endif |
775 | 958 | ||
776 | static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo) | 959 | static void fuse_inode_init_once(void *foo) |
777 | { | 960 | { |
778 | struct inode * inode = foo; | 961 | struct inode * inode = foo; |
779 | 962 | ||