linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount
@ 2006-02-22 20:21 David Howells
  2006-02-22 20:21 ` [PATCH 2/5] NFS: Apply mount root dentry override to filesystems David Howells
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: David Howells @ 2006-02-22 20:21 UTC (permalink / raw)
  To: torvalds, akpm, steved, trond.myklebust, aviro
  Cc: linux-kernel, linux-cachefs, nfsv4, linux-fsdevel

The attached patch extends the get_sb() filesystem operation to take an extra
argument that permits the default root dentry choice (sb->s_root) to be
overridden by the filesystem that owns the superblock.

If the dentry pointer pointed to by that argument is left unchanged, then
do_kern_mount() will use sb->s_root as the root of the mount. If the filesystem
sets the pointer to a dentry of its choice, then that will be used as the root
for that particular mount.

This patch permits a superblock to be implicitly shared amongst several mount
points, such as can be done with NFS to avoid potential inode aliasing (see
patch 5/5).

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 getsb-2616rc4.diff
 Documentation/filesystems/porting |    2 +-
 fs/super.c                        |   10 +++++++---
 include/linux/fs.h                |    2 +-
 3 files changed, 9 insertions(+), 5 deletions(-)

diff -uNrp linux-2.6.16-rc4/Documentation/filesystems/porting linux-2.6.16-rc4-getsb/Documentation/filesystems/porting
--- linux-2.6.16-rc4/Documentation/filesystems/porting	2004-06-18 13:42:30.000000000 +0100
+++ linux-2.6.16-rc4-getsb/Documentation/filesystems/porting	2006-02-22 17:11:59.000000000 +0000
@@ -51,7 +51,7 @@ success and negative number in case of e
 informative error value to report).  Call it foo_fill_super().  Now declare
 
 struct super_block foo_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/include/linux/fs.h linux-2.6.16-rc4-getsb/include/linux/fs.h
--- linux-2.6.16-rc4/include/linux/fs.h	2006-02-22 17:00:41.000000000 +0000
+++ linux-2.6.16-rc4-getsb/include/linux/fs.h	2006-02-22 17:08:45.000000000 +0000
@@ -1240,7 +1240,7 @@ struct file_system_type {
 	const char *name;
 	int fs_flags;
 	struct super_block *(*get_sb) (struct file_system_type *, int,
-				       const char *, void *);
+				       const char *, void *, struct dentry **);
 	void (*kill_sb) (struct super_block *);
 	struct module *owner;
 	struct file_system_type * next;
diff -uNrp linux-2.6.16-rc4/fs/super.c linux-2.6.16-rc4-getsb/fs/super.c
--- linux-2.6.16-rc4/fs/super.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/super.c	2006-02-22 17:08:45.000000000 +0000
@@ -792,6 +792,7 @@ do_kern_mount(const char *fstype, int fl
 	struct file_system_type *type = get_fs_type(fstype);
 	struct super_block *sb = ERR_PTR(-ENOMEM);
 	struct vfsmount *mnt;
+	struct dentry *root;
 	int error;
 	char *secdata = NULL;
 
@@ -816,15 +817,18 @@ do_kern_mount(const char *fstype, int fl
 		}
 	}
 
-	sb = type->get_sb(type, flags, name, data);
+	root = NULL;
+	sb = type->get_sb(type, flags, name, data, &root);
 	if (IS_ERR(sb))
 		goto out_free_secdata;
+	if (!root)
+		root = dget(sb->s_root);
  	error = security_sb_kern_mount(sb, secdata);
  	if (error)
  		goto out_sb;
 	mnt->mnt_sb = sb;
-	mnt->mnt_root = dget(sb->s_root);
-	mnt->mnt_mountpoint = sb->s_root;
+	mnt->mnt_root = root;
+	mnt->mnt_mountpoint = root;
 	mnt->mnt_parent = mnt;
 	up_write(&sb->s_umount);
 	free_secdata(secdata);

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/5] NFS: Apply mount root dentry override to filesystems
  2006-02-22 20:21 [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount David Howells
@ 2006-02-22 20:21 ` David Howells
  2006-02-22 20:21 ` [PATCH 5/5] NFS: Unify NFS superblocks per-protocol per-server David Howells
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: David Howells @ 2006-02-22 20:21 UTC (permalink / raw)
  To: torvalds, akpm, steved, trond.myklebust, aviro
  Cc: linux-kernel, linux-cachefs, nfsv4, linux-fsdevel

The attached patch changes all the filesystems in the kernel to deal with the
extra argument to get_sb(). In every case the extra argument is simply ignored,
thus causing the dentry returned in sb->s_root to be used as the root of the
mountpoint.

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 getsb-change-fses-2616rc4.diff
 arch/ia64/kernel/perfmon.c                |    3 ++-
 arch/powerpc/platforms/cell/spufs/inode.c |    2 +-
 drivers/infiniband/core/uverbs_main.c     |    3 ++-
 drivers/isdn/capi/capifs.c                |    2 +-
 drivers/misc/ibmasm/ibmasmfs.c            |    3 ++-
 drivers/oprofile/oprofilefs.c             |    2 +-
 drivers/usb/core/inode.c                  |    2 +-
 drivers/usb/gadget/inode.c                |    2 +-
 fs/9p/vfs_super.c                         |    3 ++-
 fs/adfs/super.c                           |    2 +-
 fs/affs/super.c                           |    2 +-
 fs/afs/super.c                            |    5 +++--
 fs/autofs/init.c                          |    2 +-
 fs/autofs4/init.c                         |    2 +-
 fs/befs/linuxvfs.c                        |    2 +-
 fs/bfs/inode.c                            |    2 +-
 fs/binfmt_misc.c                          |    2 +-
 fs/block_dev.c                            |    2 +-
 fs/cifs/cifsfs.c                          |    2 +-
 fs/coda/inode.c                           |    2 +-
 fs/configfs/mount.c                       |    2 +-
 fs/cramfs/inode.c                         |    2 +-
 fs/debugfs/inode.c                        |    2 +-
 fs/devfs/base.c                           |    2 +-
 fs/devpts/inode.c                         |    2 +-
 fs/efs/super.c                            |    2 +-
 fs/eventpoll.c                            |    4 ++--
 fs/ext2/super.c                           |    2 +-
 fs/ext3/super.c                           |    2 +-
 fs/freevxfs/vxfs_super.c                  |    2 +-
 fs/fuse/inode.c                           |    2 +-
 fs/hfs/super.c                            |    3 ++-
 fs/hfsplus/super.c                        |    3 ++-
 fs/hpfs/super.c                           |    2 +-
 fs/hugetlbfs/inode.c                      |    2 +-
 fs/inotify.c                              |    2 +-
 fs/isofs/inode.c                          |    2 +-
 fs/jffs/inode-v23.c                       |    2 +-
 fs/jffs2/super.c                          |    2 +-
 fs/jfs/super.c                            |    2 +-
 fs/minix/inode.c                          |    2 +-
 fs/msdos/namei.c                          |    2 +-
 fs/ncpfs/inode.c                          |    2 +-
 fs/nfs/inode.c                            |    4 ++--
 fs/nfsd/nfsctl.c                          |    2 +-
 fs/ntfs/super.c                           |    2 +-
 fs/ocfs2/dlm/dlmfs.c                      |    2 +-
 fs/ocfs2/super.c                          |    3 ++-
 fs/openpromfs/inode.c                     |    2 +-
 fs/pipe.c                                 |    2 +-
 fs/proc/root.c                            |    2 +-
 fs/qnx4/inode.c                           |    2 +-
 fs/ramfs/inode.c                          |    4 ++--
 fs/relayfs/inode.c                        |    2 +-
 fs/romfs/inode.c                          |    2 +-
 fs/smbfs/inode.c                          |    2 +-
 fs/sysfs/mount.c                          |    2 +-
 fs/sysv/super.c                           |    4 ++--
 fs/udf/super.c                            |    2 +-
 fs/ufs/super.c                            |    2 +-
 fs/vfat/namei.c                           |    2 +-
 fs/xfs/linux-2.6/xfs_super.c              |    3 ++-
 include/linux/ramfs.h                     |    2 +-
 ipc/mqueue.c                              |    2 +-
 kernel/cpuset.c                           |    2 +-
 kernel/futex.c                            |    2 +-
 mm/shmem.c                                |    2 +-
 net/socket.c                              |    2 +-
 net/sunrpc/rpc_pipe.c                     |    2 +-
 security/selinux/selinuxfs.c              |    3 ++-
 70 files changed, 85 insertions(+), 75 deletions(-)

diff -uNrp linux-2.6.16-rc4/arch/ia64/kernel/perfmon.c linux-2.6.16-rc4-getsb/arch/ia64/kernel/perfmon.c
--- linux-2.6.16-rc4/arch/ia64/kernel/perfmon.c	2006-02-22 17:00:19.000000000 +0000
+++ linux-2.6.16-rc4-getsb/arch/ia64/kernel/perfmon.c	2006-02-22 17:08:45.000000000 +0000
@@ -596,7 +596,8 @@ pfm_get_unmapped_area(struct file *file,
 
 
 static struct super_block *
-pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
+pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data,
+	     struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC);
 }
diff -uNrp linux-2.6.16-rc4/arch/powerpc/platforms/cell/spufs/inode.c linux-2.6.16-rc4-getsb/arch/powerpc/platforms/cell/spufs/inode.c
--- linux-2.6.16-rc4/arch/powerpc/platforms/cell/spufs/inode.c	2006-02-22 17:00:22.000000000 +0000
+++ linux-2.6.16-rc4-getsb/arch/powerpc/platforms/cell/spufs/inode.c	2006-02-22 17:10:18.000000000 +0000
@@ -430,7 +430,7 @@ spufs_fill_super(struct super_block *sb,
 
 static struct super_block *
 spufs_get_sb(struct file_system_type *fstype, int flags,
-		const char *name, void *data)
+		const char *name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fstype, flags, data, spufs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/drivers/infiniband/core/uverbs_main.c linux-2.6.16-rc4-getsb/drivers/infiniband/core/uverbs_main.c
--- linux-2.6.16-rc4/drivers/infiniband/core/uverbs_main.c	2006-02-22 17:00:27.000000000 +0000
+++ linux-2.6.16-rc4-getsb/drivers/infiniband/core/uverbs_main.c	2006-02-22 17:16:59.000000000 +0000
@@ -819,7 +819,8 @@ static void ib_uverbs_remove_one(struct 
 }
 
 static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
-					       const char *dev_name, void *data)
+					       const char *dev_name, void *data,
+					       struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
 			     INFINIBANDEVENTFS_MAGIC);
diff -uNrp linux-2.6.16-rc4/drivers/isdn/capi/capifs.c linux-2.6.16-rc4-getsb/drivers/isdn/capi/capifs.c
--- linux-2.6.16-rc4/drivers/isdn/capi/capifs.c	2006-02-22 17:00:28.000000000 +0000
+++ linux-2.6.16-rc4-getsb/drivers/isdn/capi/capifs.c	2006-02-22 17:08:47.000000000 +0000
@@ -122,7 +122,7 @@ fail:
 }
 
 static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, capifs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/drivers/misc/ibmasm/ibmasmfs.c linux-2.6.16-rc4-getsb/drivers/misc/ibmasm/ibmasmfs.c
--- linux-2.6.16-rc4/drivers/misc/ibmasm/ibmasmfs.c	2005-08-30 13:56:18.000000000 +0100
+++ linux-2.6.16-rc4-getsb/drivers/misc/ibmasm/ibmasmfs.c	2006-02-22 17:08:47.000000000 +0000
@@ -91,7 +91,8 @@ static int ibmasmfs_fill_super (struct s
 
 
 static struct super_block *ibmasmfs_get_super(struct file_system_type *fst,
-			int flags, const char *name, void *data)
+			int flags, const char *name, void *data,
+			struct dentry **_root)
 {
 	return get_sb_single(fst, flags, data, ibmasmfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/drivers/oprofile/oprofilefs.c linux-2.6.16-rc4-getsb/drivers/oprofile/oprofilefs.c
--- linux-2.6.16-rc4/drivers/oprofile/oprofilefs.c	2005-03-02 12:08:20.000000000 +0000
+++ linux-2.6.16-rc4-getsb/drivers/oprofile/oprofilefs.c	2006-02-22 17:08:47.000000000 +0000
@@ -273,7 +273,7 @@ static int oprofilefs_fill_super(struct 
 
 
 static struct super_block *oprofilefs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, oprofilefs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/drivers/usb/core/inode.c linux-2.6.16-rc4-getsb/drivers/usb/core/inode.c
--- linux-2.6.16-rc4/drivers/usb/core/inode.c	2006-02-22 17:00:34.000000000 +0000
+++ linux-2.6.16-rc4-getsb/drivers/usb/core/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -544,7 +544,7 @@ static void fs_remove_file (struct dentr
 /* --------------------------------------------------------------------- */
 
 static struct super_block *usb_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, usbfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/drivers/usb/gadget/inode.c linux-2.6.16-rc4-getsb/drivers/usb/gadget/inode.c
--- linux-2.6.16-rc4/drivers/usb/gadget/inode.c	2006-02-22 17:00:34.000000000 +0000
+++ linux-2.6.16-rc4-getsb/drivers/usb/gadget/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -2067,7 +2067,7 @@ gadgetfs_fill_super (struct super_block 
 /* "mount -t gadgetfs path /dev/gadget" ends up here */
 static struct super_block *
 gadgetfs_get_sb (struct file_system_type *t, int flags,
-		const char *path, void *opts)
+		const char *path, void *opts, struct dentry **_root)
 {
 	return get_sb_single (t, flags, opts, gadgetfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/9p/vfs_super.c linux-2.6.16-rc4-getsb/fs/9p/vfs_super.c
--- linux-2.6.16-rc4/fs/9p/vfs_super.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/9p/vfs_super.c	2006-02-22 17:15:20.000000000 +0000
@@ -105,7 +105,8 @@ v9fs_fill_super(struct super_block *sb, 
 
 static struct super_block *v9fs_get_sb(struct file_system_type
 				       *fs_type, int flags,
-				       const char *dev_name, void *data)
+				       const char *dev_name, void *data,
+				       struct dentry **_root)
 {
 	struct super_block *sb = NULL;
 	struct v9fs_fcall *fcall = NULL;
diff -uNrp linux-2.6.16-rc4/fs/adfs/super.c linux-2.6.16-rc4-getsb/fs/adfs/super.c
--- linux-2.6.16-rc4/fs/adfs/super.c	2005-01-04 11:13:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/adfs/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -470,7 +470,7 @@ error:
 }
 
 static struct super_block *adfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/affs/super.c linux-2.6.16-rc4-getsb/fs/affs/super.c
--- linux-2.6.16-rc4/fs/affs/super.c	2006-01-04 12:39:35.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/affs/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -524,7 +524,7 @@ affs_statfs(struct super_block *sb, stru
 }
 
 static struct super_block *affs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/afs/super.c linux-2.6.16-rc4-getsb/fs/afs/super.c
--- linux-2.6.16-rc4/fs/afs/super.c	2004-09-16 12:06:12.000000000 +0100
+++ linux-2.6.16-rc4-getsb/fs/afs/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -40,7 +40,7 @@ static void afs_i_init_once(void *foo, k
 
 static struct super_block *afs_get_sb(struct file_system_type *fs_type,
 				      int flags, const char *dev_name,
-				      void *data);
+				      void *data, struct dentry **_root);
 
 static struct inode *afs_alloc_inode(struct super_block *sb);
 
@@ -297,7 +297,8 @@ static int afs_fill_super(struct super_b
 static struct super_block *afs_get_sb(struct file_system_type *fs_type,
 				      int flags,
 				      const char *dev_name,
-				      void *options)
+				      void *options,
+				      struct dentry **_root)
 {
 	struct afs_mount_params params;
 	struct super_block *sb;
diff -uNrp linux-2.6.16-rc4/fs/autofs/init.c linux-2.6.16-rc4-getsb/fs/autofs/init.c
--- linux-2.6.16-rc4/fs/autofs/init.c	2004-06-18 13:41:28.000000000 +0100
+++ linux-2.6.16-rc4-getsb/fs/autofs/init.c	2006-02-22 17:08:47.000000000 +0000
@@ -15,7 +15,7 @@
 #include "autofs_i.h"
 
 static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, autofs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/autofs4/init.c linux-2.6.16-rc4-getsb/fs/autofs4/init.c
--- linux-2.6.16-rc4/fs/autofs4/init.c	2004-06-18 13:41:20.000000000 +0100
+++ linux-2.6.16-rc4-getsb/fs/autofs4/init.c	2006-02-22 17:08:47.000000000 +0000
@@ -15,7 +15,7 @@
 #include "autofs_i.h"
 
 static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, autofs4_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/befs/linuxvfs.c linux-2.6.16-rc4-getsb/fs/befs/linuxvfs.c
--- linux-2.6.16-rc4/fs/befs/linuxvfs.c	2006-01-04 12:39:35.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/befs/linuxvfs.c	2006-02-22 17:08:47.000000000 +0000
@@ -900,7 +900,7 @@ befs_statfs(struct super_block *sb, stru
 
 static struct super_block *
 befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name,
-	    void *data)
+	    void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/bfs/inode.c linux-2.6.16-rc4-getsb/fs/bfs/inode.c
--- linux-2.6.16-rc4/fs/bfs/inode.c	2005-11-01 13:19:14.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/bfs/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -410,7 +410,7 @@ out:
 }
 
 static struct super_block *bfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/binfmt_misc.c linux-2.6.16-rc4-getsb/fs/binfmt_misc.c
--- linux-2.6.16-rc4/fs/binfmt_misc.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/binfmt_misc.c	2006-02-22 17:08:47.000000000 +0000
@@ -741,7 +741,7 @@ static int bm_fill_super(struct super_bl
 }
 
 static struct super_block *bm_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, bm_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/block_dev.c linux-2.6.16-rc4-getsb/fs/block_dev.c
--- linux-2.6.16-rc4/fs/block_dev.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/block_dev.c	2006-02-22 17:08:47.000000000 +0000
@@ -301,7 +301,7 @@ static struct super_operations bdev_sops
 };
 
 static struct super_block *bd_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576);
 }
diff -uNrp linux-2.6.16-rc4/fs/cifs/cifsfs.c linux-2.6.16-rc4-getsb/fs/cifs/cifsfs.c
--- linux-2.6.16-rc4/fs/cifs/cifsfs.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/cifs/cifsfs.c	2006-02-22 17:13:10.000000000 +0000
@@ -467,7 +467,7 @@ struct super_operations cifs_super_ops =
 
 static struct super_block *
 cifs_get_sb(struct file_system_type *fs_type,
-	    int flags, const char *dev_name, void *data)
+	    int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	int rc;
 	struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
diff -uNrp linux-2.6.16-rc4/fs/coda/inode.c linux-2.6.16-rc4-getsb/fs/coda/inode.c
--- linux-2.6.16-rc4/fs/coda/inode.c	2005-03-02 12:08:35.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/coda/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -306,7 +306,7 @@ static int coda_statfs(struct super_bloc
 /* init_coda: used by filesystems.c to register coda */
 
 static struct super_block *coda_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, coda_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/configfs/mount.c linux-2.6.16-rc4-getsb/fs/configfs/mount.c
--- linux-2.6.16-rc4/fs/configfs/mount.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/configfs/mount.c	2006-02-22 17:15:50.000000000 +0000
@@ -104,7 +104,7 @@ static int configfs_fill_super(struct su
 }
 
 static struct super_block *configfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, configfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/cramfs/inode.c linux-2.6.16-rc4-getsb/fs/cramfs/inode.c
--- linux-2.6.16-rc4/fs/cramfs/inode.c	2005-11-01 13:19:14.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/cramfs/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -530,7 +530,7 @@ static struct super_operations cramfs_op
 };
 
 static struct super_block *cramfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/debugfs/inode.c linux-2.6.16-rc4-getsb/fs/debugfs/inode.c
--- linux-2.6.16-rc4/fs/debugfs/inode.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/debugfs/inode.c	2006-02-22 17:14:48.000000000 +0000
@@ -112,7 +112,7 @@ static int debug_fill_super(struct super
 
 static struct super_block *debug_get_sb(struct file_system_type *fs_type,
 				        int flags, const char *dev_name,
-					void *data)
+					void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, debug_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/devfs/base.c linux-2.6.16-rc4-getsb/fs/devfs/base.c
--- linux-2.6.16-rc4/fs/devfs/base.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/devfs/base.c	2006-02-22 17:08:47.000000000 +0000
@@ -2551,7 +2551,7 @@ static int devfs_fill_super(struct super
 
 static struct super_block *devfs_get_sb(struct file_system_type *fs_type,
 					int flags, const char *dev_name,
-					void *data)
+					void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, devfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/devpts/inode.c linux-2.6.16-rc4-getsb/fs/devpts/inode.c
--- linux-2.6.16-rc4/fs/devpts/inode.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/devpts/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -109,7 +109,7 @@ fail:
 }
 
 static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, devpts_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/efs/super.c linux-2.6.16-rc4-getsb/fs/efs/super.c
--- linux-2.6.16-rc4/fs/efs/super.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/efs/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -19,7 +19,7 @@ static int efs_statfs(struct super_block
 static int efs_fill_super(struct super_block *s, void *d, int silent);
 
 static struct super_block *efs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/eventpoll.c linux-2.6.16-rc4-getsb/fs/eventpoll.c
--- linux-2.6.16-rc4/fs/eventpoll.c	2005-11-01 13:19:14.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/eventpoll.c	2006-02-22 17:08:47.000000000 +0000
@@ -269,7 +269,7 @@ static int eventpollfs_delete_dentry(str
 static struct inode *ep_eventpoll_inode(void);
 static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
 					      int flags, const char *dev_name,
-					      void *data);
+					      void *data, struct dentry **_root);
 
 /*
  * This semaphore is used to serialize ep_free() and eventpoll_release_file().
@@ -1605,7 +1605,7 @@ eexit_1:
 
 static struct super_block *
 eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
-		   const char *dev_name, void *data)
+		   const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC);
 }
diff -uNrp linux-2.6.16-rc4/fs/ext2/super.c linux-2.6.16-rc4-getsb/fs/ext2/super.c
--- linux-2.6.16-rc4/fs/ext2/super.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ext2/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -1090,7 +1090,7 @@ static int ext2_statfs (struct super_blo
 }
 
 static struct super_block *ext2_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ext3/super.c linux-2.6.16-rc4-getsb/fs/ext3/super.c
--- linux-2.6.16-rc4/fs/ext3/super.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ext3/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -2651,7 +2651,7 @@ out:
 #endif
 
 static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/freevxfs/vxfs_super.c linux-2.6.16-rc4-getsb/fs/freevxfs/vxfs_super.c
--- linux-2.6.16-rc4/fs/freevxfs/vxfs_super.c	2005-11-01 13:19:14.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/freevxfs/vxfs_super.c	2006-02-22 17:08:47.000000000 +0000
@@ -242,7 +242,7 @@ out:
  * The usual module blurb.
  */
 static struct super_block *vxfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/fuse/inode.c linux-2.6.16-rc4-getsb/fs/fuse/inode.c
--- linux-2.6.16-rc4/fs/fuse/inode.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/fuse/inode.c	2006-02-22 17:13:29.000000000 +0000
@@ -606,7 +606,7 @@ static int fuse_fill_super(struct super_
 
 static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
 				       int flags, const char *dev_name,
-				       void *raw_data)
+				       void *raw_data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/hfs/super.c linux-2.6.16-rc4-getsb/fs/hfs/super.c
--- linux-2.6.16-rc4/fs/hfs/super.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/hfs/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -414,7 +414,8 @@ bail:
 }
 
 static struct super_block *hfs_get_sb(struct file_system_type *fs_type,
-				      int flags, const char *dev_name, void *data)
+				      int flags, const char *dev_name, void *data,
+				      struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/hfsplus/super.c linux-2.6.16-rc4-getsb/fs/hfsplus/super.c
--- linux-2.6.16-rc4/fs/hfsplus/super.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/hfsplus/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -451,7 +451,8 @@ static void hfsplus_destroy_inode(struct
 #define HFSPLUS_INODE_SIZE	sizeof(struct hfsplus_inode_info)
 
 static struct super_block *hfsplus_get_sb(struct file_system_type *fs_type,
-					  int flags, const char *dev_name, void *data)
+					  int flags, const char *dev_name, void *data,
+					  struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/hpfs/super.c linux-2.6.16-rc4-getsb/fs/hpfs/super.c
--- linux-2.6.16-rc4/fs/hpfs/super.c	2006-01-04 12:39:35.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/hpfs/super.c	2006-02-22 17:08:47.000000000 +0000
@@ -662,7 +662,7 @@ bail0:
 }
 
 static struct super_block *hpfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/hugetlbfs/inode.c linux-2.6.16-rc4-getsb/fs/hugetlbfs/inode.c
--- linux-2.6.16-rc4/fs/hugetlbfs/inode.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/hugetlbfs/inode.c	2006-02-22 17:08:47.000000000 +0000
@@ -758,7 +758,7 @@ void hugetlb_put_quota(struct address_sp
 }
 
 static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/inotify.c linux-2.6.16-rc4-getsb/fs/inotify.c
--- linux-2.6.16-rc4/fs/inotify.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/inotify.c	2006-02-22 17:14:52.000000000 +0000
@@ -1032,7 +1032,7 @@ out:
 
 static struct super_block *
 inotify_get_sb(struct file_system_type *fs_type, int flags,
-	       const char *dev_name, void *data)
+	       const char *dev_name, void *data, struct dentry **_root)
 {
     return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA);
 }
diff -uNrp linux-2.6.16-rc4/fs/isofs/inode.c linux-2.6.16-rc4-getsb/fs/isofs/inode.c
--- linux-2.6.16-rc4/fs/isofs/inode.c	2006-01-04 12:39:35.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/isofs/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -1399,7 +1399,7 @@ struct inode *isofs_iget(struct super_bl
 }
 
 static struct super_block *isofs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/jffs/inode-v23.c linux-2.6.16-rc4-getsb/fs/jffs/inode-v23.c
--- linux-2.6.16-rc4/fs/jffs/inode-v23.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/jffs/inode-v23.c	2006-02-22 17:08:48.000000000 +0000
@@ -1786,7 +1786,7 @@ static struct super_operations jffs_ops 
 };
 
 static struct super_block *jffs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/jffs2/super.c linux-2.6.16-rc4-getsb/fs/jffs2/super.c
--- linux-2.6.16-rc4/fs/jffs2/super.c	2006-01-04 12:39:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/jffs2/super.c	2006-02-22 17:08:48.000000000 +0000
@@ -188,7 +188,7 @@ static struct super_block *jffs2_get_sb_
 
 static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
 					int flags, const char *dev_name,
-					void *data)
+					void *data, struct dentry **_root)
 {
 	int err;
 	struct nameidata nd;
diff -uNrp linux-2.6.16-rc4/fs/jfs/super.c linux-2.6.16-rc4-getsb/fs/jfs/super.c
--- linux-2.6.16-rc4/fs/jfs/super.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/jfs/super.c	2006-02-22 17:08:48.000000000 +0000
@@ -542,7 +542,7 @@ static void jfs_unlockfs(struct super_bl
 }
 
 static struct super_block *jfs_get_sb(struct file_system_type *fs_type, 
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/minix/inode.c linux-2.6.16-rc4-getsb/fs/minix/inode.c
--- linux-2.6.16-rc4/fs/minix/inode.c	2005-11-01 13:19:15.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/minix/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -559,7 +559,7 @@ void minix_truncate(struct inode * inode
 }
 
 static struct super_block *minix_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/msdos/namei.c linux-2.6.16-rc4-getsb/fs/msdos/namei.c
--- linux-2.6.16-rc4/fs/msdos/namei.c	2006-01-04 12:39:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/msdos/namei.c	2006-02-22 17:14:34.000000000 +0000
@@ -676,7 +676,7 @@ static int msdos_fill_super(struct super
 
 static struct super_block *msdos_get_sb(struct file_system_type *fs_type,
 					int flags, const char *dev_name,
-					void *data)
+					void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ncpfs/inode.c linux-2.6.16-rc4-getsb/fs/ncpfs/inode.c
--- linux-2.6.16-rc4/fs/ncpfs/inode.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ncpfs/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -957,7 +957,7 @@ out:
 }
 
 static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, ncp_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/nfs/inode.c linux-2.6.16-rc4-getsb/fs/nfs/inode.c
--- linux-2.6.16-rc4/fs/nfs/inode.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/nfs/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -1586,7 +1586,7 @@ static int nfs_compare_super(struct supe
 }
 
 static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data)
+	int flags, const char *dev_name, void *raw_data, struct dentry **_root)
 {
 	int error;
 	struct nfs_server *server = NULL;
@@ -1924,7 +1924,7 @@ nfs_copy_user_string(char *dst, struct n
 }
 
 static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data)
+	int flags, const char *dev_name, void *raw_data, struct dentry **_root)
 {
 	int error;
 	struct nfs_server *server;
diff -uNrp linux-2.6.16-rc4/fs/nfsd/nfsctl.c linux-2.6.16-rc4-getsb/fs/nfsd/nfsctl.c
--- linux-2.6.16-rc4/fs/nfsd/nfsctl.c	2006-01-04 12:39:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/nfsd/nfsctl.c	2006-02-22 17:08:48.000000000 +0000
@@ -495,7 +495,7 @@ static int nfsd_fill_super(struct super_
 }
 
 static struct super_block *nfsd_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, nfsd_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ntfs/super.c linux-2.6.16-rc4-getsb/fs/ntfs/super.c
--- linux-2.6.16-rc4/fs/ntfs/super.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ntfs/super.c	2006-02-22 17:08:48.000000000 +0000
@@ -3015,7 +3015,7 @@ kmem_cache_t *ntfs_index_ctx_cache;
 DECLARE_MUTEX(ntfs_lock);
 
 static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ocfs2/dlm/dlmfs.c linux-2.6.16-rc4-getsb/fs/ocfs2/dlm/dlmfs.c
--- linux-2.6.16-rc4/fs/ocfs2/dlm/dlmfs.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ocfs2/dlm/dlmfs.c	2006-02-22 17:16:16.000000000 +0000
@@ -575,7 +575,7 @@ static struct inode_operations dlmfs_fil
 };
 
 static struct super_block *dlmfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, dlmfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ocfs2/super.c linux-2.6.16-rc4-getsb/fs/ocfs2/super.c
--- linux-2.6.16-rc4/fs/ocfs2/super.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ocfs2/super.c	2006-02-22 17:16:22.000000000 +0000
@@ -675,7 +675,8 @@ read_super_error:
 static struct super_block *ocfs2_get_sb(struct file_system_type *fs_type,
 					int flags,
 					const char *dev_name,
-					void *data)
+					void *data,
+					struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/openpromfs/inode.c linux-2.6.16-rc4-getsb/fs/openpromfs/inode.c
--- linux-2.6.16-rc4/fs/openpromfs/inode.c	2006-01-04 12:39:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/openpromfs/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -1055,7 +1055,7 @@ out_no_root:
 }
 
 static struct super_block *openprom_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, openprom_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/pipe.c linux-2.6.16-rc4-getsb/fs/pipe.c
--- linux-2.6.16-rc4/fs/pipe.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/pipe.c	2006-02-22 17:08:48.000000000 +0000
@@ -806,7 +806,7 @@ no_files:
  */
 
 static struct super_block *pipefs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC);
 }
diff -uNrp linux-2.6.16-rc4/fs/proc/root.c linux-2.6.16-rc4-getsb/fs/proc/root.c
--- linux-2.6.16-rc4/fs/proc/root.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/proc/root.c	2006-02-22 17:08:48.000000000 +0000
@@ -27,7 +27,7 @@ struct proc_dir_entry *proc_sys_root;
 #endif
 
 static struct super_block *proc_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, proc_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/qnx4/inode.c linux-2.6.16-rc4-getsb/fs/qnx4/inode.c
--- linux-2.6.16-rc4/fs/qnx4/inode.c	2005-11-01 13:19:15.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/qnx4/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -561,7 +561,7 @@ static void destroy_inodecache(void)
 }
 
 static struct super_block *qnx4_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ramfs/inode.c linux-2.6.16-rc4-getsb/fs/ramfs/inode.c
--- linux-2.6.16-rc4/fs/ramfs/inode.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ramfs/inode.c	2006-02-22 17:14:16.000000000 +0000
@@ -183,13 +183,13 @@ static int ramfs_fill_super(struct super
 }
 
 struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, ramfs_fill_super);
 }
 
 static struct super_block *rootfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/relayfs/inode.c linux-2.6.16-rc4-getsb/fs/relayfs/inode.c
--- linux-2.6.16-rc4/fs/relayfs/inode.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/relayfs/inode.c	2006-02-22 17:15:40.000000000 +0000
@@ -539,7 +539,7 @@ static int relayfs_fill_super(struct sup
 
 static struct super_block * relayfs_get_sb(struct file_system_type *fs_type,
 					   int flags, const char *dev_name,
-					   void *data)
+					   void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, relayfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/romfs/inode.c linux-2.6.16-rc4-getsb/fs/romfs/inode.c
--- linux-2.6.16-rc4/fs/romfs/inode.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/romfs/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -607,7 +607,7 @@ static struct super_operations romfs_ops
 };
 
 static struct super_block *romfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/smbfs/inode.c linux-2.6.16-rc4-getsb/fs/smbfs/inode.c
--- linux-2.6.16-rc4/fs/smbfs/inode.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/smbfs/inode.c	2006-02-22 17:08:48.000000000 +0000
@@ -782,7 +782,7 @@ out:
 }
 
 static struct super_block *smb_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, smb_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/sysfs/mount.c linux-2.6.16-rc4-getsb/fs/sysfs/mount.c
--- linux-2.6.16-rc4/fs/sysfs/mount.c	2005-08-30 13:56:29.000000000 +0100
+++ linux-2.6.16-rc4-getsb/fs/sysfs/mount.c	2006-02-22 17:08:48.000000000 +0000
@@ -67,7 +67,7 @@ static int sysfs_fill_super(struct super
 }
 
 static struct super_block *sysfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, sysfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/sysv/super.c linux-2.6.16-rc4-getsb/fs/sysv/super.c
--- linux-2.6.16-rc4/fs/sysv/super.c	2004-10-19 10:42:09.000000000 +0100
+++ linux-2.6.16-rc4-getsb/fs/sysv/super.c	2006-02-22 17:08:48.000000000 +0000
@@ -507,13 +507,13 @@ failed:
 /* Every kernel module contains stuff like this. */
 
 static struct super_block *sysv_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super);
 }
 
 static struct super_block *v7_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/udf/super.c linux-2.6.16-rc4-getsb/fs/udf/super.c
--- linux-2.6.16-rc4/fs/udf/super.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/udf/super.c	2006-02-22 17:08:48.000000000 +0000
@@ -95,7 +95,7 @@ static int udf_statfs(struct super_block
 
 /* UDF filesystem type */
 static struct super_block *udf_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/ufs/super.c linux-2.6.16-rc4-getsb/fs/ufs/super.c
--- linux-2.6.16-rc4/fs/ufs/super.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/ufs/super.c	2006-02-22 17:08:48.000000000 +0000
@@ -1311,7 +1311,7 @@ out:
 #endif
 
 static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/vfat/namei.c linux-2.6.16-rc4-getsb/fs/vfat/namei.c
--- linux-2.6.16-rc4/fs/vfat/namei.c	2006-01-04 12:39:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/vfat/namei.c	2006-02-22 17:14:44.000000000 +0000
@@ -1043,7 +1043,7 @@ static int vfat_fill_super(struct super_
 
 static struct super_block *vfat_get_sb(struct file_system_type *fs_type,
 				       int flags, const char *dev_name,
-				       void *data)
+				       void *data, struct dentry **_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/fs/xfs/linux-2.6/xfs_super.c linux-2.6.16-rc4-getsb/fs/xfs/linux-2.6/xfs_super.c
--- linux-2.6.16-rc4/fs/xfs/linux-2.6/xfs_super.c	2006-02-22 17:00:38.000000000 +0000
+++ linux-2.6.16-rc4-getsb/fs/xfs/linux-2.6/xfs_super.c	2006-02-22 17:12:42.000000000 +0000
@@ -914,7 +914,8 @@ linvfs_get_sb(
 	struct file_system_type	*fs_type,
 	int			flags,
 	const char		*dev_name,
-	void			*data)
+	void			*data,
+	struct dentry		**_root)
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, linvfs_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/include/linux/ramfs.h linux-2.6.16-rc4-getsb/include/linux/ramfs.h
--- linux-2.6.16-rc4/include/linux/ramfs.h	2006-02-22 17:00:42.000000000 +0000
+++ linux-2.6.16-rc4-getsb/include/linux/ramfs.h	2006-02-22 17:10:37.000000000 +0000
@@ -3,7 +3,7 @@
 
 struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev);
 struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
-	 int flags, const char *dev_name, void *data);
+	 int flags, const char *dev_name, void *data, struct dentry **_root);
 
 #ifndef CONFIG_MMU
 extern unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
diff -uNrp linux-2.6.16-rc4/ipc/mqueue.c linux-2.6.16-rc4-getsb/ipc/mqueue.c
--- linux-2.6.16-rc4/ipc/mqueue.c	2006-02-22 17:00:43.000000000 +0000
+++ linux-2.6.16-rc4-getsb/ipc/mqueue.c	2006-02-22 17:08:49.000000000 +0000
@@ -203,7 +203,7 @@ static int mqueue_fill_super(struct supe
 
 static struct super_block *mqueue_get_sb(struct file_system_type *fs_type,
 					 int flags, const char *dev_name,
-					 void *data)
+					 void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, mqueue_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/kernel/cpuset.c linux-2.6.16-rc4-getsb/kernel/cpuset.c
--- linux-2.6.16-rc4/kernel/cpuset.c	2006-02-22 17:00:43.000000000 +0000
+++ linux-2.6.16-rc4-getsb/kernel/cpuset.c	2006-02-22 17:16:44.000000000 +0000
@@ -386,7 +386,7 @@ static int cpuset_fill_super(struct supe
 
 static struct super_block *cpuset_get_sb(struct file_system_type *fs_type,
 					int flags, const char *unused_dev_name,
-					void *data)
+					void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, cpuset_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/kernel/futex.c linux-2.6.16-rc4-getsb/kernel/futex.c
--- linux-2.6.16-rc4/kernel/futex.c	2006-02-22 17:00:43.000000000 +0000
+++ linux-2.6.16-rc4-getsb/kernel/futex.c	2006-02-22 17:08:49.000000000 +0000
@@ -886,7 +886,7 @@ asmlinkage long sys_futex(u32 __user *ua
 
 static struct super_block *
 futexfs_get_sb(struct file_system_type *fs_type,
-	       int flags, const char *dev_name, void *data)
+	       int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA);
 }
diff -uNrp linux-2.6.16-rc4/mm/shmem.c linux-2.6.16-rc4-getsb/mm/shmem.c
--- linux-2.6.16-rc4/mm/shmem.c	2006-02-22 17:00:44.000000000 +0000
+++ linux-2.6.16-rc4-getsb/mm/shmem.c	2006-02-22 17:08:49.000000000 +0000
@@ -2171,7 +2171,7 @@ static struct vm_operations_struct shmem
 
 
 static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_nodev(fs_type, flags, data, shmem_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/net/socket.c linux-2.6.16-rc4-getsb/net/socket.c
--- linux-2.6.16-rc4/net/socket.c	2006-02-22 17:00:46.000000000 +0000
+++ linux-2.6.16-rc4-getsb/net/socket.c	2006-02-22 17:08:49.000000000 +0000
@@ -328,7 +328,7 @@ static struct super_operations sockfs_op
 };
 
 static struct super_block *sockfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+	int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC);
 }
diff -uNrp linux-2.6.16-rc4/net/sunrpc/rpc_pipe.c linux-2.6.16-rc4-getsb/net/sunrpc/rpc_pipe.c
--- linux-2.6.16-rc4/net/sunrpc/rpc_pipe.c	2006-02-22 17:00:46.000000000 +0000
+++ linux-2.6.16-rc4-getsb/net/sunrpc/rpc_pipe.c	2006-02-22 17:08:49.000000000 +0000
@@ -814,7 +814,7 @@ out:
 
 static struct super_block *
 rpc_get_sb(struct file_system_type *fs_type,
-		int flags, const char *dev_name, void *data)
+		int flags, const char *dev_name, void *data, struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, rpc_fill_super);
 }
diff -uNrp linux-2.6.16-rc4/security/selinux/selinuxfs.c linux-2.6.16-rc4-getsb/security/selinux/selinuxfs.c
--- linux-2.6.16-rc4/security/selinux/selinuxfs.c	2006-02-22 17:00:46.000000000 +0000
+++ linux-2.6.16-rc4-getsb/security/selinux/selinuxfs.c	2006-02-22 17:08:49.000000000 +0000
@@ -1281,7 +1281,8 @@ out:
 }
 
 static struct super_block *sel_get_sb(struct file_system_type *fs_type,
-				      int flags, const char *dev_name, void *data)
+				      int flags, const char *dev_name, void *data,
+				      struct dentry **_root)
 {
 	return get_sb_single(fs_type, flags, data, sel_fill_super);
 }

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/5] NFS: Add dentry materialisation op
  2006-02-22 20:21 [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount David Howells
                   ` (2 preceding siblings ...)
  2006-02-22 20:21 ` [PATCH 3/5] NFS: Abstract out namespace initialisation David Howells
@ 2006-02-22 20:21 ` David Howells
  3 siblings, 0 replies; 5+ messages in thread
From: David Howells @ 2006-02-22 20:21 UTC (permalink / raw)
  To: torvalds, akpm, steved, trond.myklebust, aviro
  Cc: linux-kernel, linux-cachefs, nfsv4, linux-fsdevel

The attached patch adds a new directory cache management function that prepares
a disconnected anonymous function to be connected into the dentry tree. The
anonymous dentry is transferred the name and parentage from another dentry.

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 materialise-dentry-2616rc4.diff
 fs/dcache.c            |   18 ++++++++++++++++++
 include/linux/dcache.h |    1 +
 2 files changed, 19 insertions(+)

diff -uNrp linux-2.6.16-rc4-getsb/include/linux/dcache.h linux-2.6.16-rc4-getsb-nfs/include/linux/dcache.h
--- linux-2.6.16-rc4-getsb/include/linux/dcache.h	2006-02-22 17:00:41.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/include/linux/dcache.h	2006-02-22 17:34:57.000000000 +0000
@@ -208,6 +208,7 @@ static inline int dname_external(struct 
 extern void d_instantiate(struct dentry *, struct inode *);
 extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
 extern void d_delete(struct dentry *);
+extern void d_materialise_dentry(struct dentry *, struct dentry *);
 
 /* allocate/de-allocate */
 extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
diff -uNrp linux-2.6.16-rc4-getsb/fs/dcache.c linux-2.6.16-rc4-getsb-nfs/fs/dcache.c
--- linux-2.6.16-rc4-getsb/fs/dcache.c	2006-02-22 17:00:36.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/dcache.c	2006-02-22 17:34:57.000000000 +0000
@@ -1345,6 +1345,23 @@ already_unhashed:
 }
 
 /**
+ * d_materialise_dentry - connect a disconnected dentry into the tree
+ * @dentry: dentry to replace
+ * @anon: dentry to place into the tree
+ *
+ * Prepare an anonymous dentry for life in the superblock's dentry tree as a
+ * named dentry in place of the dentry to be replaced.
+ */
+void d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
+{
+	switch_names(dentry, anon);
+	do_switch(dentry->d_name.len, anon->d_name.len);
+	do_switch(dentry->d_name.hash, anon->d_name.hash);
+	do_switch(dentry->d_parent, anon->d_parent);
+	anon->d_flags &= ~DCACHE_DISCONNECTED;
+}
+
+/**
  * d_path - return the path of a dentry
  * @dentry: dentry to report
  * @vfsmnt: vfsmnt to which the dentry belongs
@@ -1755,6 +1772,7 @@ EXPORT_SYMBOL(d_instantiate);
 EXPORT_SYMBOL(d_invalidate);
 EXPORT_SYMBOL(d_lookup);
 EXPORT_SYMBOL(d_move);
+EXPORT_SYMBOL_GPL(d_materialise_dentry);
 EXPORT_SYMBOL(d_path);
 EXPORT_SYMBOL(d_prune_aliases);
 EXPORT_SYMBOL(d_rehash);

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/5] NFS: Abstract out namespace initialisation
  2006-02-22 20:21 [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount David Howells
  2006-02-22 20:21 ` [PATCH 2/5] NFS: Apply mount root dentry override to filesystems David Howells
  2006-02-22 20:21 ` [PATCH 5/5] NFS: Unify NFS superblocks per-protocol per-server David Howells
@ 2006-02-22 20:21 ` David Howells
  2006-02-22 20:21 ` [PATCH 4/5] NFS: Add dentry materialisation op David Howells
  3 siblings, 0 replies; 5+ messages in thread
From: David Howells @ 2006-02-22 20:21 UTC (permalink / raw)
  To: torvalds, akpm, steved, trond.myklebust, aviro
  Cc: linux-kernel, linux-cachefs, nfsv4, linux-fsdevel

The attached patch abstracts out the namespace initialisation so that temporary
namespaces can be set up elsewhere.

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 init-namespace-2616rc4.diff
 fs/namespace.c            |    8 +-------
 include/linux/namespace.h |   15 +++++++++++++++
 2 files changed, 16 insertions(+), 7 deletions(-)

diff -uNrp linux-2.6.16-rc4-getsb/include/linux/namespace.h linux-2.6.16-rc4-getsb-nfs/include/linux/namespace.h
--- linux-2.6.16-rc4-getsb/include/linux/namespace.h	2006-02-22 17:00:42.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/include/linux/namespace.h	2006-02-22 17:37:04.000000000 +0000
@@ -17,6 +17,21 @@ extern int copy_namespace(int, struct ta
 extern void __put_namespace(struct namespace *namespace);
 extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *);
 
+static inline void init_namespace(struct namespace *namespace,
+				  struct vfsmount *mnt)
+{
+	atomic_set(&namespace->count, 1);
+	INIT_LIST_HEAD(&namespace->list);
+	init_waitqueue_head(&namespace->poll);
+	namespace->event = 0;
+	namespace->root = mnt;
+
+	if (mnt) {
+		list_add(&mnt->mnt_list, &namespace->list);
+		mnt->mnt_namespace = namespace;
+	}
+}
+
 static inline void put_namespace(struct namespace *namespace)
 {
 	if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock))
diff -uNrp linux-2.6.16-rc4-getsb/fs/namespace.c linux-2.6.16-rc4-getsb-nfs/fs/namespace.c
--- linux-2.6.16-rc4-getsb/fs/namespace.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/namespace.c	2006-02-22 18:21:52.000000000 +0000
@@ -1679,13 +1679,7 @@ static void __init init_mount_tree(void)
 	namespace = kmalloc(sizeof(*namespace), GFP_KERNEL);
 	if (!namespace)
 		panic("Can't allocate initial namespace");
-	atomic_set(&namespace->count, 1);
-	INIT_LIST_HEAD(&namespace->list);
-	init_waitqueue_head(&namespace->poll);
-	namespace->event = 0;
-	list_add(&mnt->mnt_list, &namespace->list);
-	namespace->root = mnt;
-	mnt->mnt_namespace = namespace;
+	init_namespace(namespace, mnt);
 
 	init_task.namespace = namespace;
 	read_lock(&tasklist_lock);

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 5/5] NFS: Unify NFS superblocks per-protocol per-server
  2006-02-22 20:21 [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount David Howells
  2006-02-22 20:21 ` [PATCH 2/5] NFS: Apply mount root dentry override to filesystems David Howells
@ 2006-02-22 20:21 ` David Howells
  2006-02-22 20:21 ` [PATCH 3/5] NFS: Abstract out namespace initialisation David Howells
  2006-02-22 20:21 ` [PATCH 4/5] NFS: Add dentry materialisation op David Howells
  3 siblings, 0 replies; 5+ messages in thread
From: David Howells @ 2006-02-22 20:21 UTC (permalink / raw)
  To: torvalds, akpm, steved, trond.myklebust, aviro
  Cc: linux-kernel, linux-cachefs, nfsv4, linux-fsdevel

The attached patch makes NFS share superblocks between mounts from the same
server over the same protocol.

It does this by creating each superblock with a false root and returning the
real root dentry through the new argument added to get_sb() in patch 1/5. The
root dentry returned starts off as an anonymous dentry if we don't already have
the dentry for its inode, otherwise it simply returns the dentry we already
have.

We may thus end up with several trees of dentries in the superblock, and if at
some later point one of anonymous tree roots is discovered by normal filesystem
activity to be located in another tree within the superblock, the anonymous
root is named and materialises attached to the second tree at the appropriate
point.

Why modify get_sb() in this way? Why not pass an extra argument to the mount()
syscall to indicate the subpath and then pathwalk from the server root to the
desired directory? You can't guarantee this will work for two reasons:

 (1) The root and intervening nodes may not be accessible to the client.

     With NFS2 and NFS3, for instance, mountd is called on the server to get
     the filehandle for the tip of a path. mountd won't give us handles for
     anything we don't have permission to access, and so we can't set up NFS
     inodes for such nodes, and so can't easily set up dentries (we'd have to
     have ghost inodes or something).

     With this patch we don't actually create dentries until we get handles
     from the server that we can use to set up their inodes, and we don't
     actually bind them into the tree until we know for sure where they go.

 (2) Inaccessible symbolic links.

     If we're asked to mount two exports from the server, eg:

	mount warthog:/warthog/aaa/xxx /mmm
	mount warthog:/warthog/bbb/yyy /nnn

     We may not be able to access anything nearer the root than xxx and yyy,
     but we may find out later that /mmm/www/yyy, say, is actually the same
     directory as the one mounted on /nnn. What we might then find out, for
     example, is that /warthog/bbb was actually a symbolic link to
     /warthog/aaa/xxx/www, but we can't actually determine that by talking to
     the server until /warthog is made available by NFS.

     This would lead to having constructed an errneous dentry tree which we
     can't easily fix. We can end up with a dentry marked as a directory when
     it should actually be a symlink, or we could end up with an apparently
     hardlinked directory.

     With this patch we need not make assumptions about the type of a dentry
     for which we can't retrieve information, nor need we assume we know its
     place in the grand scheme of things until we actually see that place.


This patch reduces the possibility of aliasing in the inode and page caches for
inodes that may be accessed by more than one NFS export. It also reduces the
number of superblocks required for NFS where there are many NFS exports being
used from a server (home directory server + autofs for example).

This in turn makes it simpler to do local caching of network filesystems, as it
can then be guaranteed that there won't be links from multiple inodes in
separate superblocks to the same cache file.

Obviously, cache aliasing between different levels of NFS protocol is still a
problem, but at least that gives us another key to use when indexing the cache.


The patch also exports some functions required from the core kernel.

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 nfs-unify-sb-2616rc4.diff
 fs/namei.c                |    2 
 fs/namespace.c            |    4 
 fs/nfs/Makefile           |    4 
 fs/nfs/dir.c              |   27 +++++
 fs/nfs/getroot.c          |  220 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/inode.c            |  198 +++++++++++++++++++++--------------------
 fs/nfs/internal.h         |   30 ++++++
 fs/nfs/nfs3proc.c         |    2 
 fs/nfs/nfs4proc.c         |   61 +-----------
 fs/nfs/nfs4state.c        |    2 
 include/linux/nfs_fs_sb.h |    2 
 11 files changed, 393 insertions(+), 159 deletions(-)

diff -uNrp linux-2.6.16-rc4-getsb/include/linux/nfs_fs_sb.h linux-2.6.16-rc4-getsb-nfs/include/linux/nfs_fs_sb.h
--- linux-2.6.16-rc4-getsb/include/linux/nfs_fs_sb.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.16-rc4-getsb-nfs/include/linux/nfs_fs_sb.h	2006-02-22 17:34:57.000000000 +0000
@@ -28,14 +28,12 @@ struct nfs_server {
 	unsigned int		acdirmax;
 	unsigned int		namelen;
 	char *			hostname;	/* remote hostname */
-	struct nfs_fh		fh;
 	struct sockaddr_in	addr;
 #ifdef CONFIG_NFS_V4
 	/* Our own IP address, as a null-terminated string.
 	 * This is used to generate the clientid, and the callback address.
 	 */
 	char			ip_addr[16];
-	char *			mnt_path;
 	struct nfs4_client *	nfs4_state;	/* all NFSv4 state starts here */
 	struct list_head	nfs4_siblings;	/* List of other nfs_server structs
 						 * that share the same clientid
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/Makefile linux-2.6.16-rc4-getsb-nfs/fs/nfs/Makefile
--- linux-2.6.16-rc4-getsb/fs/nfs/Makefile	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/Makefile	2006-02-22 17:34:57.000000000 +0000
@@ -4,8 +4,8 @@
 
 obj-$(CONFIG_NFS_FS) += nfs.o
 
-nfs-y 			:= dir.o file.o inode.o nfs2xdr.o pagelist.o \
-			   proc.o read.o symlink.o unlink.o write.o
+nfs-y 			:= dir.o file.o getroot.o inode.o nfs2xdr.o \
+			   pagelist.o proc.o read.o symlink.o unlink.o write.o
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o mount_clnt.o      
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/internal.h linux-2.6.16-rc4-getsb-nfs/fs/nfs/internal.h
--- linux-2.6.16-rc4-getsb/fs/nfs/internal.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/internal.h	2006-02-22 17:34:57.000000000 +0000
@@ -0,0 +1,30 @@
+/* internal.h: internal NFS definitions
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+/*
+ * getroot.c
+ */
+typedef void (*nfs_set_params_func)(struct super_block *sb,
+				    struct nfs_fh *mntfh,
+				    struct nfs_fsinfo *fsinfo);
+
+extern struct dentry *nfs_get_root(struct super_block *sb,
+				   struct nfs_fh *mntfh,
+				   nfs_set_params_func set_params);
+
+#ifdef CONFIG_NFS_V4
+
+extern struct dentry *nfs4_get_root(struct super_block *sb,
+				    const char *mntpath,
+				    nfs_set_params_func set_params);
+
+#endif
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/dir.c linux-2.6.16-rc4-getsb-nfs/fs/nfs/dir.c
--- linux-2.6.16-rc4-getsb/fs/nfs/dir.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/dir.c	2006-02-22 17:34:57.000000000 +0000
@@ -836,11 +836,12 @@ int nfs_is_exclusive_create(struct inode
 
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
-	struct dentry *res;
+	struct dentry *res, *anon;
 	struct inode *inode = NULL;
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
+ 	int found_alias = 0;
 
 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -869,6 +870,30 @@ static struct dentry *nfs_lookup(struct 
 	inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
 	if (!inode)
 		goto out_unlock;
+
+	/* Search for directory aliases arising from multiple mounts from one server */
+	if (S_ISDIR(inode->i_mode) && (anon = d_find_alias(inode))) {
+		spin_lock(&anon->d_lock);
+		/* Is this a mountpoint that we could splice into our tree? */
+		if (IS_ROOT(anon)) {
+			/* Yes! Convert into an ordinary dentry */
+			d_materialise_dentry(dentry, anon);
+			found_alias = 1;
+		} else if (anon->d_name.len == dentry->d_name.len &&
+			   !memcmp(anon->d_name.name, dentry->d_name.name, dentry->d_name.len) &&
+			   dentry->d_parent == anon->d_parent)
+			found_alias = 1;
+		spin_unlock(&anon->d_lock);
+		if (found_alias) {
+			d_drop(anon);
+			iput(inode);
+			d_rehash(anon);
+			return anon;
+		}
+		/* Doh! Server appears to be aliasing directories */
+		dput(anon);
+	}
+
 no_entry:
 	res = d_add_unique(dentry, inode);
 	if (res != NULL)
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/getroot.c linux-2.6.16-rc4-getsb-nfs/fs/nfs/getroot.c
--- linux-2.6.16-rc4-getsb/fs/nfs/getroot.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/getroot.c	2006-02-22 18:47:00.000000000 +0000
@@ -0,0 +1,220 @@
+/* getroot.c: get the root dentry for an NFS mount
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+#include <linux/lockd/bind.h>
+#include <linux/smp_lock.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/nfs_idmap.h>
+#include <linux/vfs.h>
+#include <linux/namei.h>
+#include <linux/namespace.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "nfs4_fs.h"
+#include "delegation.h"
+#include "internal.h"
+
+#define NFSDBG_FACILITY		NFSDBG_VFS
+#define NFS_PARANOIA 1
+
+/*
+ * get an NFS2/NFS3 root dentry from the root filehandle
+ */
+struct dentry *nfs_get_root(struct super_block *sb,
+			    struct nfs_fh *mntfh,
+			    nfs_set_params_func set_params)
+{
+	struct nfs_server *server = NFS_SB(sb);
+	struct nfs_fsinfo fsinfo;
+	struct nfs_fattr fattr;
+	struct dentry *mntroot;
+	struct inode *inode;
+	int error;
+
+	/* create a dummy root dentry with dummy inode for this superblock */
+	if (!sb->s_root) {
+		struct nfs_fh dummyfh;
+		struct dentry *root;
+		struct inode *iroot;
+
+		memset(&dummyfh, 0, sizeof(dummyfh));
+		memset(&fattr, 0, sizeof(fattr));
+		nfs_fattr_init(&fattr);
+		fattr.valid = NFS_ATTR_FATTR;
+		fattr.type = NFDIR;
+		fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
+		fattr.nlink = 2;
+		iroot = nfs_fhget(sb, &dummyfh, &fattr);
+		if (!iroot)
+			return ERR_PTR(-ENOMEM);
+
+		root = d_alloc_root(iroot);
+		if (!root) {
+			iput(iroot);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		sb->s_root = root;
+	}
+
+	/* get the actual root for this mount */
+	fsinfo.fattr = &fattr;
+
+	error = server->rpc_ops->getroot(server, mntfh, &fsinfo);
+	if (error < 0) {
+		dprintk("nfs_get_root: getattr error = %d\n", -error);
+		return ERR_PTR(error);
+	}
+
+	inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
+	if (!inode) {
+		dprintk("nfs_get_root: get root inode failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* root dentries start off anonymous and get spliced in later if the
+	 * dentry tree reaches them */
+	mntroot = d_alloc_anon(inode);
+	if (!mntroot) {
+		iput(inode);
+		dprintk("nfs_get_root: get root dentry failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (!mntroot->d_op)
+		mntroot->d_op = server->rpc_ops->dentry_ops;
+
+	/* make use of the fsinfo if requested */
+	if (set_params)
+		set_params(sb, mntfh, &fsinfo);
+
+	return mntroot;
+}
+
+#ifdef CONFIG_NFS_V4
+
+/*
+ * walk the path to the specified mountpoint on an NFS4 server
+ */
+struct dentry *nfs4_get_root(struct super_block *sb,
+			     const char *mntpath,
+			     nfs_set_params_func set_params)
+{
+	struct namespace *namespace = NULL;
+	struct nameidata nd;
+	struct vfsmount *mnt = NULL;
+	struct dentry *mntroot;
+	struct inode *inode;
+	int ret;
+	int saved_link_count = current->link_count;
+	int saved_total_link_count = current->total_link_count;
+
+	/* get the dentry for the "/" directory on the server */
+	if (!sb->s_root) {
+		struct nfs_server *server = sb->s_fs_info;
+		struct nfs_fsinfo fsinfo;
+		struct nfs_fattr fattr;
+		struct nfs_fh rootfh;
+
+		/* need the filehandle first */
+		nfs_fattr_init(&fattr);
+		fsinfo.fattr = &fattr;
+
+		ret = server->rpc_ops->getroot(server, &rootfh, &fsinfo);
+		if (ret < 0) {
+			dprintk("nfs4_get_root: getroot error = %d\n", -ret);
+			return ERR_PTR(ret);
+		}
+		
+		inode = nfs_fhget(sb, &rootfh, &fattr);
+		if (!inode) {
+			dprintk("nfs4_get_root: get root inode failed\n");
+			return ERR_PTR(-ENOMEM);
+		}
+
+		sb->s_root = d_alloc_root(inode);
+		if (!sb->s_root) {
+			iput(inode);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		/* make use of the fsinfo if requested */
+		if (set_params)
+			set_params(sb, &rootfh, &fsinfo);
+	}
+
+	/* create a mount to represent the NFS server's FH tree */
+	mnt = alloc_vfsmnt(NULL);
+	if (!mnt)
+		return ERR_PTR(-ENOMEM);
+
+	mnt->mnt_sb = sb;
+	mnt->mnt_root = sb->s_root;
+	mnt->mnt_mountpoint = sb->s_root;
+	mnt->mnt_parent = mnt;
+
+	/* create a namespace through which to walk */
+	namespace = kmalloc(sizeof(*namespace), GFP_KERNEL);
+	if (!namespace) {
+		kfree(mnt);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init_namespace(namespace, mnt);
+
+	/* set up the walk we're going to take */
+	nd.last_type = LAST_ROOT;
+	nd.flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_ACCESS;
+	nd.depth = 0;
+
+	nd.mnt = mntget(namespace->root);
+	nd.dentry = dget(nd.mnt->mnt_root);
+
+	/* walk the walk */
+	current->total_link_count = 0;
+	ret = link_path_walk(mntpath, &nd);
+	if (ret < 0) {
+		mntroot = ERR_PTR(ret);
+		goto error;
+	}
+
+	/* we've found the directory we're going to mount */
+	mntput(nd.mnt);
+	mntroot = nd.dentry;
+
+error:
+	free_vfsmnt(namespace->root);
+	kfree(namespace);
+	current->link_count = saved_link_count;
+	current->total_link_count = saved_total_link_count;
+	return mntroot;
+}
+
+#endif /* CONFIG_NFS_V4 */
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/inode.c linux-2.6.16-rc4-getsb-nfs/fs/nfs/inode.c
--- linux-2.6.16-rc4-getsb/fs/nfs/inode.c	2006-02-22 17:08:48.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/inode.c	2006-02-22 18:48:30.000000000 +0000
@@ -42,6 +42,7 @@
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "delegation.h"
+#include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
@@ -231,79 +232,48 @@ nfs_block_size(unsigned long bsize, unsi
 }
 
 /*
- * Obtain the root inode of the file system.
+ * Initialise the common bits of the superblock
  */
-static struct inode *
-nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
+static inline void nfs_initialise_sb(struct super_block *sb)
 {
-	struct nfs_server	*server = NFS_SB(sb);
-	struct inode *rooti;
-	int			error;
+	sb->s_magic = NFS_SUPER_MAGIC;
 
-	error = server->rpc_ops->getroot(server, rootfh, fsinfo);
-	if (error < 0) {
-		dprintk("nfs_get_root: getattr error = %d\n", -error);
-		return ERR_PTR(error);
-	}
-
-	rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
-	if (!rooti)
-		return ERR_PTR(-ENOMEM);
-	return rooti;
+	/* We probably want something more informative here */
+	snprintf(sb->s_id, sizeof(sb->s_id),
+		 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
 }
 
 /*
- * Do NFS version-independent mount processing, and sanity checking
+ * Set the communications parameters
  */
-static int
-nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
+static void nfs_set_comms_params(struct super_block *sb,
+				 struct nfs_fh *mntfh,
+				 struct nfs_fsinfo *fsinfo)
 {
-	struct nfs_server	*server;
-	struct inode		*root_inode;
-	struct nfs_fattr	fattr;
-	struct nfs_fsinfo	fsinfo = {
-					.fattr = &fattr,
-				};
-	struct nfs_pathconf pathinfo = {
-			.fattr = &fattr,
-	};
-	int no_root_error = 0;
+	struct nfs_pathconf pathinfo;
+	struct nfs_server *server;
 	unsigned long max_rpc_payload;
 
-	/* We probably want something more informative here */
-	snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
 	server = NFS_SB(sb);
 
-	sb->s_magic      = NFS_SUPER_MAGIC;
+	/* Get some general file system info */
+	if (server->namelen == 0) {
+		pathinfo.fattr = fsinfo->fattr; /* reuse the fsinfo's attrs */
 
-	root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
-	/* Did getting the root inode fail? */
-	if (IS_ERR(root_inode)) {
-		no_root_error = PTR_ERR(root_inode);
-		goto out_no_root;
-	}
-	sb->s_root = d_alloc_root(root_inode);
-	if (!sb->s_root) {
-		no_root_error = -ENOMEM;
-		goto out_no_root;
+		if (server->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
+			server->namelen = pathinfo.max_namelen;
 	}
-	sb->s_root->d_op = server->rpc_ops->dentry_ops;
 
-	/* Get some general file system info */
-	if (server->namelen == 0 &&
-	    server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
-		server->namelen = pathinfo.max_namelen;
 	/* Work out a lot of parameters */
 	if (server->rsize == 0)
-		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+		server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
 	if (server->wsize == 0)
-		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+		server->wsize = nfs_block_size(fsinfo->wtpref, NULL);
 
-	if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
-		server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
-	if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
-		server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
+	if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
+		server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
+	if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
+		server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
 
 	max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
 	if (server->rsize > max_rpc_payload)
@@ -321,9 +291,9 @@ nfs_sb_init(struct super_block *sb, rpc_
 	if (sb->s_blocksize == 0)
 		sb->s_blocksize = nfs_block_bits(server->wsize,
 							 &sb->s_blocksize_bits);
-	server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
+	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
-	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
 	if (server->dtsize > PAGE_CACHE_SIZE)
 		server->dtsize = PAGE_CACHE_SIZE;
 	if (server->dtsize > server->rsize)
@@ -336,7 +306,7 @@ nfs_sb_init(struct super_block *sb, rpc_
 	}
 	server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
 
-	sb->s_maxbytes = fsinfo.maxfilesize;
+	sb->s_maxbytes = fsinfo->maxfilesize;
 	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
 		sb->s_maxbytes = MAX_LFS_FILESIZE; 
 
@@ -345,13 +315,6 @@ nfs_sb_init(struct super_block *sb, rpc_
 
 	/* We're airborne Set socket buffersize */
 	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
-	return 0;
-	/* Yargs. It didn't work out. */
-out_no_root:
-	dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
-	if (!IS_ERR(root_inode))
-		iput(root_inode);
-	return no_root_error;
 }
 
 static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
@@ -520,9 +483,13 @@ nfs_fill_super(struct super_block *sb, s
 	}
 
 	sb->s_op = &nfs_sops;
-	return nfs_sb_init(sb, authflavor);
+	nfs_initialise_sb(sb);
+	return 0;
 }
 
+/*
+ * return NFS filesystem statistics to userspace
+ */
 static int
 nfs_statfs(struct super_block *sb, struct kstatfs *buf)
 {
@@ -1565,6 +1532,11 @@ static int nfs_update_inode(struct inode
 
 /*
  * File system information
+ * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a
+ *   particular server are held in the same superblock
+ * - NFS superblocks can have several effective roots to the dentry tree
+ * - directory type roots are spliced into the tree when a path from one root reaches the root
+ *   of another (see nfs_lookup())
  */
 
 static int nfs_set_super(struct super_block *s, void *data)
@@ -1582,7 +1554,7 @@ static int nfs_compare_super(struct supe
 		return 0;
 	if (old->addr.sin_port != server->addr.sin_port)
 		return 0;
-	return !nfs_compare_fh(&old->fh, &server->fh);
+	return 1;
 }
 
 static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
@@ -1591,8 +1563,9 @@ static struct super_block *nfs_get_sb(st
 	int error;
 	struct nfs_server *server = NULL;
 	struct super_block *s;
-	struct nfs_fh *root;
+	struct nfs_fh mntfh;
 	struct nfs_mount_data *data = raw_data;
+	struct dentry *mntroot;
 
 	s = ERR_PTR(-EINVAL);
 	if (data == NULL) {
@@ -1640,22 +1613,28 @@ static struct super_block *nfs_get_sb(st
 	server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
 	if (!server)
 		goto out_err;
+
 	memset(server, 0, sizeof(struct nfs_server));
+
 	/* Zero out the NFS state stuff */
 	init_nfsv4_state(server);
 	server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
 
-	root = &server->fh;
 	if (data->flags & NFS_MOUNT_VER3)
-		root->size = data->root.size;
+		mntfh.size = data->root.size;
 	else
-		root->size = NFS2_FHSIZE;
+		mntfh.size = NFS2_FHSIZE;
+
 	s = ERR_PTR(-EINVAL);
-	if (root->size > sizeof(root->data)) {
+	if (mntfh.size > sizeof(mntfh.data)) {
 		dprintk("%s: invalid root filehandle\n", __FUNCTION__);
 		goto out_err;
 	}
-	memcpy(root->data, data->root.data, root->size);
+
+	memcpy(mntfh.data, data->root.data, mntfh.size);
+	if (mntfh.size < sizeof(mntfh.data))
+		memset(mntfh.data + mntfh.size, 0,
+		       sizeof(mntfh.data) - mntfh.size);
 
 	/* We now require that the mount process passes the remote address */
 	memcpy(&server->addr, &data->addr, sizeof(server->addr));
@@ -1673,18 +1652,27 @@ static struct super_block *nfs_get_sb(st
 		goto out_err;
 	}
 
+	/* Get a superblock - note that we may end up sharing one that already exists */
 	s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
-	if (IS_ERR(s) || s->s_root)
+	if (IS_ERR(s))
 		goto out_rpciod_down;
 
-	s->s_flags = flags;
+	if (!s->s_root) {
+		/* initial superblock/root creation */
+		s->s_flags = flags;
 
-	error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
-	if (error) {
-		up_write(&s->s_umount);
-		deactivate_super(s);
-		return ERR_PTR(error);
+		error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+		if (error)
+			goto error_splat_super;
 	}
+
+	mntroot = nfs_get_root(s, &mntfh, s->s_root ? NULL : nfs_set_comms_params);
+	if (IS_ERR(mntroot)) {
+		error = PTR_ERR(mntroot);
+		goto error_splat_super;
+	}
+
+	*_root = mntroot;
 	s->s_flags |= MS_ACTIVE;
 	return s;
 out_rpciod_down:
@@ -1692,6 +1680,11 @@ out_rpciod_down:
 out_err:
 	kfree(server);
 	return s;
+
+error_splat_super:
+	up_write(&s->s_umount);
+	deactivate_super(s);
+	return ERR_PTR(error);
 }
 
 static void nfs_kill_super(struct super_block *s)
@@ -1771,7 +1764,8 @@ static void nfs4_clear_inode(struct inod
 }
 
 
-static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
+static int nfs4_fill_super(struct super_block *sb,
+			   struct nfs4_mount_data *data, int silent)
 {
 	struct nfs_server *server;
 	struct nfs4_client *clp = NULL;
@@ -1880,9 +1874,7 @@ static int nfs4_fill_super(struct super_
 	sb->s_time_gran = 1;
 
 	sb->s_op = &nfs4_sops;
-	err = nfs_sb_init(sb, authflavour);
-	if (err == 0)
-		return 0;
+	nfs_initialise_sb(sb);
 out_fail:
 	if (clp)
 		nfs4_put_client(clp);
@@ -1896,8 +1888,6 @@ static int nfs4_compare_super(struct sup
 
 	if (strcmp(server->hostname, old->hostname) != 0)
 		return 0;
-	if (strcmp(server->mnt_path, old->mnt_path) != 0)
-		return 0;
 	return 1;
 }
 
@@ -1930,6 +1920,8 @@ static struct super_block *nfs4_get_sb(s
 	struct nfs_server *server;
 	struct super_block *s;
 	struct nfs4_mount_data *data = raw_data;
+	struct dentry *mntroot;
+	char *mntpath = NULL;
 	void *p;
 
 	if (data == NULL) {
@@ -1957,7 +1949,7 @@ static struct super_block *nfs4_get_sb(s
 	p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
 	if (IS_ERR(p))
 		goto out_err;
-	server->mnt_path = p;
+	mntpath = p;
 
 	p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
 			sizeof(server->ip_addr) - 1);
@@ -1989,28 +1981,43 @@ static struct super_block *nfs4_get_sb(s
 		goto out_free;
 	}
 
+	/* Get a superblock - note that we may end up sharing one that already exists */
 	s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
-
-	if (IS_ERR(s) || s->s_root)
+	if (IS_ERR(s))
 		goto out_free;
 
-	s->s_flags = flags;
+	if (!s->s_root) {
+		/* initial superblock/root creation */
+		s->s_flags = flags;
+
+		error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+		if (error)
+			goto error_splat_super;
+	}
 
-	error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
-	if (error) {
-		up_write(&s->s_umount);
-		deactivate_super(s);
-		return ERR_PTR(error);
+	mntroot = nfs4_get_root(s, mntpath, nfs_set_comms_params);
+	if (IS_ERR(mntroot)) {
+		error = PTR_ERR(mntroot);
+		goto error_splat_super;
 	}
+
+	*_root = mntroot;
+
+	kfree(mntpath);
 	s->s_flags |= MS_ACTIVE;
 	return s;
 out_err:
 	s = (struct super_block *)p;
 out_free:
-	kfree(server->mnt_path);
+	kfree(mntpath);
 	kfree(server->hostname);
 	kfree(server);
 	return s;
+
+error_splat_super:
+	up_write(&s->s_umount);
+	deactivate_super(s);
+	return ERR_PTR(error);
 }
 
 static void nfs4_kill_super(struct super_block *sb)
@@ -2131,6 +2138,7 @@ static struct inode *nfs_alloc_inode(str
 #ifdef CONFIG_NFS_V4
 	nfsi->nfs4_acl = NULL;
 #endif /* CONFIG_NFS_V4 */
+
 	return &nfsi->vfs_inode;
 }
 
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/nfs3proc.c linux-2.6.16-rc4-getsb-nfs/fs/nfs/nfs3proc.c
--- linux-2.6.16-rc4-getsb/fs/nfs/nfs3proc.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/nfs3proc.c	2006-02-22 17:34:57.000000000 +0000
@@ -86,7 +86,7 @@ do_proc_get_root(struct rpc_clnt *client
 }
 
 /*
- * Bare-bones access to getattr: this is for nfs_read_super.
+ * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
  */
 static int
 nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/nfs4proc.c linux-2.6.16-rc4-getsb-nfs/fs/nfs/nfs4proc.c
--- linux-2.6.16-rc4-getsb/fs/nfs/nfs4proc.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/nfs4proc.c	2006-02-22 18:25:55.000000000 +0000
@@ -908,7 +908,7 @@ out_put_state_owner:
 static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_state *res;
+	struct nfs4_state *res = NULL;
 	int err;
 
 	do {
@@ -1366,70 +1366,19 @@ static int nfs4_lookup_root(struct nfs_s
 	return err;
 }
 
+/*
+ * get the file handle for the "/" directory on the server
+ */
 static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		struct nfs_fsinfo *info)
+			      struct nfs_fsinfo *info)
 {
-	struct nfs_fattr *	fattr = info->fattr;
-	unsigned char *		p;
-	struct qstr		q;
-	struct nfs4_lookup_arg args = {
-		.dir_fh = fhandle,
-		.name = &q,
-		.bitmask = nfs4_fattr_bitmap,
-	};
-	struct nfs4_lookup_res res = {
-		.server = server,
-		.fattr = fattr,
-		.fh = fhandle,
-	};
-	struct rpc_message msg = {
-		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
-		.rpc_argp = &args,
-		.rpc_resp = &res,
-	};
 	int status;
 
-	/*
-	 * Now we do a separate LOOKUP for each component of the mount path.
-	 * The LOOKUPs are done separately so that we can conveniently
-	 * catch an ERR_WRONGSEC if it occurs along the way...
-	 */
 	status = nfs4_lookup_root(server, fhandle, info);
-	if (status)
-		goto out;
-
-	p = server->mnt_path;
-	for (;;) {
-		struct nfs4_exception exception = { };
-
-		while (*p == '/')
-			p++;
-		if (!*p)
-			break;
-		q.name = p;
-		while (*p && (*p != '/'))
-			p++;
-		q.len = p - q.name;
-
-		do {
-			nfs_fattr_init(fattr);
-			status = nfs4_handle_exception(server,
-					rpc_call_sync(server->client, &msg, 0),
-					&exception);
-		} while (exception.retry);
-		if (status == 0)
-			continue;
-		if (status == -ENOENT) {
-			printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
-			printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
-		}
-		break;
-	}
 	if (status == 0)
 		status = nfs4_server_capabilities(server, fhandle);
 	if (status == 0)
 		status = nfs4_do_fsinfo(server, fhandle, info);
-out:
 	return status;
 }
 
diff -uNrp linux-2.6.16-rc4-getsb/fs/nfs/nfs4state.c linux-2.6.16-rc4-getsb-nfs/fs/nfs/nfs4state.c
--- linux-2.6.16-rc4-getsb/fs/nfs/nfs4state.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/nfs/nfs4state.c	2006-02-22 17:46:54.000000000 +0000
@@ -69,8 +69,6 @@ init_nfsv4_state(struct nfs_server *serv
 void
 destroy_nfsv4_state(struct nfs_server *server)
 {
-	kfree(server->mnt_path);
-	server->mnt_path = NULL;
 	if (server->nfs4_state) {
 		nfs4_put_client(server->nfs4_state);
 		server->nfs4_state = NULL;
diff -uNrp linux-2.6.16-rc4-getsb/fs/namei.c linux-2.6.16-rc4-getsb-nfs/fs/namei.c
--- linux-2.6.16-rc4-getsb/fs/namei.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/namei.c	2006-02-22 18:27:19.000000000 +0000
@@ -992,6 +992,8 @@ int fastcall link_path_walk(const char *
 	return result;
 }
 
+EXPORT_SYMBOL_GPL(link_path_walk);
+
 int fastcall path_walk(const char * name, struct nameidata *nd)
 {
 	current->total_link_count = 0;
diff -uNrp linux-2.6.16-rc4-getsb/fs/namespace.c linux-2.6.16-rc4-getsb-nfs/fs/namespace.c
--- linux-2.6.16-rc4-getsb/fs/namespace.c	2006-02-22 17:00:37.000000000 +0000
+++ linux-2.6.16-rc4-getsb-nfs/fs/namespace.c	2006-02-22 18:21:52.000000000 +0000
@@ -86,12 +86,16 @@ struct vfsmount *alloc_vfsmnt(const char
 	return mnt;
 }
 
+EXPORT_SYMBOL_GPL(alloc_vfsmnt);
+
 void free_vfsmnt(struct vfsmount *mnt)
 {
 	kfree(mnt->mnt_devname);
 	kmem_cache_free(mnt_cache, mnt);
 }
 
+EXPORT_SYMBOL_GPL(free_vfsmnt);
+
 /*
  * find the first or last mount at @dentry on vfsmount @mnt depending on
  * @dir. If @dir is set return the first mount else return the last mount.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2006-02-22 20:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-02-22 20:21 [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount David Howells
2006-02-22 20:21 ` [PATCH 2/5] NFS: Apply mount root dentry override to filesystems David Howells
2006-02-22 20:21 ` [PATCH 5/5] NFS: Unify NFS superblocks per-protocol per-server David Howells
2006-02-22 20:21 ` [PATCH 3/5] NFS: Abstract out namespace initialisation David Howells
2006-02-22 20:21 ` [PATCH 4/5] NFS: Add dentry materialisation op David Howells

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).