Freeing vnodes.
David Schultz
das at FreeBSD.ORG
Tue Mar 29 06:19:04 PST 2005
On Tue, Mar 29, 2005, Jeff Roberson wrote:
> I fixed this. You should wrap vn_fullpath() with Giant and then commit
> your patch. I'll do the VFS_LOCK_GIANT() bit. Do you think we can get
> rid of v_id and v_ddid after you commit your patch?
Yeah, I'll merge in your changes and commit that later today.
I just realized that the patch I sent you isn't the same one
that I sent phk last Monday, so it didn't actually include most
of the v_id changes. Once I merge your changes into the following,
v_id can go away entirely.
BTW, I recently noticed that cache_leaf_test() is no longer used
and can also go away. I'll get to that later unless you beat me
to it.
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvs/src/sys/sys/vnode.h,v
retrieving revision 1.293
diff -u -r1.293 vnode.h
--- sys/sys/vnode.h 16 Mar 2005 11:20:51 -0000 1.293
+++ sys/sys/vnode.h 19 Mar 2005 22:00:54 -0000
@@ -145,7 +145,6 @@
TAILQ_HEAD(, namecache) v_cache_dst; /* c Cache entries to us */
u_long v_id; /* c capability identifier */
struct vnode *v_dd; /* c .. vnode */
- u_long v_ddid; /* c .. capability identifier */
/*
* clustering stuff
Index: sys/kern/vfs_cache.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_cache.c,v
retrieving revision 1.90
diff -u -r1.90 vfs_cache.c
--- sys/kern/vfs_cache.c 10 Feb 2005 12:16:42 -0000 1.90
+++ sys/kern/vfs_cache.c 19 Mar 2005 22:01:23 -0000
@@ -169,6 +169,8 @@
static void cache_zap(struct namecache *ncp);
+static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, u_int buflen);
static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
@@ -356,9 +358,8 @@
}
if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
dotdothits++;
- if (dvp->v_dd->v_id != dvp->v_ddid ||
+ if (dvp->v_dd == NULL ||
(cnp->cn_flags & MAKEENTRY) == 0) {
- dvp->v_ddid = 0;
CACHE_UNLOCK();
return (0);
}
@@ -369,7 +370,7 @@
}
hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT);
- hash = fnv_32_buf(&dvp->v_id, sizeof(dvp->v_id), hash);
+ hash = fnv_32_buf(&dvp, sizeof(dvp), hash);
LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) {
numchecks++;
if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen &&
@@ -456,13 +457,7 @@
return;
}
if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
- if (vp) {
- dvp->v_dd = vp;
- dvp->v_ddid = vp->v_id;
- } else {
- dvp->v_dd = dvp;
- dvp->v_ddid = 0;
- }
+ dvp->v_dd = vp;
return;
}
}
@@ -477,7 +472,8 @@
ncp->nc_flag = cnp->cn_flags & ISWHITEOUT ? NCF_WHITE : 0;
} else if (vp->v_type == VDIR) {
vp->v_dd = dvp;
- vp->v_ddid = dvp->v_id;
+ } else {
+ vp->v_dd = NULL;
}
/*
@@ -490,7 +486,7 @@
len = ncp->nc_nlen = cnp->cn_namelen;
hash = fnv_32_buf(cnp->cn_nameptr, len, FNV1_32_INIT);
bcopy(cnp->cn_nameptr, ncp->nc_name, len);
- hash = fnv_32_buf(&dvp->v_id, sizeof(dvp->v_id), hash);
+ hash = fnv_32_buf(&dvp, sizeof(dvp), hash);
ncpp = NCHHASH(hash);
LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
if (LIST_EMPTY(&dvp->v_cache_src)) {
@@ -542,16 +538,8 @@
* Invalidate all entries to a particular vnode.
*
* Remove all entries in the namecache relating to this vnode and
- * change the v_id. We take the v_id from a global counter, since
- * it becomes a handy sequence number in crash-dumps that way.
- * No valid vnode will ever have (v_id == 0).
- *
- * XXX: Only time and the size of v_id prevents this from failing:
- * XXX: In theory we should hunt down all (struct vnode*, v_id)
- * XXX: soft references and nuke them, at least on the global
- * XXX: v_id wraparound. The period of resistance can be extended
- * XXX: by incrementing each vnodes v_id individually instead of
- * XXX: using the global v_id.
+ * change the v_id. The counter is per-vnode, so two vnodes may
+ * have the same v_id. No valid vnode will ever have (v_id == 0).
*/
/*
@@ -562,7 +550,6 @@
cache_purge(vp)
struct vnode *vp;
{
- static u_long nextid;
CACHE_LOCK();
while (!LIST_EMPTY(&vp->v_cache_src))
@@ -570,12 +557,9 @@
while (!TAILQ_EMPTY(&vp->v_cache_dst))
cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
- do
- nextid++;
- while (nextid == vp->v_id || !nextid);
- vp->v_id = nextid;
- vp->v_dd = vp;
- vp->v_ddid = 0;
+ MPASS(vp->v_id > 0);
+ vp->v_id++;
+ vp->v_dd = NULL;
CACHE_UNLOCK();
}
@@ -780,14 +764,6 @@
SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0,
"Disable the getcwd syscall");
-/* Various statistics for the getcwd syscall */
-static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls);
-static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1);
-static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2);
-static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3);
-static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4);
-static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound);
-
/* Implementation of the getcwd syscall */
int
__getcwd(td, uap)
@@ -802,94 +778,29 @@
kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen)
{
char *bp, *tmpbuf;
- int error, i, slash_prefixed;
struct filedesc *fdp;
- struct namecache *ncp;
- struct vnode *vp;
+ int error;
- numcwdcalls++;
if (disablecwd)
return (ENODEV);
if (buflen < 2)
return (EINVAL);
if (buflen > MAXPATHLEN)
buflen = MAXPATHLEN;
- mtx_lock(&Giant);
- error = 0;
- tmpbuf = bp = malloc(buflen, M_TEMP, M_WAITOK);
- bp += buflen - 1;
- *bp = '\0';
+
+ tmpbuf = malloc(buflen, M_TEMP, M_WAITOK);
fdp = td->td_proc->p_fd;
- slash_prefixed = 0;
FILEDESC_LOCK(fdp);
- for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) {
- if (vp->v_vflag & VV_ROOT) {
- if (vp->v_mount == NULL) { /* forced unmount */
- error = EBADF;
- goto out;
- }
- vp = vp->v_mount->mnt_vnodecovered;
- continue;
- }
- if (vp->v_dd->v_id != vp->v_ddid) {
- numcwdfail1++;
- error = ENOTDIR;
- goto out;
- }
- CACHE_LOCK();
- ncp = TAILQ_FIRST(&vp->v_cache_dst);
- if (!ncp) {
- numcwdfail2++;
- CACHE_UNLOCK();
- error = ENOENT;
- goto out;
- }
- if (ncp->nc_dvp != vp->v_dd) {
- numcwdfail3++;
- CACHE_UNLOCK();
- error = EBADF;
- goto out;
- }
- for (i = ncp->nc_nlen - 1; i >= 0; i--) {
- if (bp == tmpbuf) {
- numcwdfail4++;
- CACHE_UNLOCK();
- error = ENOMEM;
- goto out;
- }
- *--bp = ncp->nc_name[i];
- }
- if (bp == tmpbuf) {
- numcwdfail4++;
- CACHE_UNLOCK();
- error = ENOMEM;
- goto out;
- }
- *--bp = '/';
- slash_prefixed = 1;
- vp = vp->v_dd;
- CACHE_UNLOCK();
- }
- if (!slash_prefixed) {
- if (bp == tmpbuf) {
- numcwdfail4++;
- error = ENOMEM;
- goto out;
- }
- *--bp = '/';
- }
+ error = vn_fullpath1(td, fdp->fd_cdir, fdp->fd_rdir, tmpbuf,
+ &bp, buflen);
FILEDESC_UNLOCK(fdp);
- mtx_unlock(&Giant);
- numcwdfound++;
- if (bufseg == UIO_SYSSPACE)
- bcopy(bp, buf, strlen(bp) + 1);
- else
- error = copyout(bp, buf, strlen(bp) + 1);
- free(tmpbuf, M_TEMP);
- return (error);
-out:
- FILEDESC_UNLOCK(fdp);
- mtx_unlock(&Giant);
+
+ if (!error) {
+ if (bufseg == UIO_SYSSPACE)
+ bcopy(bp, buf, strlen(bp) + 1);
+ else
+ error = copyout(bp, buf, strlen(bp) + 1);
+ }
free(tmpbuf, M_TEMP);
return (error);
}
@@ -907,10 +818,10 @@
SYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0,
"Disable the vn_fullpath function");
+/* These count for kern___getcwd(), too. */
STATNODE(numfullpathcalls);
STATNODE(numfullpathfail1);
STATNODE(numfullpathfail2);
-STATNODE(numfullpathfail3);
STATNODE(numfullpathfail4);
STATNODE(numfullpathfound);
@@ -921,90 +832,112 @@
int
vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
{
- char *bp, *buf;
- int i, slash_prefixed;
+ char *buf;
struct filedesc *fdp;
- struct namecache *ncp;
- struct vnode *vp;
+ int error;
- numfullpathcalls++;
if (disablefullpath)
return (ENODEV);
if (vn == NULL)
return (EINVAL);
+
buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- bp = buf + MAXPATHLEN - 1;
- *bp = '\0';
fdp = td->td_proc->p_fd;
- slash_prefixed = 0;
- ASSERT_VOP_LOCKED(vn, "vn_fullpath");
FILEDESC_LOCK(fdp);
- for (vp = vn; vp != fdp->fd_rdir && vp != rootvnode;) {
+ error = vn_fullpath1(td, vn, fdp->fd_rdir, buf, retbuf, MAXPATHLEN);
+ FILEDESC_UNLOCK(fdp);
+
+ if (!error)
+ *freebuf = buf;
+ else
+ free(buf, M_TEMP);
+ return (error);
+}
+
+/*
+ * The magic behind kern___getcwd() and vn_fullpath().
+ */
+static int
+vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, u_int buflen)
+{
+ char *bp;
+ int error, i, slash_prefixed;
+ struct namecache *ncp;
+
+ bp = buf + buflen - 1;
+ *bp = '\0';
+ error = 0;
+ slash_prefixed = 0;
+
+ CACHE_LOCK();
+ numfullpathcalls++;
+ if (vp->v_type != VDIR) {
+ ncp = TAILQ_FIRST(&vp->v_cache_dst);
+ if (!ncp) {
+ numfullpathfail2++;
+ CACHE_UNLOCK();
+ return (ENOENT);
+ }
+ for (i = ncp->nc_nlen - 1; i >= 0 && bp > buf; i--)
+ *--bp = ncp->nc_name[i];
+ if (bp == buf) {
+ numfullpathfail4++;
+ CACHE_UNLOCK();
+ return (ENOMEM);
+ }
+ *--bp = '/';
+ slash_prefixed = 1;
+ vp = ncp->nc_dvp;
+ }
+ while (vp != rdir && vp != rootvnode) {
if (vp->v_vflag & VV_ROOT) {
if (vp->v_mount == NULL) { /* forced unmount */
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (EBADF);
+ error = EBADF;
+ break;
}
vp = vp->v_mount->mnt_vnodecovered;
continue;
}
- if (vp != vn && vp->v_dd->v_id != vp->v_ddid) {
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
+ if (vp->v_dd == NULL) {
numfullpathfail1++;
- return (ENOTDIR);
+ error = ENOTDIR;
+ break;
}
- CACHE_LOCK();
ncp = TAILQ_FIRST(&vp->v_cache_dst);
if (!ncp) {
numfullpathfail2++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (ENOENT);
+ error = ENOENT;
+ break;
}
- if (vp != vn && ncp->nc_dvp != vp->v_dd) {
- numfullpathfail3++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (EBADF);
- }
- for (i = ncp->nc_nlen - 1; i >= 0; i--) {
- if (bp == buf) {
- numfullpathfail4++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (ENOMEM);
- }
+ MPASS(ncp->nc_dvp == vp->v_dd);
+ for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
*--bp = ncp->nc_name[i];
- }
if (bp == buf) {
numfullpathfail4++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (ENOMEM);
+ error = ENOMEM;
+ break;
}
*--bp = '/';
slash_prefixed = 1;
vp = ncp->nc_dvp;
+ }
+ if (error) {
CACHE_UNLOCK();
+ return (error);
}
if (!slash_prefixed) {
if (bp == buf) {
numfullpathfail4++;
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
+ CACHE_UNLOCK();
return (ENOMEM);
+ } else {
+ *--bp = '/';
}
- *--bp = '/';
}
- FILEDESC_UNLOCK(fdp);
numfullpathfound++;
+ CACHE_UNLOCK();
+
*retbuf = bp;
- *freebuf = buf;
return (0);
}
Index: sys/kern/vfs_subr.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.596
diff -u -r1.596 vfs_subr.c
--- sys/kern/vfs_subr.c 15 Mar 2005 14:38:16 -0000 1.596
+++ sys/kern/vfs_subr.c 19 Mar 2005 21:59:35 -0000
@@ -837,13 +837,12 @@
vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK|M_ZERO);
mtx_init(&vp->v_interlock, "vnode interlock", NULL, MTX_DEF);
- vp->v_dd = vp;
bo = &vp->v_bufobj;
bo->__bo_vnode = vp;
bo->bo_mtx = &vp->v_interlock;
vp->v_vnlock = &vp->v_lock;
lockinit(vp->v_vnlock, PVFS, tag, VLKTIMEOUT, LK_NOPAUSE);
- cache_purge(vp); /* Sets up v_id. */
+ vp->v_id = 1;
LIST_INIT(&vp->v_cache_src);
TAILQ_INIT(&vp->v_cache_dst);
}
More information about the freebsd-arch
mailing list