aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-10-21 19:42:05 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-22 11:13:19 -0400
commit2596110a3994593f6aa3e2bb76345ad4791b1a14 (patch)
tree0f1773238265f83e1b5640256176851a60ff5ea8 /fs
parent6e91ea2bb0b6a3ddf6d4faeb54a9c20d4e20bc42 (diff)
exportfs: add new methods
Add the guts for the new filesystem API to exportfs. There's now a fh_to_dentry method that returns a dentry for the object looked for given a filehandle fragment, and a fh_to_parent operation that returns the dentry for the encoded parent directory in case the file handle contains it. There are default implementations for these methods that only take a callback for an nfs-enhanced iget variant and implement the rest of the semantics. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: Neil Brown <neilb@suse.de> Cc: "J. Bruce Fields" <bfields@fieldses.org> Cc: <linux-ext4@vger.kernel.org> Cc: Dave Kleikamp <shaggy@austin.ibm.com> Cc: Anton Altaparmakov <aia21@cantab.net> Cc: David Chinner <dgc@sgi.com> Cc: Timothy Shimmin <tes@sgi.com> Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Cc: Hugh Dickins <hugh@veritas.com> Cc: Chris Mason <mason@suse.com> Cc: Jeff Mahoney <jeffm@suse.com> Cc: "Vladimir V. Saveliev" <vs@namesys.com> Cc: Steven Whitehouse <swhiteho@redhat.com> Cc: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/exportfs/expfs.c136
-rw-r--r--fs/libfs.c88
2 files changed, 218 insertions, 6 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 813011aad700..99294a23cd54 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -514,17 +514,141 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
514 int (*acceptable)(void *, struct dentry *), void *context) 514 int (*acceptable)(void *, struct dentry *), void *context)
515{ 515{
516 struct export_operations *nop = mnt->mnt_sb->s_export_op; 516 struct export_operations *nop = mnt->mnt_sb->s_export_op;
517 struct dentry *result; 517 struct dentry *result, *alias;
518 int err;
518 519
519 if (nop->decode_fh) { 520 /*
520 result = nop->decode_fh(mnt->mnt_sb, fid->raw, fh_len, 521 * Old way of doing things. Will go away soon.
522 */
523 if (!nop->fh_to_dentry) {
524 if (nop->decode_fh) {
525 return nop->decode_fh(mnt->mnt_sb, fid->raw, fh_len,
521 fileid_type, acceptable, context); 526 fileid_type, acceptable, context);
527 } else {
528 return export_decode_fh(mnt->mnt_sb, fid->raw, fh_len,
529 fileid_type, acceptable, context);
530 }
531 }
532
533 /*
534 * Try to get any dentry for the given file handle from the filesystem.
535 */
536 result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
537 if (!result)
538 result = ERR_PTR(-ESTALE);
539 if (IS_ERR(result))
540 return result;
541
542 if (S_ISDIR(result->d_inode->i_mode)) {
543 /*
544 * This request is for a directory.
545 *
546 * On the positive side there is only one dentry for each
547 * directory inode. On the negative side this implies that we
548 * to ensure our dentry is connected all the way up to the
549 * filesystem root.
550 */
551 if (result->d_flags & DCACHE_DISCONNECTED) {
552 err = reconnect_path(mnt->mnt_sb, result);
553 if (err)
554 goto err_result;
555 }
556
557 if (!acceptable(context, result)) {
558 err = -EACCES;
559 goto err_result;
560 }
561
562 return result;
522 } else { 563 } else {
523 result = export_decode_fh(mnt->mnt_sb, fid->raw, fh_len, 564 /*
524 fileid_type, acceptable, context); 565 * It's not a directory. Life is a little more complicated.
566 */
567 struct dentry *target_dir, *nresult;
568 char nbuf[NAME_MAX+1];
569
570 /*
571 * See if either the dentry we just got from the filesystem
572 * or any alias for it is acceptable. This is always true
573 * if this filesystem is exported without the subtreecheck
574 * option. If the filesystem is exported with the subtree
575 * check option there's a fair chance we need to look at
576 * the parent directory in the file handle and make sure
577 * it's connected to the filesystem root.
578 */
579 alias = find_acceptable_alias(result, acceptable, context);
580 if (alias)
581 return alias;
582
583 /*
584 * Try to extract a dentry for the parent directory from the
585 * file handle. If this fails we'll have to give up.
586 */
587 err = -ESTALE;
588 if (!nop->fh_to_parent)
589 goto err_result;
590
591 target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
592 fh_len, fileid_type);
593 if (!target_dir)
594 goto err_result;
595 err = PTR_ERR(target_dir);
596 if (IS_ERR(target_dir))
597 goto err_result;
598
599 /*
600 * And as usual we need to make sure the parent directory is
601 * connected to the filesystem root. The VFS really doesn't
602 * like disconnected directories..
603 */
604 err = reconnect_path(mnt->mnt_sb, target_dir);
605 if (err) {
606 dput(target_dir);
607 goto err_result;
608 }
609
610 /*
611 * Now that we've got both a well-connected parent and a
612 * dentry for the inode we're after, make sure that our
613 * inode is actually connected to the parent.
614 */
615 err = exportfs_get_name(target_dir, nbuf, result);
616 if (!err) {
617 mutex_lock(&target_dir->d_inode->i_mutex);
618 nresult = lookup_one_len(nbuf, target_dir,
619 strlen(nbuf));
620 mutex_unlock(&target_dir->d_inode->i_mutex);
621 if (!IS_ERR(nresult)) {
622 if (nresult->d_inode) {
623 dput(result);
624 result = nresult;
625 } else
626 dput(nresult);
627 }
628 }
629
630 /*
631 * At this point we are done with the parent, but it's pinned
632 * by the child dentry anyway.
633 */
634 dput(target_dir);
635
636 /*
637 * And finally make sure the dentry is actually acceptable
638 * to NFSD.
639 */
640 alias = find_acceptable_alias(result, acceptable, context);
641 if (!alias) {
642 err = -EACCES;
643 goto err_result;
644 }
645
646 return alias;
525 } 647 }
526 648
527 return result; 649 err_result:
650 dput(result);
651 return ERR_PTR(err);
528} 652}
529EXPORT_SYMBOL_GPL(exportfs_decode_fh); 653EXPORT_SYMBOL_GPL(exportfs_decode_fh);
530 654
diff --git a/fs/libfs.c b/fs/libfs.c
index ae51481e45e5..6e68b700958d 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -8,6 +8,7 @@
8#include <linux/mount.h> 8#include <linux/mount.h>
9#include <linux/vfs.h> 9#include <linux/vfs.h>
10#include <linux/mutex.h> 10#include <linux/mutex.h>
11#include <linux/exportfs.h>
11 12
12#include <asm/uaccess.h> 13#include <asm/uaccess.h>
13 14
@@ -678,6 +679,93 @@ out:
678 return ret; 679 return ret;
679} 680}
680 681
682/*
683 * This is what d_alloc_anon should have been. Once the exportfs
684 * argument transition has been finished I will update d_alloc_anon
685 * to this prototype and this wrapper will go away. --hch
686 */
687static struct dentry *exportfs_d_alloc(struct inode *inode)
688{
689 struct dentry *dentry;
690
691 if (!inode)
692 return NULL;
693 if (IS_ERR(inode))
694 return ERR_PTR(PTR_ERR(inode));
695
696 dentry = d_alloc_anon(inode);
697 if (!dentry) {
698 iput(inode);
699 dentry = ERR_PTR(-ENOMEM);
700 }
701 return dentry;
702}
703
704/**
705 * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
706 * @sb: filesystem to do the file handle conversion on
707 * @fid: file handle to convert
708 * @fh_len: length of the file handle in bytes
709 * @fh_type: type of file handle
710 * @get_inode: filesystem callback to retrieve inode
711 *
712 * This function decodes @fid as long as it has one of the well-known
713 * Linux filehandle types and calls @get_inode on it to retrieve the
714 * inode for the object specified in the file handle.
715 */
716struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
717 int fh_len, int fh_type, struct inode *(*get_inode)
718 (struct super_block *sb, u64 ino, u32 gen))
719{
720 struct inode *inode = NULL;
721
722 if (fh_len < 2)
723 return NULL;
724
725 switch (fh_type) {
726 case FILEID_INO32_GEN:
727 case FILEID_INO32_GEN_PARENT:
728 inode = get_inode(sb, fid->i32.ino, fid->i32.gen);
729 break;
730 }
731
732 return exportfs_d_alloc(inode);
733}
734EXPORT_SYMBOL_GPL(generic_fh_to_dentry);
735
736/**
737 * generic_fh_to_dentry - generic helper for the fh_to_parent export operation
738 * @sb: filesystem to do the file handle conversion on
739 * @fid: file handle to convert
740 * @fh_len: length of the file handle in bytes
741 * @fh_type: type of file handle
742 * @get_inode: filesystem callback to retrieve inode
743 *
744 * This function decodes @fid as long as it has one of the well-known
745 * Linux filehandle types and calls @get_inode on it to retrieve the
746 * inode for the _parent_ object specified in the file handle if it
747 * is specified in the file handle, or NULL otherwise.
748 */
749struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
750 int fh_len, int fh_type, struct inode *(*get_inode)
751 (struct super_block *sb, u64 ino, u32 gen))
752{
753 struct inode *inode = NULL;
754
755 if (fh_len <= 2)
756 return NULL;
757
758 switch (fh_type) {
759 case FILEID_INO32_GEN_PARENT:
760 inode = get_inode(sb, fid->i32.parent_ino,
761 (fh_len > 3 ? fid->i32.parent_gen : 0));
762 break;
763 }
764
765 return exportfs_d_alloc(inode);
766}
767EXPORT_SYMBOL_GPL(generic_fh_to_parent);
768
681EXPORT_SYMBOL(dcache_dir_close); 769EXPORT_SYMBOL(dcache_dir_close);
682EXPORT_SYMBOL(dcache_dir_lseek); 770EXPORT_SYMBOL(dcache_dir_lseek);
683EXPORT_SYMBOL(dcache_dir_open); 771EXPORT_SYMBOL(dcache_dir_open);