summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThordur I. Bjornsson <thib@cvs.openbsd.org>2009-08-11 11:07:37 +0000
committerThordur I. Bjornsson <thib@cvs.openbsd.org>2009-08-11 11:07:37 +0000
commiteaa5cc3a729723b87f770e5319d57549e6bd9bcc (patch)
tree029ab802ca62fed8ba906e255df3a25b3129f232
parente90e1b5a69a87fae8c01ce2bd524a3a254dda719 (diff)
Fix a few bugs in nfsrv_rename() error recovery code.
- Prevent a double vrele() by setting the vnode pointer to NULL. - Check if vnode pointers have been set to NULL before trying to vrele(). - don't double free the component path name buffer. - Add a workaround for multiple vnode pointers all pointing to the same vnode and the code doing vrele() on all of them, leading to botched refcounts. This is a horrible hack, but a real fix is being worked on. OK blambert@
-rw-r--r--sys/nfs/nfs_serv.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c
index 5497237d817..85c3a6a592f 100644
--- a/sys/nfs/nfs_serv.c
+++ b/sys/nfs/nfs_serv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_serv.c,v 1.83 2009/08/10 09:44:44 blambert Exp $ */
+/* $OpenBSD: nfs_serv.c,v 1.84 2009/08/11 11:07:36 thib Exp $ */
/* $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $ */
/*
@@ -1161,8 +1161,10 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
nfsm_reply(NFSX_WCCDATA(1));
nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
&info.nmi_mb);
- if (dirp)
+ if (dirp) {
vrele(dirp);
+ dirp = NULL;
+ }
error = 0;
goto nfsmout;
}
@@ -1419,8 +1421,6 @@ nfsrv_rename(nfsd, slp, procp, mrq)
&info.nmi_mb);
nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft,
&info.nmi_mb);
- if (fdirp)
- vrele(fdirp);
error = 0;
goto nfsmout;
}
@@ -1533,11 +1533,19 @@ nfsmout:
pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
}
if (fromnd.ni_cnd.cn_nameiop) {
- vrele(fromnd.ni_startdir);
- pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
+ if (fromnd.ni_startdir)
+ vrele(fromnd.ni_startdir);
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
- vrele(fromnd.ni_dvp);
- vrele(fvp);
+
+ /*
+ * XXX: Workaround the fact that fromnd.ni_dvp can point
+ * to the same vnode as fdirp. The real fix is to not have
+ * multiple pointers to the same object.
+ */
+ if (fromnd.ni_dvp != NULL && fromnd.ni_dvp != fdirp)
+ vrele(fromnd.ni_dvp);
+ if (fvp)
+ vrele(fvp);
}
return (error);
}