aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/inode.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2008-07-25 04:49:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:48 -0400
commitdbd561d236ff16f8143bc727d91758ddd190e8cb (patch)
treeaac8fb4d98c3f425b2f5bf404af7d82182f19bc0 /fs/fuse/inode.c
parent0de6256daafa3a97a269995e9b29f956bd419bbf (diff)
fuse: add export operations
Implement export_operations, to allow fuse filesystems to be exported to NFS. This feature has been in the out-of-tree fuse module, and is widely used and tested. It has not been originally merged into mainline, because doing the NFS export in userspace was thought to be a cleaner and more efficient way of doing it, than through the kernel. While that is true, it would also have involved a lot of duplicated effort at reimplementing NFS exporting (all the different versions of the protocol). This effort was unfortunately not undertaken by anyone, so we are left with doing it the easy but less efficient way. If this feature goes in, the out-of-tree fuse module can go away, which would have several advantages: - not having to maintain two versions - less confusion for users - no bugs due to kernel API changes Comment from hch: - Use the same fh_type values as XFS, since we use the same fh encoding. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r--fs/fuse/inode.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 3141690558c8..71fa76a48a31 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
22MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); 23MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
23MODULE_DESCRIPTION("Filesystem in Userspace"); 24MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -552,6 +553,119 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
552 return fuse_iget(sb, 1, 0, &attr, 0, 0); 553 return fuse_iget(sb, 1, 0, &attr, 0, 0);
553} 554}
554 555
556struct fuse_inode_handle
557{
558 u64 nodeid;
559 u32 generation;
560};
561
562static struct dentry *fuse_get_dentry(struct super_block *sb,
563 struct fuse_inode_handle *handle)
564{
565 struct inode *inode;
566 struct dentry *entry;
567 int err = -ESTALE;
568
569 if (handle->nodeid == 0)
570 goto out_err;
571
572 inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
573 if (!inode)
574 goto out_err;
575 err = -ESTALE;
576 if (inode->i_generation != handle->generation)
577 goto out_iput;
578
579 entry = d_alloc_anon(inode);
580 err = -ENOMEM;
581 if (!entry)
582 goto out_iput;
583
584 if (get_node_id(inode) != FUSE_ROOT_ID) {
585 entry->d_op = &fuse_dentry_operations;
586 fuse_invalidate_entry_cache(entry);
587 }
588
589 return entry;
590
591 out_iput:
592 iput(inode);
593 out_err:
594 return ERR_PTR(err);
595}
596
597static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
598 int connectable)
599{
600 struct inode *inode = dentry->d_inode;
601 bool encode_parent = connectable && !S_ISDIR(inode->i_mode);
602 int len = encode_parent ? 6 : 3;
603 u64 nodeid;
604 u32 generation;
605
606 if (*max_len < len)
607 return 255;
608
609 nodeid = get_fuse_inode(inode)->nodeid;
610 generation = inode->i_generation;
611
612 fh[0] = (u32)(nodeid >> 32);
613 fh[1] = (u32)(nodeid & 0xffffffff);
614 fh[2] = generation;
615
616 if (encode_parent) {
617 struct inode *parent;
618
619 spin_lock(&dentry->d_lock);
620 parent = dentry->d_parent->d_inode;
621 nodeid = get_fuse_inode(parent)->nodeid;
622 generation = parent->i_generation;
623 spin_unlock(&dentry->d_lock);
624
625 fh[3] = (u32)(nodeid >> 32);
626 fh[4] = (u32)(nodeid & 0xffffffff);
627 fh[5] = generation;
628 }
629
630 *max_len = len;
631 return encode_parent ? 0x82 : 0x81;
632}
633
634static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
635 struct fid *fid, int fh_len, int fh_type)
636{
637 struct fuse_inode_handle handle;
638
639 if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3)
640 return NULL;
641
642 handle.nodeid = (u64) fid->raw[0] << 32;
643 handle.nodeid |= (u64) fid->raw[1];
644 handle.generation = fid->raw[2];
645 return fuse_get_dentry(sb, &handle);
646}
647
648static struct dentry *fuse_fh_to_parent(struct super_block *sb,
649 struct fid *fid, int fh_len, int fh_type)
650{
651 struct fuse_inode_handle parent;
652
653 if (fh_type != 0x82 || fh_len < 6)
654 return NULL;
655
656 parent.nodeid = (u64) fid->raw[3] << 32;
657 parent.nodeid |= (u64) fid->raw[4];
658 parent.generation = fid->raw[5];
659 return fuse_get_dentry(sb, &parent);
660}
661
662
663static const struct export_operations fuse_export_operations = {
664 .fh_to_dentry = fuse_fh_to_dentry,
665 .fh_to_parent = fuse_fh_to_parent,
666 .encode_fh = fuse_encode_fh,
667};
668
555static const struct super_operations fuse_super_operations = { 669static const struct super_operations fuse_super_operations = {
556 .alloc_inode = fuse_alloc_inode, 670 .alloc_inode = fuse_alloc_inode,
557 .destroy_inode = fuse_destroy_inode, 671 .destroy_inode = fuse_destroy_inode,
@@ -652,6 +766,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
652 sb->s_magic = FUSE_SUPER_MAGIC; 766 sb->s_magic = FUSE_SUPER_MAGIC;
653 sb->s_op = &fuse_super_operations; 767 sb->s_op = &fuse_super_operations;
654 sb->s_maxbytes = MAX_LFS_FILESIZE; 768 sb->s_maxbytes = MAX_LFS_FILESIZE;
769 sb->s_export_op = &fuse_export_operations;
655 770
656 file = fget(d.fd); 771 file = fget(d.fd);
657 if (!file) 772 if (!file)