Sophie

Sophie

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

kernel-2.6.18-194.11.1.el5.src.rpm

From: Steve Dickson <SteveD@redhat.com>
Subject: Re: [RHEL5.1][PATCH] NFS: enable 'nosharecache' mounts.
Date: Wed, 12 Sep 2007 13:41:46 -0400
Bugzilla: 243913
Message-Id: <46E824DA.5060602@RedHat.com>
Changelog: [nfs] enable 'nosharecache' mounts fixes

[modified to deal with rhel5's fs-cache patches]

commit e89a5a43b95cdc4305b7c8e8121a380f02476636
Author: Trond Myklebust <Trond.Myklebust@netapp.com>

    NFS: Fix the mount regression
    
    This avoids the recent NFS mount regression (returning EBUSY when
    mounting the same filesystem twice with different parameters).
    
    The best I can do given the constraints appears to be to have the kernel
    first look for a superblock that matches both the fsid and the
    user-specified mount options, and then spawn off a new superblock if
    that search fails.
    
    Note that this is not the same as specifying nosharecache everywhere
    since nosharecache will never attempt to match an existing superblock.
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
    Tested-by: Hua Zhong <hzhong@gmail.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

--- linux-2.6.18.i686/fs/nfs/super.c.orig	2007-09-11 09:52:28.118771000 -0400
+++ linux-2.6.18.i686/fs/nfs/super.c	2007-09-12 13:19:28.403336000 -0400
@@ -599,36 +599,16 @@
  	nfs_initialise_sb(sb);
 }
 
-static int nfs_set_super(struct super_block *s, void *_server)
-{
-	struct nfs_server *server = _server;
-	int ret;
-
-	s->s_fs_info = server;
-	ret = set_anon_super(s, server);
-	if (ret == 0)
-		server->s_dev = s->s_dev;
-	return ret;
-}
+#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
 
-static int nfs_compare_super(struct super_block *sb, void *data)
+static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
 {
-	struct nfs_server *server = data, *old = NFS_SB(sb);
+	const struct nfs_server *a = s->s_fs_info;
+	const struct rpc_clnt *clnt_a = a->client;
+	const struct rpc_clnt *clnt_b = b->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)
-		return 0;
-	if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
-		return 0;
-	return 1;
-}
-
-static int nfs_compare_mount_options(const struct nfs_server *a, const struct nfs_server *b)
-{
+	if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK))
+		goto Ebusy;
 	if (a->nfs_client != b->nfs_client)
 		goto Ebusy;
 	if (a->flags != b->flags)
@@ -645,9 +625,62 @@
 		goto Ebusy;
 	if (a->acdirmax != b->acdirmax)
 		goto Ebusy;
-	return 0;
+	if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
+		goto Ebusy;
+	return 1;
 Ebusy:
-	return -EBUSY;
+	return 0;
+}
+
+struct nfs_sb_mountdata {
+	struct nfs_server *server;
+	int mntflags;
+	int err_on_noshare;
+};
+
+static int nfs_set_super(struct super_block *s, void *data)
+{
+	struct nfs_sb_mountdata *sb_mntdata = data;
+	struct nfs_server *server = sb_mntdata->server;
+	int ret;
+
+	s->s_flags = sb_mntdata->mntflags;
+	s->s_fs_info = server;
+	ret = set_anon_super(s, server);
+	if (ret == 0)
+		server->s_dev = s->s_dev;
+	return ret;
+}
+
+static int nfs_compare_super(struct super_block *sb, void *data)
+{
+	struct nfs_sb_mountdata *sb_mntdata = data;
+	struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
+	int mntflags = sb_mntdata->mntflags;
+	int cc, fsc;
+
+	if (memcmp(&old->nfs_client->cl_addr,
+				&server->nfs_client->cl_addr,
+				sizeof(old->nfs_client->cl_addr)) != 0)
+		return 0;
+	if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
+		return 0;
+	/*
+	 * With FS-Cache super block sharing is a must with the 
+	 * same server and exported filesystem 
+	 */
+	fsc = ((server->flags & NFS_MOUNT_FSCACHE) &&
+		(old->flags & NFS_MOUNT_FSCACHE));
+
+	/* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
+	if (old->flags & NFS_MOUNT_UNSHARED) {
+		sb_mntdata->err_on_noshare |= fsc;
+		return 0;
+	}
+	cc =  nfs_compare_mount_options(sb, server, mntflags);
+	if (!cc)
+		sb_mntdata->err_on_noshare |= fsc;
+	return cc;
 }
 
 static int nfs_get_sb(struct file_system_type *fs_type,
@@ -659,6 +692,10 @@
 	struct nfs_mount_data *data = raw_data;
 	struct dentry *mntroot;
 	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
+	struct nfs_sb_mountdata sb_mntdata = {
+		.mntflags = flags,
+		.err_on_noshare = 0,
+	};
 	int error;
 
 	/* Validate the mount data */
@@ -672,32 +709,29 @@
 		error = PTR_ERR(server);
 		goto out_err_noserver;
 	}
+	sb_mntdata.server = server;
 
 	if (server->flags & NFS_MOUNT_UNSHARED) {
-		if (server->flags & NFS_MOUNT_FSCACHE) {
-			error = -EINVAL;
-			goto out_err_nosb;
-		}
-		compare_super = NULL;
+		/* Always do the comapre with fsc mounts */
+		if (!(server->flags & NFS_MOUNT_FSCACHE))
+			compare_super = NULL;
 	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(fs_type, compare_super, nfs_set_super, server);
+	s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
 	}
-
 	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;
+	} else if (sb_mntdata.err_on_noshare) {
+		error = -EINVAL;
+		goto error_splat_super;
 	}
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		s->s_flags = flags;
 		nfs_fill_super(s, data);
 	}
 
@@ -746,6 +780,10 @@
 	struct nfs_server *server;
 	struct dentry *mntroot;
 	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
+	struct nfs_sb_mountdata sb_mntdata = {
+		.mntflags = flags,
+		.err_on_noshare = 0,
+	};
 	int error;
 
 	dprintk("--> nfs_xdev_get_sb()\n");
@@ -756,16 +794,15 @@
 		error = PTR_ERR(server);
 		goto out_err_noserver;
 	}
+	sb_mntdata.server = server;
 
 	if (server->flags & NFS_MOUNT_UNSHARED) {
-		if (server->flags & NFS_MOUNT_FSCACHE) {
-			error = -EINVAL;
-			goto out_err_nosb;
-		}
-		compare_super = NULL;
+		/* Always do the comapre with fsc mounts */
+		if (!(server->flags & NFS_MOUNT_FSCACHE))
+			compare_super = NULL;
 	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
+	s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
@@ -774,11 +811,13 @@
 	if (s->s_fs_info != server) {
 		nfs_free_server(server);
 		server = NULL;
+	} else if (sb_mntdata.err_on_noshare) {
+		error = -EINVAL;
+		goto error_splat_super;
 	}
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		s->s_flags = flags;
 		nfs_clone_super(s, data->sb);
 	}
 
@@ -871,6 +910,10 @@
 	char *mntpath = NULL, *hostname = NULL, ip_addr[16];
 	void *p;
 	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
+	struct nfs_sb_mountdata sb_mntdata = {
+		.mntflags = flags,
+		.err_on_noshare = 0,
+	};
 	int error;
 
 	if (data == NULL) {
@@ -938,32 +981,30 @@
 		error = PTR_ERR(server);
 		goto out_err_noserver;
 	}
+	sb_mntdata.server = server;
 
 	if (server->flags & NFS_MOUNT_UNSHARED) {
-		if (server->flags & NFS_MOUNT_FSCACHE) {
-			error = -EINVAL;
-			goto out_free;
-		}
-		compare_super = NULL;
+		/* Always do the comapre with fsc mounts */
+		if (!(server->flags & NFS_MOUNT_FSCACHE))
+			compare_super = NULL;
 	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(fs_type, compare_super, nfs_set_super, server);
+	s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_free;
 	}
 
 	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;
+	} else if (sb_mntdata.err_on_noshare) {
+		error = -EINVAL;
+		goto error_splat_super;
 	}
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		s->s_flags = flags;
 		nfs4_fill_super(s);
 	}
 
@@ -1020,6 +1061,10 @@
 	struct nfs_server *server;
 	struct dentry *mntroot;
 	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
+	struct nfs_sb_mountdata sb_mntdata = {
+		.mntflags = flags,
+		.err_on_noshare = 0,
+	};
 	int error;
 
 	dprintk("--> nfs4_xdev_get_sb()\n");
@@ -1030,16 +1075,15 @@
 		error = PTR_ERR(server);
 		goto out_err_noserver;
 	}
+	sb_mntdata.server = server;
 
 	if (server->flags & NFS4_MOUNT_UNSHARED) {
-		if (server->flags & NFS4_MOUNT_FSCACHE) {
-			error = -EINVAL;
-			goto out_err_nosb;
-		}
-		compare_super = NULL;
+		/* Always do the comapre with fsc mounts */
+		if (!(server->flags & NFS_MOUNT_FSCACHE))
+			compare_super = NULL;
 	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
+	s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
@@ -1048,11 +1092,13 @@
 	if (s->s_fs_info != server) {
 		nfs_free_server(server);
 		server = NULL;
+	} else if (sb_mntdata.err_on_noshare) {
+		error = -EINVAL;
+		goto error_splat_super;
 	}
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		s->s_flags = flags;
 		nfs4_clone_super(s, data->sb);
 	}
 
@@ -1095,6 +1141,10 @@
 	struct dentry *mntroot;
 	struct nfs_fh mntfh;
 	int (*compare_super)(struct super_block *,void *) = nfs_compare_super;
+	struct nfs_sb_mountdata sb_mntdata = {
+		.mntflags = flags,
+		.err_on_noshare = 0,
+	};
 	int error;
 
 	dprintk("--> nfs4_referral_get_sb()\n");
@@ -1105,16 +1155,15 @@
 		error = PTR_ERR(server);
 		goto out_err_noserver;
 	}
+	sb_mntdata.server = server;
 
 	if (server->flags & NFS4_MOUNT_UNSHARED) {
-		if (server->flags & NFS4_MOUNT_FSCACHE) {
-			error = -EINVAL;
-			goto out_err_nosb;
-		}
-		compare_super = NULL;
+		/* Always do the comapre with fsc mounts */
+		if (!(server->flags & NFS_MOUNT_FSCACHE))
+			compare_super = NULL;
 	}
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
+	s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto out_err_nosb;
@@ -1123,11 +1172,13 @@
 	if (s->s_fs_info != server) {
 		nfs_free_server(server);
 		server = NULL;
+	} else if (sb_mntdata.err_on_noshare) {
+		error = -EINVAL;
+		goto error_splat_super;
 	}
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		s->s_flags = flags;
 		nfs4_fill_super(s);
 	}