Page MenuHomeFreeBSD

D23427.id67541.diff
No OneTemporary

D23427.id67541.diff

Index: sys/kern/vfs_lookup.c
===================================================================
--- sys/kern/vfs_lookup.c
+++ sys/kern/vfs_lookup.c
@@ -254,7 +254,7 @@
}
static int
-namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
+namei_handle_root(struct nameidata *ndp, struct vnode **dpp, u_int n)
{
struct componentname *cnp;
@@ -276,7 +276,7 @@
ndp->ni_pathlen--;
}
*dpp = ndp->ni_rootdir;
- vrefact(*dpp);
+ vrefactn(*dpp, n);
return (0);
}
@@ -395,8 +395,11 @@
* Get starting point for the translation.
*/
FILEDESC_SLOCK(fdp);
+ /*
+ * The reference on ni_rootdir is acquired in the block below to avoid
+ * back-to-back atomics for absolute lookups.
+ */
ndp->ni_rootdir = fdp->fd_rdir;
- vrefact(ndp->ni_rootdir);
ndp->ni_topdir = fdp->fd_jdir;
/*
@@ -412,15 +415,29 @@
cnp->cn_nameptr = cnp->cn_pnbuf;
if (cnp->cn_pnbuf[0] == '/') {
ndp->ni_resflags |= NIRES_ABS;
- error = namei_handle_root(ndp, &dp);
+ error = namei_handle_root(ndp, &dp, 2);
+ if (error != 0) {
+ /*
+ * Simplify error handling, we should almost never be
+ * here.
+ */
+ vrefact(ndp->ni_rootdir);
+ }
} else {
if (ndp->ni_startdir != NULL) {
+ vrefact(ndp->ni_rootdir);
dp = ndp->ni_startdir;
startdir_used = 1;
} else if (ndp->ni_dirfd == AT_FDCWD) {
dp = fdp->fd_cdir;
- vrefact(dp);
+ if (dp == ndp->ni_rootdir) {
+ vrefactn(dp, 2);
+ } else {
+ vrefact(ndp->ni_rootdir);
+ vrefact(dp);
+ }
} else {
+ vrefact(ndp->ni_rootdir);
rights = ndp->ni_rightsneeded;
cap_rights_set(&rights, CAP_LOOKUP);
@@ -567,7 +584,7 @@
cnp->cn_nameptr = cnp->cn_pnbuf;
if (*(cnp->cn_nameptr) == '/') {
vrele(dp);
- error = namei_handle_root(ndp, &dp);
+ error = namei_handle_root(ndp, &dp, 1);
if (error != 0)
goto out;
}
Index: sys/kern/vfs_subr.c
===================================================================
--- sys/kern/vfs_subr.c
+++ sys/kern/vfs_subr.c
@@ -3046,6 +3046,19 @@
#endif
}
+void
+vrefactn(struct vnode *vp, u_int n)
+{
+
+ CTR2(KTR_VFS, "%s: vp %p", __func__, vp);
+#ifdef INVARIANTS
+ int old = atomic_fetchadd_int(&vp->v_usecount, n);
+ VNASSERT(old > 0, vp, ("%s: wrong use count %d", __func__, old));
+#else
+ atomic_add_int(&vp->v_usecount, n);
+#endif
+}
+
/*
* Return reference count of a vnode.
*
Index: sys/sys/vnode.h
===================================================================
--- sys/sys/vnode.h
+++ sys/sys/vnode.h
@@ -900,6 +900,7 @@
void vref(struct vnode *vp);
void vrefl(struct vnode *vp);
void vrefact(struct vnode *vp);
+void vrefactn(struct vnode *vp, u_int n);
int vrefcnt(struct vnode *vp);
void v_addpollinfo(struct vnode *vp);

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 26, 12:00 PM (18 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26211554
Default Alt Text
D23427.id67541.diff (2 KB)

Event Timeline