aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c4
-rw-r--r--fs/fuse/fuse_i.h4
-rw-r--r--fs/fuse/inode.c115
3 files changed, 121 insertions, 2 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index e5217b213b44..be5450dd6387 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -97,7 +97,7 @@ void fuse_invalidate_attr(struct inode *inode)
97 * timeout is unknown (unlink, rmdir, rename and in some cases 97 * timeout is unknown (unlink, rmdir, rename and in some cases
98 * lookup) 98 * lookup)
99 */ 99 */
100static void fuse_invalidate_entry_cache(struct dentry *entry) 100void fuse_invalidate_entry_cache(struct dentry *entry)
101{ 101{
102 fuse_dentry_settime(entry, 0); 102 fuse_dentry_settime(entry, 0);
103} 103}
@@ -225,7 +225,7 @@ static int invalid_nodeid(u64 nodeid)
225 return !nodeid || nodeid == FUSE_ROOT_ID; 225 return !nodeid || nodeid == FUSE_ROOT_ID;
226} 226}
227 227
228static struct dentry_operations fuse_dentry_operations = { 228struct dentry_operations fuse_dentry_operations = {
229 .d_revalidate = fuse_dentry_revalidate, 229 .d_revalidate = fuse_dentry_revalidate,
230}; 230};
231 231
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index bae948657c4f..5d3146da64e6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -464,6 +464,8 @@ static inline u64 get_node_id(struct inode *inode)
464/** Device operations */ 464/** Device operations */
465extern const struct file_operations fuse_dev_operations; 465extern const struct file_operations fuse_dev_operations;
466 466
467extern struct dentry_operations fuse_dentry_operations;
468
467/** 469/**
468 * Get a filled in inode 470 * Get a filled in inode
469 */ 471 */
@@ -604,6 +606,8 @@ void fuse_abort_conn(struct fuse_conn *fc);
604 */ 606 */
605void fuse_invalidate_attr(struct inode *inode); 607void fuse_invalidate_attr(struct inode *inode);
606 608
609void fuse_invalidate_entry_cache(struct dentry *entry);
610
607/** 611/**
608 * Acquire reference to fuse_conn 612 * Acquire reference to fuse_conn
609 */ 613 */
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)