VFS sometimes is unable to inactivate a vnode when vnode use count
goes to zero. E.g., the vnode might be only shared-locked at the time of vput() call. Such vnodes are kept in the hash, so they can be found later. If ffs_valloc() allocated an inode that has its vnode cached in hash, and still owing the inactivation, then vget() call from ffs_valloc() clears VI_OWEINACT, and then the vnode is reused for the newly allocated inode. The problem is, the vnode is not reclaimed before it is put to the new use. ffs_valloc() recycles vnode vm object, but this is not enough. In particular, at least v_vflag should be cleared, and several bits of UFS state need to be removed. It is very inconvenient to call vgone() at this point. Instead, move some parts of ufs_reclaim() into helper function ufs_prepare_reclaim(), and call the helper from VOP_RECLAIM and ffs_valloc(). Reviewed by: mckusick Tested by: pho MFC after: 3 weeks
This commit is contained in:
parent
16a174b5c5
commit
d9ca1af7ed
@ -1012,8 +1012,9 @@ dup_alloc:
|
||||
ip->i_din2->di_birthtime = ts.tv_sec;
|
||||
ip->i_din2->di_birthnsec = ts.tv_nsec;
|
||||
}
|
||||
ufs_prepare_reclaim(*vpp);
|
||||
ip->i_flag = 0;
|
||||
vnode_destroy_vobject(*vpp);
|
||||
(*vpp)->v_vflag = 0;
|
||||
(*vpp)->v_type = VNON;
|
||||
if (fs->fs_magic == FS_UFS2_MAGIC)
|
||||
(*vpp)->v_op = &ffs_vnodeops2;
|
||||
|
@ -76,6 +76,7 @@ int ufs_inactive(struct vop_inactive_args *);
|
||||
int ufs_init(struct vfsconf *);
|
||||
void ufs_itimes(struct vnode *vp);
|
||||
int ufs_lookup(struct vop_cachedlookup_args *);
|
||||
void ufs_prepare_reclaim(struct vnode *vp);
|
||||
int ufs_readdir(struct vop_readdir_args *);
|
||||
int ufs_reclaim(struct vop_reclaim_args *);
|
||||
void ffs_snapgone(struct inode *);
|
||||
|
@ -172,6 +172,31 @@ out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
ufs_prepare_reclaim(struct vnode *vp)
|
||||
{
|
||||
struct inode *ip;
|
||||
#ifdef QUOTA
|
||||
int i;
|
||||
#endif
|
||||
|
||||
ip = VTOI(vp);
|
||||
|
||||
vnode_destroy_vobject(vp);
|
||||
#ifdef QUOTA
|
||||
for (i = 0; i < MAXQUOTAS; i++) {
|
||||
if (ip->i_dquot[i] != NODQUOT) {
|
||||
dqrele(vp, ip->i_dquot[i]);
|
||||
ip->i_dquot[i] = NODQUOT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef UFS_DIRHASH
|
||||
if (ip->i_dirhash != NULL)
|
||||
ufsdirhash_free(ip);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim an inode so that it can be used for other purposes.
|
||||
*/
|
||||
@ -185,14 +210,9 @@ ufs_reclaim(ap)
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct inode *ip = VTOI(vp);
|
||||
struct ufsmount *ump = ip->i_ump;
|
||||
#ifdef QUOTA
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Destroy the vm object and flush associated pages.
|
||||
*/
|
||||
vnode_destroy_vobject(vp);
|
||||
ufs_prepare_reclaim(vp);
|
||||
|
||||
if (ip->i_flag & IN_LAZYMOD)
|
||||
ip->i_flag |= IN_MODIFIED;
|
||||
UFS_UPDATE(vp, 0);
|
||||
@ -200,21 +220,7 @@ ufs_reclaim(ap)
|
||||
* Remove the inode from its hash chain.
|
||||
*/
|
||||
vfs_hash_remove(vp);
|
||||
/*
|
||||
* Purge old data structures associated with the inode.
|
||||
*/
|
||||
#ifdef QUOTA
|
||||
for (i = 0; i < MAXQUOTAS; i++) {
|
||||
if (ip->i_dquot[i] != NODQUOT) {
|
||||
dqrele(vp, ip->i_dquot[i]);
|
||||
ip->i_dquot[i] = NODQUOT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef UFS_DIRHASH
|
||||
if (ip->i_dirhash != NULL)
|
||||
ufsdirhash_free(ip);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lock the clearing of v_data so ffs_lock() can inspect it
|
||||
* prior to obtaining the lock.
|
||||
|
Loading…
x
Reference in New Issue
Block a user