version 1.357.4.9, 2010/01/11 00:02:09 |
version 1.358, 2008/12/07 20:58:46 |
|
|
* change from a non-zero value to zero, again the interlock must be |
* change from a non-zero value to zero, again the interlock must be |
* held. |
* held. |
* |
* |
* There's a flag bit, VC_XLOCK, embedded in v_usecount. |
* Changing the usecount from a non-zero value to a non-zero value can |
* To raise v_usecount, if the VC_XLOCK bit is set in it, the interlock |
* safely be done using atomic operations, without the interlock held. |
* must be held. |
|
* To modify the VC_XLOCK bit, the interlock must be held. |
|
* We always keep the usecount (v_usecount & VC_MASK) non-zero while the |
|
* VC_XLOCK bit is set. |
|
* |
|
* Unless the VC_XLOCK bit is set, changing the usecount from a non-zero |
|
* value to a non-zero value can safely be done using atomic operations, |
|
* without the interlock held. |
|
* Even if the VC_XLOCK bit is set, decreasing the usecount to a non-zero |
|
* value can be done using atomic operations, without the interlock held. |
|
*/ |
*/ |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
Line 148 const int vttoif_tab[9] = { |
|
Line 138 const int vttoif_tab[9] = { |
|
int doforce = 1; /* 1 => permit forcible unmounting */ |
int doforce = 1; /* 1 => permit forcible unmounting */ |
int prtactive = 0; /* 1 => print out reclaim of active vnodes */ |
int prtactive = 0; /* 1 => print out reclaim of active vnodes */ |
|
|
extern int dovfsusermount; /* 1 => permit any user to mount filesystems */ |
|
extern int vfs_magiclinks; /* 1 => expand "magic" symlinks */ |
|
|
|
static vnodelst_t vnode_free_list = TAILQ_HEAD_INITIALIZER(vnode_free_list); |
static vnodelst_t vnode_free_list = TAILQ_HEAD_INITIALIZER(vnode_free_list); |
static vnodelst_t vnode_hold_list = TAILQ_HEAD_INITIALIZER(vnode_hold_list); |
static vnodelst_t vnode_hold_list = TAILQ_HEAD_INITIALIZER(vnode_hold_list); |
static vnodelst_t vrele_list = TAILQ_HEAD_INITIALIZER(vrele_list); |
static vnodelst_t vrele_list = TAILQ_HEAD_INITIALIZER(vrele_list); |
|
|
vp->v_freelisthd = NULL; |
vp->v_freelisthd = NULL; |
mutex_exit(&vnode_free_list_lock); |
mutex_exit(&vnode_free_list_lock); |
|
|
if (vp->v_usecount != 0) { |
|
/* |
|
* was referenced again before we got the interlock |
|
* Don't return to freelist - the holder of the last |
|
* reference will destroy it. |
|
*/ |
|
mutex_exit(&vp->v_interlock); |
|
mutex_enter(&vnode_free_list_lock); |
|
goto retry; |
|
} |
|
|
|
/* |
/* |
* The vnode is still associated with a file system, so we must |
* The vnode is still associated with a file system, so we must |
* clean it out before reusing it. We need to add a reference |
* clean it out before reusing it. We need to add a reference |
* before doing this. If the vnode gains another reference while |
* before doing this. If the vnode gains another reference while |
* being cleaned out then we lose - retry. |
* being cleaned out then we lose - retry. |
*/ |
*/ |
atomic_add_int(&vp->v_usecount, 1 + VC_XLOCK); |
atomic_inc_uint(&vp->v_usecount); |
vclean(vp, DOCLOSE); |
vclean(vp, DOCLOSE); |
KASSERT(vp->v_usecount >= 1 + VC_XLOCK); |
|
atomic_add_int(&vp->v_usecount, -VC_XLOCK); |
|
if (vp->v_usecount == 1) { |
if (vp->v_usecount == 1) { |
/* We're about to dirty it. */ |
/* We're about to dirty it. */ |
vp->v_iflag &= ~VI_CLEAN; |
vp->v_iflag &= ~VI_CLEAN; |
Line 1244 vtryget(vnode_t *vp) |
|
Line 1218 vtryget(vnode_t *vp) |
|
return false; |
return false; |
} |
} |
for (use = vp->v_usecount;; use = next) { |
for (use = vp->v_usecount;; use = next) { |
if (use == 0 || __predict_false((use & VC_XLOCK) != 0)) { |
if (use == 0) { |
/* Need interlock held if first reference. */ |
/* Need interlock held if first reference. */ |
return false; |
return false; |
} |
} |
Line 1299 vget(vnode_t *vp, int flags) |
|
Line 1273 vget(vnode_t *vp, int flags) |
|
vrelel(vp, 0); |
vrelel(vp, 0); |
return ENOENT; |
return ENOENT; |
} |
} |
|
|
if ((vp->v_iflag & VI_INACTNOW) != 0) { |
|
/* |
|
* if it's being desactived, wait for it to complete. |
|
* Make sure to not return a clean vnode. |
|
*/ |
|
if ((flags & LK_NOWAIT) != 0) { |
|
vrelel(vp, 0); |
|
return EBUSY; |
|
} |
|
vwait(vp, VI_INACTNOW); |
|
if ((vp->v_iflag & VI_CLEAN) != 0) { |
|
vrelel(vp, 0); |
|
return ENOENT; |
|
} |
|
} |
|
if (flags & LK_TYPE_MASK) { |
if (flags & LK_TYPE_MASK) { |
error = vn_lock(vp, flags | LK_INTERLOCK); |
error = vn_lock(vp, flags | LK_INTERLOCK); |
if (error != 0) { |
if (error != 0) { |
Line 1341 vput(vnode_t *vp) |
|
Line 1299 vput(vnode_t *vp) |
|
|
|
/* |
/* |
* Try to drop reference on a vnode. Abort if we are releasing the |
* Try to drop reference on a vnode. Abort if we are releasing the |
* last reference. Note: this _must_ succeed if not the last reference. |
* last reference. |
*/ |
*/ |
static inline bool |
static inline bool |
vtryrele(vnode_t *vp) |
vtryrele(vnode_t *vp) |
Line 1349 vtryrele(vnode_t *vp) |
|
Line 1307 vtryrele(vnode_t *vp) |
|
u_int use, next; |
u_int use, next; |
|
|
for (use = vp->v_usecount;; use = next) { |
for (use = vp->v_usecount;; use = next) { |
if (use == 1) { |
if (use == 1) { |
return false; |
return false; |
} |
} |
KASSERT((use & VC_MASK) > 1); |
|
next = atomic_cas_uint(&vp->v_usecount, use, use - 1); |
next = atomic_cas_uint(&vp->v_usecount, use, use - 1); |
if (__predict_true(next == use)) { |
if (__predict_true(next == use)) { |
return true; |
return true; |
Line 1374 vrelel(vnode_t *vp, int flags) |
|
Line 1331 vrelel(vnode_t *vp, int flags) |
|
KASSERT((vp->v_iflag & VI_MARKER) == 0); |
KASSERT((vp->v_iflag & VI_MARKER) == 0); |
KASSERT(vp->v_freelisthd == NULL); |
KASSERT(vp->v_freelisthd == NULL); |
|
|
if (__predict_false(vp->v_op == dead_vnodeop_p && |
if (vp->v_op == dead_vnodeop_p && (vp->v_iflag & VI_CLEAN) == 0) { |
(vp->v_iflag & (VI_CLEAN|VI_XLOCK)) == 0)) { |
|
vpanic(vp, "dead but not clean"); |
vpanic(vp, "dead but not clean"); |
} |
} |
|
|
Line 1389 vrelel(vnode_t *vp, int flags) |
|
Line 1345 vrelel(vnode_t *vp, int flags) |
|
return; |
return; |
} |
} |
if (vp->v_usecount <= 0 || vp->v_writecount != 0) { |
if (vp->v_usecount <= 0 || vp->v_writecount != 0) { |
vpanic(vp, "vrelel: bad ref count"); |
vpanic(vp, "vput: bad ref count"); |
} |
} |
|
|
KASSERT((vp->v_iflag & VI_XLOCK) == 0); |
|
|
|
/* |
/* |
* If not clean, deactivate the vnode, but preserve |
* If not clean, deactivate the vnode, but preserve |
* our reference across the call to VOP_INACTIVE(). |
* our reference across the call to VOP_INACTIVE(). |
Line 1411 vrelel(vnode_t *vp, int flags) |
|
Line 1365 vrelel(vnode_t *vp, int flags) |
|
/* The pagedaemon can't wait around; defer. */ |
/* The pagedaemon can't wait around; defer. */ |
defer = true; |
defer = true; |
} else if (curlwp == vrele_lwp) { |
} else if (curlwp == vrele_lwp) { |
/* |
/* We have to try harder. */ |
* We have to try harder. But we can't sleep |
vp->v_iflag &= ~VI_INACTREDO; |
* with VI_INACTNOW as vget() may be waiting on it. |
|
*/ |
|
vp->v_iflag &= ~(VI_INACTREDO|VI_INACTNOW); |
|
cv_broadcast(&vp->v_cv); |
|
error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK | |
error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK | |
LK_RETRY); |
LK_RETRY); |
if (error != 0) { |
if (error != 0) { |
/* XXX */ |
/* XXX */ |
vpanic(vp, "vrele: unable to lock %p"); |
vpanic(vp, "vrele: unable to lock %p"); |
} |
} |
mutex_enter(&vp->v_interlock); |
|
/* |
|
* if we did get another reference while |
|
* sleeping, don't try to inactivate it yet. |
|
*/ |
|
if (__predict_false(vtryrele(vp))) { |
|
VOP_UNLOCK(vp, 0); |
|
mutex_exit(&vp->v_interlock); |
|
return; |
|
} |
|
vp->v_iflag |= VI_INACTNOW; |
|
mutex_exit(&vp->v_interlock); |
|
defer = false; |
defer = false; |
} else if ((vp->v_iflag & VI_LAYER) != 0) { |
} else if ((vp->v_iflag & VI_LAYER) != 0) { |
/* |
/* |
Line 1470 vrelel(vnode_t *vp, int flags) |
|
Line 1408 vrelel(vnode_t *vp, int flags) |
|
if (++vrele_pending > (desiredvnodes >> 8)) |
if (++vrele_pending > (desiredvnodes >> 8)) |
cv_signal(&vrele_cv); |
cv_signal(&vrele_cv); |
mutex_exit(&vrele_lock); |
mutex_exit(&vrele_lock); |
cv_broadcast(&vp->v_cv); |
|
mutex_exit(&vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
return; |
return; |
} |
} |
Line 1495 vrelel(vnode_t *vp, int flags) |
|
Line 1432 vrelel(vnode_t *vp, int flags) |
|
VOP_INACTIVE(vp, &recycle); |
VOP_INACTIVE(vp, &recycle); |
mutex_enter(&vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
vp->v_iflag &= ~VI_INACTNOW; |
vp->v_iflag &= ~VI_INACTNOW; |
cv_broadcast(&vp->v_cv); |
|
if (!recycle) { |
if (!recycle) { |
if (vtryrele(vp)) { |
if (vtryrele(vp)) { |
mutex_exit(&vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
Line 1902 vclean(vnode_t *vp, int flags) |
|
Line 1838 vclean(vnode_t *vp, int flags) |
|
cache_purge(vp); |
cache_purge(vp); |
|
|
/* Done with purge, notify sleepers of the grim news. */ |
/* Done with purge, notify sleepers of the grim news. */ |
mutex_enter(&vp->v_interlock); |
|
vp->v_op = dead_vnodeop_p; |
vp->v_op = dead_vnodeop_p; |
vp->v_tag = VT_NON; |
vp->v_tag = VT_NON; |
|
mutex_enter(&vp->v_interlock); |
vp->v_vnlock = &vp->v_lock; |
vp->v_vnlock = &vp->v_lock; |
KNOTE(&vp->v_klist, NOTE_REVOKE); |
KNOTE(&vp->v_klist, NOTE_REVOKE); |
vp->v_iflag &= ~(VI_XLOCK | VI_FREEING); |
vp->v_iflag &= ~(VI_XLOCK | VI_FREEING); |
Line 2051 vrevoke(vnode_t *vp) |
|
Line 1987 vrevoke(vnode_t *vp) |
|
if ((vp->v_iflag & VI_CLEAN) != 0) { |
if ((vp->v_iflag & VI_CLEAN) != 0) { |
mutex_exit(&vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
return; |
return; |
} else if (vp->v_type != VBLK && vp->v_type != VCHR) { |
|
atomic_inc_uint(&vp->v_usecount); |
|
vclean(vp, DOCLOSE); |
|
vrelel(vp, 0); |
|
return; |
|
} else { |
} else { |
dev = vp->v_rdev; |
dev = vp->v_rdev; |
type = vp->v_type; |
type = vp->v_type; |
Line 2091 vrevoke(vnode_t *vp) |
|
Line 2022 vrevoke(vnode_t *vp) |
|
/* |
/* |
* sysctl helper routine to return list of supported fstypes |
* sysctl helper routine to return list of supported fstypes |
*/ |
*/ |
static int |
int |
sysctl_vfs_generic_fstypes(SYSCTLFN_ARGS) |
sysctl_vfs_generic_fstypes(SYSCTLFN_ARGS) |
{ |
{ |
char bf[sizeof(((struct statvfs *)NULL)->f_fstypename)]; |
char bf[sizeof(((struct statvfs *)NULL)->f_fstypename)]; |
Line 2147 sysctl_vfs_generic_fstypes(SYSCTLFN_ARGS |
|
Line 2078 sysctl_vfs_generic_fstypes(SYSCTLFN_ARGS |
|
return (error); |
return (error); |
} |
} |
|
|
/* |
|
* Top level filesystem related information gathering. |
|
*/ |
|
SYSCTL_SETUP(sysctl_vfs_setup, "sysctl vfs subtree setup") |
|
{ |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "vfs", NULL, |
|
NULL, 0, NULL, 0, |
|
CTL_VFS, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "generic", |
|
SYSCTL_DESCR("Non-specific vfs related information"), |
|
NULL, 0, NULL, 0, |
|
CTL_VFS, VFS_GENERIC, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "usermount", |
|
SYSCTL_DESCR("Whether unprivileged users may mount " |
|
"filesystems"), |
|
NULL, 0, &dovfsusermount, 0, |
|
CTL_VFS, VFS_GENERIC, VFS_USERMOUNT, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_STRING, "fstypes", |
|
SYSCTL_DESCR("List of file systems present"), |
|
sysctl_vfs_generic_fstypes, 0, NULL, 0, |
|
CTL_VFS, VFS_GENERIC, CTL_CREATE, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "magiclinks", |
|
SYSCTL_DESCR("Whether \"magic\" symlinks are expanded"), |
|
NULL, 0, &vfs_magiclinks, 0, |
|
CTL_VFS, VFS_GENERIC, VFS_MAGICLINKS, CTL_EOL); |
|
} |
|
|
|
|
|
int kinfo_vdebug = 1; |
int kinfo_vdebug = 1; |
int kinfo_vgetfailed; |
int kinfo_vgetfailed; |
Line 2250 sysctl_kern_vnode(SYSCTLFN_ARGS) |
|
Line 2144 sysctl_kern_vnode(SYSCTLFN_ARGS) |
|
} |
} |
memcpy(&vbuf, vp, VNODESZ); |
memcpy(&vbuf, vp, VNODESZ); |
mutex_exit(&mntvnode_lock); |
mutex_exit(&mntvnode_lock); |
if ((error = copyout(&vp, bp, VPTRSZ)) || |
if ((error = copyout(vp, bp, VPTRSZ)) || |
(error = copyout(&vbuf, bp + VPTRSZ, VNODESZ))) { |
(error = copyout(&vbuf, bp + VPTRSZ, VNODESZ))) { |
mutex_enter(&mntvnode_lock); |
mutex_enter(&mntvnode_lock); |
(void)vunmark(mvp); |
(void)vunmark(mvp); |
|
|
vattr_null(struct vattr *vap) |
vattr_null(struct vattr *vap) |
{ |
{ |
|
|
memset(vap, 0, sizeof(*vap)); |
|
|
|
vap->va_type = VNON; |
vap->va_type = VNON; |
|
|
/* |
/* |
Line 2574 vattr_null(struct vattr *vap) |
|
Line 2466 vattr_null(struct vattr *vap) |
|
vap->va_flags = VNOVAL; |
vap->va_flags = VNOVAL; |
vap->va_rdev = VNOVAL; |
vap->va_rdev = VNOVAL; |
vap->va_bytes = VNOVAL; |
vap->va_bytes = VNOVAL; |
|
vap->va_vaflags = 0; |
} |
} |
|
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |