Simplify and rationalise the management of the vnode free list
(preparing the code to add snapshots).
This commit is contained in:
parent
e6796b67d9
commit
c904bbbdd8
@ -83,7 +83,6 @@ static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
|
||||
|
||||
static void insmntque __P((struct vnode *vp, struct mount *mp));
|
||||
static void vclean __P((struct vnode *vp, int flags, struct proc *p));
|
||||
static void vfree __P((struct vnode *));
|
||||
static unsigned long numvnodes;
|
||||
SYSCTL_INT(_debug, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, "");
|
||||
|
||||
@ -97,7 +96,6 @@ int vttoif_tab[9] = {
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */
|
||||
struct tobefreelist vnode_tobefree_list; /* vnode free list */
|
||||
|
||||
static u_long wantfreevnodes = 25;
|
||||
SYSCTL_INT(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, "");
|
||||
@ -175,7 +173,6 @@ vntblinit()
|
||||
simple_lock_init(&mntid_slock);
|
||||
simple_lock_init(&spechash_slock);
|
||||
TAILQ_INIT(&vnode_free_list);
|
||||
TAILQ_INIT(&vnode_tobefree_list);
|
||||
simple_lock_init(&vnode_free_list_slock);
|
||||
vnode_zone = zinit("VNODE", sizeof (struct vnode), 0, 0, 5);
|
||||
/*
|
||||
@ -451,11 +448,10 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
vop_t **vops;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
int s;
|
||||
int s, count;
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp, *tvp, *nvp;
|
||||
struct vnode *vp = NULL;
|
||||
vm_object_t object;
|
||||
TAILQ_HEAD(freelst, vnode) vnode_tmp_list;
|
||||
|
||||
/*
|
||||
* We take the least recently used vnode from the freelist
|
||||
@ -466,22 +462,6 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
TAILQ_INIT(&vnode_tmp_list);
|
||||
|
||||
for (vp = TAILQ_FIRST(&vnode_tobefree_list); vp; vp = nvp) {
|
||||
nvp = TAILQ_NEXT(vp, v_freelist);
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
if (vp->v_flag & VAGE) {
|
||||
TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
|
||||
}
|
||||
vp->v_flag &= ~(VTBFREE|VAGE);
|
||||
vp->v_flag |= VFREE;
|
||||
if (vp->v_usecount)
|
||||
panic("tobe free vnode isn't");
|
||||
freevnodes++;
|
||||
}
|
||||
|
||||
if (wantfreevnodes && freevnodes < wantfreevnodes) {
|
||||
vp = NULL;
|
||||
@ -490,42 +470,29 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
* XXX: this is only here to be backwards compatible
|
||||
*/
|
||||
vp = NULL;
|
||||
} else {
|
||||
for (vp = TAILQ_FIRST(&vnode_free_list); vp; vp = nvp) {
|
||||
nvp = TAILQ_NEXT(vp, v_freelist);
|
||||
if (!simple_lock_try(&vp->v_interlock))
|
||||
continue;
|
||||
if (vp->v_usecount)
|
||||
panic("free vnode isn't");
|
||||
|
||||
object = vp->v_object;
|
||||
if (object && (object->resident_page_count || object->ref_count)) {
|
||||
printf("object inconsistant state: RPC: %d, RC: %d\n",
|
||||
object->resident_page_count, object->ref_count);
|
||||
/* Don't recycle if it's caching some pages */
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
TAILQ_INSERT_TAIL(&vnode_tmp_list, vp, v_freelist);
|
||||
continue;
|
||||
} else if (LIST_FIRST(&vp->v_cache_src)) {
|
||||
/* Don't recycle if active in the namecache */
|
||||
simple_unlock(&vp->v_interlock);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else for (count = 0; count < freevnodes; count++) {
|
||||
vp = TAILQ_FIRST(&vnode_free_list);
|
||||
if (vp == NULL || vp->v_usecount)
|
||||
panic("getnewvnode: free vnode isn't");
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
/*
|
||||
* Don't recycle if active in the namecache or
|
||||
* if it still has cached pages or we cannot get
|
||||
* its interlock.
|
||||
*/
|
||||
object = vp->v_object;
|
||||
if (LIST_FIRST(&vp->v_cache_src) != NULL ||
|
||||
(object && (object->resident_page_count ||
|
||||
object->ref_count)) ||
|
||||
!simple_lock_try(&vp->v_interlock)) {
|
||||
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
|
||||
vp = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (tvp = TAILQ_FIRST(&vnode_tmp_list); tvp; tvp = nvp) {
|
||||
nvp = TAILQ_NEXT(tvp, v_freelist);
|
||||
TAILQ_REMOVE(&vnode_tmp_list, tvp, v_freelist);
|
||||
TAILQ_INSERT_TAIL(&vnode_free_list, tvp, v_freelist);
|
||||
simple_unlock(&tvp->v_interlock);
|
||||
}
|
||||
|
||||
if (vp) {
|
||||
vp->v_flag |= VDOOMED;
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
freevnodes--;
|
||||
simple_unlock(&vnode_free_list_slock);
|
||||
cache_purge(vp);
|
||||
@ -1868,8 +1835,8 @@ vgonel(vp, p)
|
||||
|
||||
/*
|
||||
* If it is on the freelist and not already at the head,
|
||||
* move it to the head of the list. The test of the back
|
||||
* pointer and the reference count of zero is because
|
||||
* move it to the head of the list. The test of the
|
||||
* VDOOMED flag and the reference count of zero is because
|
||||
* it will be removed from the free list by getnewvnode,
|
||||
* but will not have its reference count incremented until
|
||||
* after calling vgone. If the reference count were
|
||||
@ -1879,13 +1846,9 @@ vgonel(vp, p)
|
||||
if (vp->v_usecount == 0 && !(vp->v_flag & VDOOMED)) {
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
if (vp->v_flag & VFREE) {
|
||||
if (vp->v_flag & VFREE)
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
} else if (vp->v_flag & VTBFREE) {
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag &= ~VTBFREE;
|
||||
freevnodes++;
|
||||
} else
|
||||
else
|
||||
freevnodes++;
|
||||
vp->v_flag |= VFREE;
|
||||
TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
|
||||
@ -2593,7 +2556,7 @@ retn:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
vfree(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
@ -2601,10 +2564,7 @@ vfree(vp)
|
||||
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
if (vp->v_flag & VTBFREE) {
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag &= ~VTBFREE;
|
||||
}
|
||||
KASSERT((vp->v_flag & VFREE) == 0, ("vnode already free"));
|
||||
if (vp->v_flag & VAGE) {
|
||||
TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
|
||||
} else {
|
||||
@ -2625,13 +2585,9 @@ vbusy(vp)
|
||||
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
if (vp->v_flag & VTBFREE) {
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag &= ~VTBFREE;
|
||||
} else {
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
freevnodes--;
|
||||
}
|
||||
KASSERT((vp->v_flag & VFREE) != 0, ("vnode not free"));
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
freevnodes--;
|
||||
simple_unlock(&vnode_free_list_slock);
|
||||
vp->v_flag &= ~(VFREE|VAGE);
|
||||
splx(s);
|
||||
|
@ -83,7 +83,6 @@ static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
|
||||
|
||||
static void insmntque __P((struct vnode *vp, struct mount *mp));
|
||||
static void vclean __P((struct vnode *vp, int flags, struct proc *p));
|
||||
static void vfree __P((struct vnode *));
|
||||
static unsigned long numvnodes;
|
||||
SYSCTL_INT(_debug, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, "");
|
||||
|
||||
@ -97,7 +96,6 @@ int vttoif_tab[9] = {
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */
|
||||
struct tobefreelist vnode_tobefree_list; /* vnode free list */
|
||||
|
||||
static u_long wantfreevnodes = 25;
|
||||
SYSCTL_INT(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, "");
|
||||
@ -175,7 +173,6 @@ vntblinit()
|
||||
simple_lock_init(&mntid_slock);
|
||||
simple_lock_init(&spechash_slock);
|
||||
TAILQ_INIT(&vnode_free_list);
|
||||
TAILQ_INIT(&vnode_tobefree_list);
|
||||
simple_lock_init(&vnode_free_list_slock);
|
||||
vnode_zone = zinit("VNODE", sizeof (struct vnode), 0, 0, 5);
|
||||
/*
|
||||
@ -451,11 +448,10 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
vop_t **vops;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
int s;
|
||||
int s, count;
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp, *tvp, *nvp;
|
||||
struct vnode *vp = NULL;
|
||||
vm_object_t object;
|
||||
TAILQ_HEAD(freelst, vnode) vnode_tmp_list;
|
||||
|
||||
/*
|
||||
* We take the least recently used vnode from the freelist
|
||||
@ -466,22 +462,6 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
TAILQ_INIT(&vnode_tmp_list);
|
||||
|
||||
for (vp = TAILQ_FIRST(&vnode_tobefree_list); vp; vp = nvp) {
|
||||
nvp = TAILQ_NEXT(vp, v_freelist);
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
if (vp->v_flag & VAGE) {
|
||||
TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
|
||||
}
|
||||
vp->v_flag &= ~(VTBFREE|VAGE);
|
||||
vp->v_flag |= VFREE;
|
||||
if (vp->v_usecount)
|
||||
panic("tobe free vnode isn't");
|
||||
freevnodes++;
|
||||
}
|
||||
|
||||
if (wantfreevnodes && freevnodes < wantfreevnodes) {
|
||||
vp = NULL;
|
||||
@ -490,42 +470,29 @@ getnewvnode(tag, mp, vops, vpp)
|
||||
* XXX: this is only here to be backwards compatible
|
||||
*/
|
||||
vp = NULL;
|
||||
} else {
|
||||
for (vp = TAILQ_FIRST(&vnode_free_list); vp; vp = nvp) {
|
||||
nvp = TAILQ_NEXT(vp, v_freelist);
|
||||
if (!simple_lock_try(&vp->v_interlock))
|
||||
continue;
|
||||
if (vp->v_usecount)
|
||||
panic("free vnode isn't");
|
||||
|
||||
object = vp->v_object;
|
||||
if (object && (object->resident_page_count || object->ref_count)) {
|
||||
printf("object inconsistant state: RPC: %d, RC: %d\n",
|
||||
object->resident_page_count, object->ref_count);
|
||||
/* Don't recycle if it's caching some pages */
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
TAILQ_INSERT_TAIL(&vnode_tmp_list, vp, v_freelist);
|
||||
continue;
|
||||
} else if (LIST_FIRST(&vp->v_cache_src)) {
|
||||
/* Don't recycle if active in the namecache */
|
||||
simple_unlock(&vp->v_interlock);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else for (count = 0; count < freevnodes; count++) {
|
||||
vp = TAILQ_FIRST(&vnode_free_list);
|
||||
if (vp == NULL || vp->v_usecount)
|
||||
panic("getnewvnode: free vnode isn't");
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
/*
|
||||
* Don't recycle if active in the namecache or
|
||||
* if it still has cached pages or we cannot get
|
||||
* its interlock.
|
||||
*/
|
||||
object = vp->v_object;
|
||||
if (LIST_FIRST(&vp->v_cache_src) != NULL ||
|
||||
(object && (object->resident_page_count ||
|
||||
object->ref_count)) ||
|
||||
!simple_lock_try(&vp->v_interlock)) {
|
||||
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
|
||||
vp = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (tvp = TAILQ_FIRST(&vnode_tmp_list); tvp; tvp = nvp) {
|
||||
nvp = TAILQ_NEXT(tvp, v_freelist);
|
||||
TAILQ_REMOVE(&vnode_tmp_list, tvp, v_freelist);
|
||||
TAILQ_INSERT_TAIL(&vnode_free_list, tvp, v_freelist);
|
||||
simple_unlock(&tvp->v_interlock);
|
||||
}
|
||||
|
||||
if (vp) {
|
||||
vp->v_flag |= VDOOMED;
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
freevnodes--;
|
||||
simple_unlock(&vnode_free_list_slock);
|
||||
cache_purge(vp);
|
||||
@ -1868,8 +1835,8 @@ vgonel(vp, p)
|
||||
|
||||
/*
|
||||
* If it is on the freelist and not already at the head,
|
||||
* move it to the head of the list. The test of the back
|
||||
* pointer and the reference count of zero is because
|
||||
* move it to the head of the list. The test of the
|
||||
* VDOOMED flag and the reference count of zero is because
|
||||
* it will be removed from the free list by getnewvnode,
|
||||
* but will not have its reference count incremented until
|
||||
* after calling vgone. If the reference count were
|
||||
@ -1879,13 +1846,9 @@ vgonel(vp, p)
|
||||
if (vp->v_usecount == 0 && !(vp->v_flag & VDOOMED)) {
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
if (vp->v_flag & VFREE) {
|
||||
if (vp->v_flag & VFREE)
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
} else if (vp->v_flag & VTBFREE) {
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag &= ~VTBFREE;
|
||||
freevnodes++;
|
||||
} else
|
||||
else
|
||||
freevnodes++;
|
||||
vp->v_flag |= VFREE;
|
||||
TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
|
||||
@ -2593,7 +2556,7 @@ retn:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
vfree(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
@ -2601,10 +2564,7 @@ vfree(vp)
|
||||
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
if (vp->v_flag & VTBFREE) {
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag &= ~VTBFREE;
|
||||
}
|
||||
KASSERT((vp->v_flag & VFREE) == 0, ("vnode already free"));
|
||||
if (vp->v_flag & VAGE) {
|
||||
TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
|
||||
} else {
|
||||
@ -2625,13 +2585,9 @@ vbusy(vp)
|
||||
|
||||
s = splbio();
|
||||
simple_lock(&vnode_free_list_slock);
|
||||
if (vp->v_flag & VTBFREE) {
|
||||
TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag &= ~VTBFREE;
|
||||
} else {
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
freevnodes--;
|
||||
}
|
||||
KASSERT((vp->v_flag & VFREE) != 0, ("vnode not free"));
|
||||
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
|
||||
freevnodes--;
|
||||
simple_unlock(&vnode_free_list_slock);
|
||||
vp->v_flag &= ~(VFREE|VAGE);
|
||||
splx(s);
|
||||
|
@ -164,7 +164,7 @@ struct vnode {
|
||||
#define VOWANT 0x20000 /* a process is waiting for VOLOCK */
|
||||
#define VDOOMED 0x40000 /* This vnode is being recycled */
|
||||
#define VFREE 0x80000 /* This vnode is on the freelist */
|
||||
#define VTBFREE 0x100000 /* This vnode is on the to-be-freelist */
|
||||
/* open for business 0x100000 */
|
||||
#define VONWORKLST 0x200000 /* On syncer work-list */
|
||||
#define VMOUNT 0x400000 /* Mount in progress */
|
||||
|
||||
@ -298,7 +298,7 @@ extern void (*lease_updatetime) __P((int deltat));
|
||||
!((vp)->v_object->ref_count || (vp)->v_object->resident_page_count)))
|
||||
|
||||
#define VSHOULDBUSY(vp) \
|
||||
(((vp)->v_flag & (VFREE|VTBFREE)) && \
|
||||
(((vp)->v_flag & VFREE) && \
|
||||
((vp)->v_holdcnt || (vp)->v_usecount))
|
||||
|
||||
#endif /* _KERNEL */
|
||||
@ -613,6 +613,7 @@ int vop_defaultop __P((struct vop_generic_args *ap));
|
||||
int vop_null __P((struct vop_generic_args *ap));
|
||||
int vop_panic __P((struct vop_generic_args *ap));
|
||||
|
||||
void vfree __P((struct vnode *));
|
||||
void vput __P((struct vnode *vp));
|
||||
void vrele __P((struct vnode *vp));
|
||||
void vref __P((struct vnode *vp));
|
||||
@ -621,9 +622,6 @@ void vbusy __P((struct vnode *vp));
|
||||
extern vop_t **default_vnodeop_p;
|
||||
extern vop_t **spec_vnodeop_p;
|
||||
|
||||
extern TAILQ_HEAD(tobefreelist, vnode)
|
||||
vnode_tobefree_list; /* vnode free list */
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_SYS_VNODE_H_ */
|
||||
|
@ -1120,12 +1120,8 @@ vm_page_free_toq(vm_page_t m)
|
||||
) {
|
||||
struct vnode *vp = (struct vnode *)object->handle;
|
||||
|
||||
if (vp && VSHOULDFREE(vp)) {
|
||||
if ((vp->v_flag & (VTBFREE|VDOOMED|VFREE)) == 0) {
|
||||
TAILQ_INSERT_TAIL(&vnode_tobefree_list, vp, v_freelist);
|
||||
vp->v_flag |= VTBFREE;
|
||||
}
|
||||
}
|
||||
if (vp && VSHOULDFREE(vp))
|
||||
vfree(vp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user