Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_subr.c
Show First 20 Lines • Show All 2,708 Lines • ▼ Show 20 Lines | |||||
* usecount is permitted to transition 1->0 without the interlock because | * usecount is permitted to transition 1->0 without the interlock because | ||||
* vnode is kept live by holdcnt. | * vnode is kept live by holdcnt. | ||||
*/ | */ | ||||
static enum vgetstate | static enum vgetstate | ||||
_vget_prep(struct vnode *vp, bool interlock) | _vget_prep(struct vnode *vp, bool interlock) | ||||
{ | { | ||||
enum vgetstate vs; | enum vgetstate vs; | ||||
if (__predict_true(vp->v_type != VCHR)) { | |||||
if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | ||||
vs = VGET_USECOUNT; | vs = VGET_USECOUNT; | ||||
} else { | } else { | ||||
_vhold(vp, interlock); | _vhold(vp, interlock); | ||||
vs = VGET_HOLDCNT; | vs = VGET_HOLDCNT; | ||||
} | } | ||||
} else { | |||||
if (!interlock) | |||||
VI_LOCK(vp); | |||||
if (vp->v_usecount == 0) { | |||||
vholdl(vp); | |||||
vs = VGET_HOLDCNT; | |||||
} else { | |||||
v_incr_devcount(vp); | |||||
refcount_acquire(&vp->v_usecount); | |||||
vs = VGET_USECOUNT; | |||||
} | |||||
if (!interlock) | |||||
VI_UNLOCK(vp); | |||||
} | |||||
return (vs); | return (vs); | ||||
} | } | ||||
enum vgetstate | enum vgetstate | ||||
vget_prep(struct vnode *vp) | vget_prep(struct vnode *vp) | ||||
{ | { | ||||
return (_vget_prep(vp, false)); | return (_vget_prep(vp, false)); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (vs == VGET_USECOUNT) { | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* We hold the vnode. If the usecount is 0 it will be utilized to keep | * We hold the vnode. If the usecount is 0 it will be utilized to keep | ||||
* the vnode around. Otherwise someone else lended their hold count and | * the vnode around. Otherwise someone else lended their hold count and | ||||
* we have to drop ours. | * we have to drop ours. | ||||
*/ | */ | ||||
if (vp->v_type != VCHR && | if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | ||||
refcount_acquire_if_not_zero(&vp->v_usecount)) { | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
int old = atomic_fetchadd_int(&vp->v_holdcnt, -1) - 1; | int old = atomic_fetchadd_int(&vp->v_holdcnt, -1) - 1; | ||||
VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__)); | VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__)); | ||||
#else | #else | ||||
refcount_release(&vp->v_holdcnt); | refcount_release(&vp->v_holdcnt); | ||||
#endif | #endif | ||||
VNODE_REFCOUNT_FENCE_ACQ(); | VNODE_REFCOUNT_FENCE_ACQ(); | ||||
VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | ||||
Show All 9 Lines | #endif | ||||
* | * | ||||
* Upgrade our holdcnt to a usecount. | * Upgrade our holdcnt to a usecount. | ||||
*/ | */ | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
/* | /* | ||||
* See the previous section. By the time we get here we may find | * See the previous section. By the time we get here we may find | ||||
* ourselves in the same spot. | * ourselves in the same spot. | ||||
*/ | */ | ||||
if (vp->v_type != VCHR) { | |||||
if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
int old = atomic_fetchadd_int(&vp->v_holdcnt, -1) - 1; | int old = atomic_fetchadd_int(&vp->v_holdcnt, -1) - 1; | ||||
VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__)); | VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__)); | ||||
#else | #else | ||||
refcount_release(&vp->v_holdcnt); | refcount_release(&vp->v_holdcnt); | ||||
#endif | #endif | ||||
VNODE_REFCOUNT_FENCE_ACQ(); | VNODE_REFCOUNT_FENCE_ACQ(); | ||||
VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | ||||
("%s: vnode with usecount and VI_OWEINACT set", | ("%s: vnode with usecount and VI_OWEINACT set", | ||||
__func__)); | __func__)); | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
return (0); | return (0); | ||||
} | } | ||||
} else { | |||||
if (vp->v_usecount > 0) | |||||
refcount_release(&vp->v_holdcnt); | |||||
} | |||||
if ((vp->v_iflag & VI_OWEINACT) == 0) { | if ((vp->v_iflag & VI_OWEINACT) == 0) { | ||||
oweinact = 0; | oweinact = 0; | ||||
} else { | } else { | ||||
oweinact = 1; | oweinact = 1; | ||||
vp->v_iflag &= ~VI_OWEINACT; | vp->v_iflag &= ~VI_OWEINACT; | ||||
VNODE_REFCOUNT_FENCE_REL(); | VNODE_REFCOUNT_FENCE_REL(); | ||||
} | } | ||||
v_incr_devcount(vp); | v_incr_devcount(vp); | ||||
Show All 10 Lines | |||||
* This will also remove the vnode from the free list if it is presently free. | * This will also remove the vnode from the free list if it is presently free. | ||||
*/ | */ | ||||
void | void | ||||
vref(struct vnode *vp) | vref(struct vnode *vp) | ||||
{ | { | ||||
ASSERT_VI_UNLOCKED(vp, __func__); | ASSERT_VI_UNLOCKED(vp, __func__); | ||||
CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | ||||
if (vp->v_type != VCHR && | if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | ||||
refcount_acquire_if_not_zero(&vp->v_usecount)) { | |||||
VNODE_REFCOUNT_FENCE_ACQ(); | VNODE_REFCOUNT_FENCE_ACQ(); | ||||
VNASSERT(vp->v_holdcnt > 0, vp, | VNASSERT(vp->v_holdcnt > 0, vp, | ||||
("%s: active vnode not held", __func__)); | ("%s: active vnode not held", __func__)); | ||||
VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | ||||
("%s: vnode with usecount and VI_OWEINACT set", __func__)); | ("%s: vnode with usecount and VI_OWEINACT set", __func__)); | ||||
return; | return; | ||||
} | } | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
vrefl(vp); | vrefl(vp); | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
} | } | ||||
void | void | ||||
vrefl(struct vnode *vp) | vrefl(struct vnode *vp) | ||||
{ | { | ||||
ASSERT_VI_LOCKED(vp, __func__); | ASSERT_VI_LOCKED(vp, __func__); | ||||
CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | ||||
if (vp->v_type != VCHR && | if (refcount_acquire_if_not_zero(&vp->v_usecount)) { | ||||
refcount_acquire_if_not_zero(&vp->v_usecount)) { | |||||
VNODE_REFCOUNT_FENCE_ACQ(); | VNODE_REFCOUNT_FENCE_ACQ(); | ||||
VNASSERT(vp->v_holdcnt > 0, vp, | VNASSERT(vp->v_holdcnt > 0, vp, | ||||
("%s: active vnode not held", __func__)); | ("%s: active vnode not held", __func__)); | ||||
VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, | ||||
("%s: vnode with usecount and VI_OWEINACT set", __func__)); | ("%s: vnode with usecount and VI_OWEINACT set", __func__)); | ||||
return; | return; | ||||
} | } | ||||
if (vp->v_usecount == 0) | |||||
vholdl(vp); | vholdl(vp); | ||||
if ((vp->v_iflag & VI_OWEINACT) != 0) { | if ((vp->v_iflag & VI_OWEINACT) != 0) { | ||||
vp->v_iflag &= ~VI_OWEINACT; | vp->v_iflag &= ~VI_OWEINACT; | ||||
VNODE_REFCOUNT_FENCE_REL(); | VNODE_REFCOUNT_FENCE_REL(); | ||||
} | } | ||||
v_incr_devcount(vp); | v_incr_devcount(vp); | ||||
refcount_acquire(&vp->v_usecount); | refcount_acquire(&vp->v_usecount); | ||||
} | } | ||||
void | void | ||||
vrefact(struct vnode *vp) | vrefact(struct vnode *vp) | ||||
{ | { | ||||
CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | ||||
if (__predict_false(vp->v_type == VCHR)) { | |||||
VNASSERT(vp->v_holdcnt > 0 && vp->v_usecount > 0, vp, | |||||
("%s: wrong ref counts", __func__)); | |||||
vref(vp); | |||||
return; | |||||
} | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
int old = atomic_fetchadd_int(&vp->v_usecount, 1); | int old = atomic_fetchadd_int(&vp->v_usecount, 1); | ||||
VNASSERT(old > 0, vp, ("%s: wrong use count", __func__)); | VNASSERT(old > 0, vp, ("%s: wrong use count", __func__)); | ||||
#else | #else | ||||
refcount_acquire(&vp->v_usecount); | refcount_acquire(&vp->v_usecount); | ||||
#endif | #endif | ||||
} | } | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | vputx(struct vnode *vp, int func) | ||||
*/ | */ | ||||
if (func == VPUTX_VPUT) | if (func == VPUTX_VPUT) | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
/* | /* | ||||
* We want to hold the vnode until the inactive finishes to | * We want to hold the vnode until the inactive finishes to | ||||
* prevent vgone() races. We drop the use count here and the | * prevent vgone() races. We drop the use count here and the | ||||
* hold count below when we're done. | * hold count below when we're done. | ||||
*/ | * | ||||
if (vp->v_type != VCHR) { | |||||
/* | |||||
* If we release the last usecount we take ownership of the hold | * If we release the last usecount we take ownership of the hold | ||||
* count which provides liveness of the vnode, in which case we | * count which provides liveness of the vnode, in which case we | ||||
* have to vdrop. | * have to vdrop. | ||||
*/ | */ | ||||
if (!refcount_release(&vp->v_usecount)) | if (!refcount_release(&vp->v_usecount)) | ||||
return; | return; | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
v_decr_devcount(vp); | |||||
/* | /* | ||||
* By the time we got here someone else might have transitioned | * By the time we got here someone else might have transitioned | ||||
* the count back to > 0. | * the count back to > 0. | ||||
*/ | */ | ||||
if (vp->v_usecount > 0) { | if (vp->v_usecount > 0) { | ||||
vdropl(vp); | vdropl(vp); | ||||
return; | return; | ||||
} | } | ||||
} else { | |||||
VI_LOCK(vp); | |||||
v_decr_devcount(vp); | |||||
if (!refcount_release(&vp->v_usecount)) { | |||||
VI_UNLOCK(vp); | |||||
return; | |||||
} | |||||
} | |||||
if (vp->v_iflag & VI_DOINGINACT) { | if (vp->v_iflag & VI_DOINGINACT) { | ||||
vdropl(vp); | vdropl(vp); | ||||
return; | return; | ||||
} | } | ||||
error = 0; | error = 0; | ||||
if (vp->v_usecount != 0) { | if (vp->v_usecount != 0) { | ||||
▲ Show 20 Lines • Show All 704 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
int | int | ||||
vcount(struct vnode *vp) | vcount(struct vnode *vp) | ||||
{ | { | ||||
int count; | int count; | ||||
dev_lock(); | dev_lock(); | ||||
count = vp->v_rdev->si_usecount; | count = vp->v_rdev->si_usecount; | ||||
dev_unlock(); | |||||
return (count); | |||||
} | |||||
/* | |||||
* Same as above, but using the struct cdev *as argument | |||||
*/ | |||||
int | |||||
count_dev(struct cdev *dev) | |||||
{ | |||||
int count; | |||||
dev_lock(); | |||||
count = dev->si_usecount; | |||||
dev_unlock(); | dev_unlock(); | ||||
return(count); | return (count); | ||||
} | } | ||||
/* | /* | ||||
* Print out a description of a vnode. | * Print out a description of a vnode. | ||||
*/ | */ | ||||
static char *typename[] = | static char *typename[] = | ||||
{"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD", | {"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD", | ||||
"VMARKER"}; | "VMARKER"}; | ||||
▲ Show 20 Lines • Show All 2,348 Lines • Show Last 20 Lines |