aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2008-07-25 04:49:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:48 -0400
commit33670fa296860283f04a7975b8c790f101e43a6e (patch)
tree61162737edbffe696f4f9b13998d192cd3be3f75
parentc180eebe1390c2076ead6a9bc95a02efb994edb7 (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>
-rw-r--r--fs/fuse/fuse_i.h6
-rw-r--r--fs/fuse/inode.c66
-rw-r--r--include/linux/fuse.h3
3 files changed, 72 insertions, 3 deletions
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 5d3146da64e6..3a876076bdd1 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -363,6 +363,9 @@ struct fuse_conn {
363 /** Do not send separate SETATTR request before open(O_TRUNC) */ 363 /** Do not send separate SETATTR request before open(O_TRUNC) */
364 unsigned atomic_o_trunc : 1; 364 unsigned atomic_o_trunc : 1;
365 365
366 /** Filesystem supports NFS exporting. Only set in INIT */
367 unsigned export_support : 1;
368
366 /* 369 /*
367 * The following bitfields are only for optimization purposes 370 * The following bitfields are only for optimization purposes
368 * and hence races in setting them will not cause malfunction 371 * and hence races in setting them will not cause malfunction
@@ -473,6 +476,9 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
473 int generation, struct fuse_attr *attr, 476 int generation, struct fuse_attr *attr,
474 u64 attr_valid, u64 attr_version); 477 u64 attr_valid, u64 attr_version);
475 478
479int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
480 struct fuse_entry_out *outarg, struct inode **inode);
481
476/** 482/**
477 * Send FORGET command 483 * Send FORGET command
478 */ 484 */
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
562static struct dentry *fuse_get_dentry(struct super_block *sb, 562static 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
682static 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
663static const struct export_operations fuse_export_operations = { 717static 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
669static const struct super_operations fuse_super_operations = { 724static 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);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index d48282197696..265635dc9908 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -104,11 +104,14 @@ struct fuse_file_lock {
104 104
105/** 105/**
106 * INIT request/reply flags 106 * INIT request/reply flags
107 *
108 * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
107 */ 109 */
108#define FUSE_ASYNC_READ (1 << 0) 110#define FUSE_ASYNC_READ (1 << 0)
109#define FUSE_POSIX_LOCKS (1 << 1) 111#define FUSE_POSIX_LOCKS (1 << 1)
110#define FUSE_FILE_OPS (1 << 2) 112#define FUSE_FILE_OPS (1 << 2)
111#define FUSE_ATOMIC_O_TRUNC (1 << 3) 113#define FUSE_ATOMIC_O_TRUNC (1 << 3)
114#define FUSE_EXPORT_SUPPORT (1 << 4)
112#define FUSE_BIG_WRITES (1 << 5) 115#define FUSE_BIG_WRITES (1 << 5)
113 116
114/** 117/**