Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 2577

kernel-2.6.18-194.11.1.el5.src.rpm

From: Steve Dickson <SteveD@redhat.com>
Subject: [RHEL5.1][PATCH] NFS: enable 'nosharecache' mounts.
Date: Mon, 04 Jun 2007 10:41:19 -0400
Bugzilla: 209964
Message-Id: <4664248F.2060400@RedHat.com>
Changelog: [nfs] enable 'nosharecache' mounts.


The attached two patches basically re-enable the ability for
NFS clients to mount read-only and read-write filesystems from the
same server.

This ability was lost when NFS started to use the same super blocks for
the same server. This was needed for the FS-Cache support and it also
had a nice side effect of using less connections per server (i.e one).
But the ability to mount read-only and read-write filesystem was lost.

So these patches add a 'nosharecache' mount options that stops the
same super block from being used (i.e. allocates a new sb for each
mount). But nosharecache and the fsc mount options incompatible so
checks had to be added to ensure those mounts are not done.

Note: These commit blobs are relative to the NFS maintainer's git tree
but will be pulled Linus' tree in the next kernel release.

The bz is:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=209964


In this third version, I simply increase the FLAGMASK to include
the new 'UNSHARED' flag which eliminates some hackyness in
nfs/client.c.

No worries... we are will completely compatible with the
unsupported fsc flag and incompatible with upstream as the
wisdom has deemed...


--- linux-2.6.18.i686/fs/nfs/super.c.orig	2007-06-04 15:37:08.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/super.c	2007-06-04 15:42:30.000000000 -0400
@@ -290,8 +290,9 @@ static void nfs_show_mount_options(struc
 		{ NFS_MOUNT_NOAC, ",noac", "" },
 		{ NFS_MOUNT_NONLM, ",nolock", "" },
 		{ NFS_MOUNT_NOACL, ",noacl", "" },
-		{ NFS_MOUNT_FSCACHE, ",fsc", "" },
 		{ NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
+		{ NFS_MOUNT_UNSHARED, ",nosharecache", "" },
+		{ NFS_MOUNT_FSCACHE, ",fsc", "" },
 		{ 0, NULL, NULL }
 	};
 	const struct proc_nfs_info *nfs_infop;
@@ -601,6 +602,9 @@ static int nfs_compare_super(struct supe
 
 	if (old->nfs_client != server->nfs_client)
 		return 0;
+	/* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
+	if (old->flags & NFS_MOUNT_UNSHARED)
+		return 0;
 	if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
 		return 0;
 	return 1;
@@ -614,6 +618,7 @@ static int nfs_get_sb(struct file_system
 	struct nfs_fh mntfh;
 	struct nfs_mount_data *data = raw_data;
 	struct dentry *mntroot;
+	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
 	int error;
 
 	/* Validate the mount data */
@@ -628,8 +633,15 @@ static int nfs_get_sb(struct file_system
 		goto out_err_noserver;
 	}
 
+	if (server->flags & NFS_MOUNT_UNSHARED) {
+		if (server->flags & NFS_MOUNT_FSCACHE) {
+			error = -EINVAL;
+			goto out_err_nosb;
+		}
+		compare_super = NULL;
+	}
 	/* 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);
+	s = sget(fs_type, compare_super, nfs_set_super, server);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
@@ -690,6 +702,7 @@ static int nfs_xdev_get_sb(struct file_s
 	struct super_block *s;
 	struct nfs_server *server;
 	struct dentry *mntroot;
+	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
 	int error;
 
 	dprintk("--> nfs_xdev_get_sb()\n");
@@ -701,8 +714,15 @@ static int nfs_xdev_get_sb(struct file_s
 		goto out_err_noserver;
 	}
 
+	if (server->flags & NFS_MOUNT_UNSHARED) {
+		if (server->flags & NFS_MOUNT_FSCACHE) {
+			error = -EINVAL;
+			goto out_err_nosb;
+		}
+		compare_super = NULL;
+	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+	s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
@@ -807,6 +827,7 @@ static int nfs4_get_sb(struct file_syste
 	struct dentry *mntroot;
 	char *mntpath = NULL, *hostname = NULL, ip_addr[16];
 	void *p;
+	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
 	int error;
 
 	if (data == NULL) {
@@ -875,8 +896,15 @@ static int nfs4_get_sb(struct file_syste
 		goto out_err_noserver;
 	}
 
+	if (server->flags & NFS_MOUNT_UNSHARED) {
+		if (server->flags & NFS_MOUNT_FSCACHE) {
+			error = -EINVAL;
+			goto out_free;
+		}
+		compare_super = NULL;
+	}
 	/* 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);
+	s = sget(fs_type, compare_super, nfs_set_super, server);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_free;
@@ -945,6 +973,7 @@ static int nfs4_xdev_get_sb(struct file_
 	struct super_block *s;
 	struct nfs_server *server;
 	struct dentry *mntroot;
+	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
 	int error;
 
 	dprintk("--> nfs4_xdev_get_sb()\n");
@@ -956,8 +985,15 @@ static int nfs4_xdev_get_sb(struct file_
 		goto out_err_noserver;
 	}
 
+	if (server->flags & NFS4_MOUNT_UNSHARED) {
+		if (server->flags & NFS4_MOUNT_FSCACHE) {
+			error = -EINVAL;
+			goto out_err_nosb;
+		}
+		compare_super = NULL;
+	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+	s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
@@ -1012,6 +1048,7 @@ static int nfs4_referral_get_sb(struct f
 	struct nfs_server *server;
 	struct dentry *mntroot;
 	struct nfs_fh mntfh;
+	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
 	int error;
 
 	dprintk("--> nfs4_referral_get_sb()\n");
@@ -1023,8 +1060,15 @@ static int nfs4_referral_get_sb(struct f
 		goto out_err_noserver;
 	}
 
+	if (server->flags & NFS4_MOUNT_UNSHARED) {
+		if (server->flags & NFS4_MOUNT_FSCACHE) {
+			error = -EINVAL;
+			goto out_err_nosb;
+		}
+		compare_super = NULL;
+	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+	s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
--- linux-2.6.18.i686/include/linux/nfs_mount.h.orig	2007-06-04 15:37:08.000000000 -0400
+++ linux-2.6.18.i686/include/linux/nfs_mount.h	2007-06-05 03:53:27.000000000 -0400
@@ -63,6 +63,8 @@ struct nfs_mount_data {
 #define NFS_MOUNT_SECFLAVOUR	0x2000	/* 5 */
 #define NFS_MOUNT_FSCACHE	0x4000
 #define NFS_MOUNT_NORDIRPLUS	0x8000	/* 5 */
-#define NFS_MOUNT_FLAGMASK	0xFFFF
+#define NFS_MOUNT_UNSHARED  0x10000  /* 5 */
+#define NFS_MOUNT_FLAGMASK	0xFFFFF
+
 
 #endif
--- linux-2.6.18.i686/include/linux/nfs4_mount.h.orig	2007-06-04 15:37:08.000000000 -0400
+++ linux-2.6.18.i686/include/linux/nfs4_mount.h	2007-06-05 03:54:03.000000000 -0400
@@ -66,6 +66,8 @@ struct nfs4_mount_data {
 #define NFS4_MOUNT_NOAC		0x0020	/* 1 */
 #define NFS4_MOUNT_STRICTLOCK	0x1000	/* 1 */
 #define NFS4_MOUNT_FSCACHE	0x4000	/* 1 */
-#define NFS4_MOUNT_FLAGMASK	0xFFFF
+#define NFS4_MOUNT_UNSHARED 0x10000  /* 5 */
+#define NFS4_MOUNT_FLAGMASK	0xFFFFF
+
 
 #endif

commit 608a2896d6d9079b97715820ae8a5469e70bdecc
Author: Trond Myklebust <Trond.Myklebust@netapp.com>

    NFS: Error when mounting the same filesystem with different options
    
    Unless the user sets the NFS_MOUNT_NOSHAREDCACHE mount flag, we should
    return EBUSY if the filesystem is already mounted on a superblock that
    has set conflicting mount options.
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

--- linux-2.6.18.i686/fs/nfs/super.c.orig	2007-06-04 08:59:22.000000000 -0400
+++ linux-2.6.18.i686/fs/nfs/super.c	2007-06-04 09:30:50.000000000 -0400
@@ -600,7 +600,9 @@ static int nfs_compare_super(struct supe
 {
 	struct nfs_server *server = data, *old = NFS_SB(sb);
 
-	if (old->nfs_client != server->nfs_client)
+	if (memcmp(&old->nfs_client->cl_addr,
+				&server->nfs_client->cl_addr,
+				sizeof(old->nfs_client->cl_addr)) != 0)
 		return 0;
 	/* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
 	if (old->flags & NFS_MOUNT_UNSHARED)
@@ -610,6 +612,29 @@ static int nfs_compare_super(struct supe
 	return 1;
 }
 
+static int nfs_compare_mount_options(const struct nfs_server *a, const struct nfs_server *b)
+{
+	if (a->nfs_client != b->nfs_client)
+		goto Ebusy;
+	if (a->flags != b->flags)
+		goto Ebusy;
+	if (a->wsize != b->wsize)
+		goto Ebusy;
+	if (a->rsize != b->rsize)
+		goto Ebusy;
+	if (a->acregmin != b->acregmin)
+		goto Ebusy;
+	if (a->acregmax != b->acregmax)
+		goto Ebusy;
+	if (a->acdirmin != b->acdirmin)
+		goto Ebusy;
+	if (a->acdirmax != b->acdirmax)
+		goto Ebusy;
+	return 0;
+Ebusy:
+	return -EBUSY;
+}
+
 static int nfs_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
 {
@@ -648,8 +673,11 @@ static int nfs_get_sb(struct file_system
 	}
 
 	if (s->s_fs_info != server) {
+		error = nfs_compare_mount_options(server, NFS_SB(s));
 		nfs_free_server(server);
 		server = NULL;
+		if (error < 0)
+			goto error_splat_super;
 	}
 
 	if (!s->s_root) {
@@ -911,8 +939,11 @@ static int nfs4_get_sb(struct file_syste
 	}
 
 	if (s->s_fs_info != server) {
+		error = nfs_compare_mount_options(server, NFS_SB(s));
 		nfs_free_server(server);
 		server = NULL;
+		if (error < 0)
+			goto error_splat_super;
 	}
 
 	if (!s->s_root) {