summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2015-07-27 00:28:51 +0000
committerrmacklem <rmacklem@FreeBSD.org>2015-07-27 00:28:51 +0000
commit9c93ec1f0bfb28216eaa38482d4a91ea5ff2808e (patch)
tree172fefb0e79c153dcdd2109d67139367b489b9d4
parentd8cc27b9d06534836220413043b897e6983cf9c6 (diff)
downloadFreeBSD-src-9c93ec1f0bfb28216eaa38482d4a91ea5ff2808e.zip
FreeBSD-src-9c93ec1f0bfb28216eaa38482d4a91ea5ff2808e.tar.gz
MFC: r285066
Alex Burlyga reported a POLA violation for the new NFS client as compared to the old NFS client via email to the freebsd-fs@ mailing list. For the new client, when multiple clients attempted to create a symbolic link concurrently, more that one client would report success instead of EEXIST. This was caused by code in the new client that mapped EEXIST to OK assuming it was caused by a retried RPC request. Since the old client did not do this, the patch defaults to the old behaviour and permits the new behaviour to be enabled via a sysctl.
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index f8b6775..bfe6fa3 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -46,6 +46,13 @@ __FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include <fs/nfs/nfsport.h>
+#include <sys/sysctl.h>
+
+SYSCTL_DECL(_vfs_nfs);
+
+static int nfsignore_eexist = 0;
+SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
+ &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
/*
* Global variables
@@ -2528,8 +2535,12 @@ nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
mbuf_freem(nd->nd_mrep);
/*
* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+ * Only do this if vfs.nfs.ignore_eexist is set.
+ * Never do this for NFSv4.1 or later minor versions, since sessions
+ * should guarantee "exactly once" RPC semantics.
*/
- if (error == EEXIST)
+ if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
+ nmp->nm_minorvers == 0))
error = 0;
return (error);
}
@@ -2548,10 +2559,12 @@ nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
nfsattrbit_t attrbits;
int error = 0;
struct nfsfh *fhp;
+ struct nfsmount *nmp;
*nfhpp = NULL;
*attrflagp = 0;
*dattrflagp = 0;
+ nmp = VFSTONFS(vnode_mount(dvp));
fhp = VTONFS(dvp)->n_fhp;
if (namelen > NFS_MAXNAMLEN)
return (ENAMETOOLONG);
@@ -2603,9 +2616,13 @@ nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
nfsmout:
mbuf_freem(nd->nd_mrep);
/*
- * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
+ * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+ * Only do this if vfs.nfs.ignore_eexist is set.
+ * Never do this for NFSv4.1 or later minor versions, since sessions
+ * should guarantee "exactly once" RPC semantics.
*/
- if (error == EEXIST)
+ if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
+ nmp->nm_minorvers == 0))
error = 0;
return (error);
}
OpenPOWER on IntegriCloud