diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2008-07-25 04:49:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:48 -0400 |
commit | 33670fa296860283f04a7975b8c790f101e43a6e (patch) | |
tree | 61162737edbffe696f4f9b13998d192cd3be3f75 /fs/fuse/inode.c | |
parent | c180eebe1390c2076ead6a9bc95a02efb994edb7 (diff) |
fuse: nfs export special lookups
Implement the get_parent export operation by sending a LOOKUP request with
".." as the name.
Implement looking up an inode by node ID after it has been evicted from
the cache. This is done by seding a LOOKUP request with "." as the name
(for all file types, not just directories).
The filesystem can set the FUSE_EXPORT_SUPPORT flag in the INIT reply, to
indicate that it supports these special lookups.
Thanks to John Muir for the original implementation of this feature.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Cc: "J. Bruce Fields" <bfields@fieldses.org>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: David Teigland <teigland@redhat.com>
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.c | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 71fa76a48a31..7d2f7d6e22e2 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -562,6 +562,7 @@ struct fuse_inode_handle | |||
562 | static struct dentry *fuse_get_dentry(struct super_block *sb, | 562 | static struct dentry *fuse_get_dentry(struct super_block *sb, |
563 | struct fuse_inode_handle *handle) | 563 | struct fuse_inode_handle *handle) |
564 | { | 564 | { |
565 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
565 | struct inode *inode; | 566 | struct inode *inode; |
566 | struct dentry *entry; | 567 | struct dentry *entry; |
567 | int err = -ESTALE; | 568 | int err = -ESTALE; |
@@ -570,8 +571,27 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, | |||
570 | goto out_err; | 571 | goto out_err; |
571 | 572 | ||
572 | inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); | 573 | inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); |
573 | if (!inode) | 574 | if (!inode) { |
574 | goto out_err; | 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 | } | ||
575 | err = -ESTALE; | 595 | err = -ESTALE; |
576 | if (inode->i_generation != handle->generation) | 596 | if (inode->i_generation != handle->generation) |
577 | goto out_iput; | 597 | goto out_iput; |
@@ -659,11 +679,46 @@ static struct dentry *fuse_fh_to_parent(struct super_block *sb, | |||
659 | return fuse_get_dentry(sb, &parent); | 679 | return fuse_get_dentry(sb, &parent); |
660 | } | 680 | } |
661 | 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 | } | ||
662 | 716 | ||
663 | static const struct export_operations fuse_export_operations = { | 717 | static const struct export_operations fuse_export_operations = { |
664 | .fh_to_dentry = fuse_fh_to_dentry, | 718 | .fh_to_dentry = fuse_fh_to_dentry, |
665 | .fh_to_parent = fuse_fh_to_parent, | 719 | .fh_to_parent = fuse_fh_to_parent, |
666 | .encode_fh = fuse_encode_fh, | 720 | .encode_fh = fuse_encode_fh, |
721 | .get_parent = fuse_get_parent, | ||
667 | }; | 722 | }; |
668 | 723 | ||
669 | static const struct super_operations fuse_super_operations = { | 724 | static const struct super_operations fuse_super_operations = { |
@@ -695,6 +750,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
695 | fc->no_lock = 1; | 750 | fc->no_lock = 1; |
696 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) | 751 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) |
697 | 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 | } | ||
698 | if (arg->flags & FUSE_BIG_WRITES) | 758 | if (arg->flags & FUSE_BIG_WRITES) |
699 | fc->big_writes = 1; | 759 | fc->big_writes = 1; |
700 | } else { | 760 | } else { |
@@ -721,7 +781,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
721 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 781 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
722 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 782 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
723 | 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 | |
724 | FUSE_BIG_WRITES; | 784 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES; |
725 | req->in.h.opcode = FUSE_INIT; | 785 | req->in.h.opcode = FUSE_INIT; |
726 | req->in.numargs = 1; | 786 | req->in.numargs = 1; |
727 | req->in.args[0].size = sizeof(*arg); | 787 | req->in.args[0].size = sizeof(*arg); |