/* * purge a vnode from the cache * At this point the vnode is guaranteed to have no references (vn_count == 0) * The caller has to make sure that there are no ways someone could * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock). */ void vn_purge( struct vnode *vp, vmap_t *vmap) { vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address); again: /* * Check whether vp has already been reclaimed since our caller * sampled its version while holding a filesystem cache lock that * its VOP_RECLAIM function acquires. */ VN_LOCK(vp); if (vp->v_number != vmap->v_number) { VN_UNLOCK(vp, 0); return; } /* * If vp is being reclaimed or inactivated, wait until it is inert, * then proceed. Can't assume that vnode is actually reclaimed * just because the reclaimed flag is asserted -- a vn_alloc * reclaim can fail. */ if (vp->v_flag & (VINACT | VRECLM)) { ASSERT(vn_count(vp) == 0); vp->v_flag |= VWAIT; sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0); goto again; } /* * Another process could have raced in and gotten this vnode... */ if (vn_count(vp) > 0) { VN_UNLOCK(vp, 0); return; } XFS_STATS_DEC(vn_active); vp->v_flag |= VRECLM; VN_UNLOCK(vp, 0); /* * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells * vp's filesystem to flush and invalidate all cached resources. * When vn_reclaim returns, vp should have no private data, * either in a system cache or attached to v_data. */ if (vn_reclaim(vp) != 0) panic("vn_purge: cannot reclaim"); /* * Wakeup anyone waiting for vp to be reclaimed. */ vn_wakeup(vp); }
static void __xfs_inode_free( struct xfs_inode *ip) { /* asserts to verify all state is correct here */ ASSERT(atomic_read(&ip->i_pincount) == 0); XFS_STATS_DEC(ip->i_mount, vn_active); call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback); }
/* * This is called to free all the memory associated with a dquot */ void xfs_qm_dqdestroy( xfs_dquot_t *dqp) { ASSERT(list_empty(&dqp->q_lru)); mutex_destroy(&dqp->q_qlock); kmem_zone_free(xfs_qm_dqzone, dqp); XFS_STATS_DEC(xs_qm_dquot); }
/* * This is called to free all the memory associated with a dquot */ void xfs_qm_dqdestroy( xfs_dquot_t *dqp) { ASSERT(list_empty(&dqp->q_lru)); kmem_free(dqp->q_logitem.qli_item.li_lv_shadow); mutex_destroy(&dqp->q_qlock); XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot); kmem_zone_free(xfs_qm_dqzone, dqp); }
void xfs_inode_free( struct xfs_inode *ip) { switch (ip->i_d.di_mode & S_IFMT) { case S_IFREG: case S_IFDIR: case S_IFLNK: xfs_idestroy_fork(ip, XFS_DATA_FORK); break; } if (ip->i_afp) xfs_idestroy_fork(ip, XFS_ATTR_FORK); if (ip->i_itemp) { ASSERT(!(ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL)); xfs_inode_item_destroy(ip); ip->i_itemp = NULL; } /* * Because we use RCU freeing we need to ensure the inode always * appears to be reclaimed with an invalid inode number when in the * free state. The ip->i_flags_lock provides the barrier against lookup * races. */ spin_lock(&ip->i_flags_lock); ip->i_flags = XFS_IRECLAIM; ip->i_ino = 0; spin_unlock(&ip->i_flags_lock); /* asserts to verify all state is correct here */ ASSERT(atomic_read(&ip->i_pincount) == 0); ASSERT(!xfs_isiflocked(ip)); XFS_STATS_DEC(vn_active); call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback); }
STATIC void xfs_qm_dqreclaim_one( struct xfs_dquot *dqp, struct list_head *buffer_list, struct list_head *dispose_list) { struct xfs_mount *mp = dqp->q_mount; struct xfs_quotainfo *qi = mp->m_quotainfo; int error; if (!xfs_dqlock_nowait(dqp)) goto out_move_tail; /* * This dquot has acquired a reference in the meantime remove it from * the freelist and try again. */ if (dqp->q_nrefs) { xfs_dqunlock(dqp); trace_xfs_dqreclaim_want(dqp); XFS_STATS_INC(xs_qm_dqwants); list_del_init(&dqp->q_lru); qi->qi_lru_count--; XFS_STATS_DEC(xs_qm_dquot_unused); return; } /* * Try to grab the flush lock. If this dquot is in the process of * getting flushed to disk, we don't want to reclaim it. */ if (!xfs_dqflock_nowait(dqp)) goto out_unlock_move_tail; if (XFS_DQ_IS_DIRTY(dqp)) { struct xfs_buf *bp = NULL; trace_xfs_dqreclaim_dirty(dqp); error = xfs_qm_dqflush(dqp, &bp); if (error) { xfs_warn(mp, "%s: dquot %p flush failed", __func__, dqp); goto out_unlock_move_tail; } xfs_buf_delwri_queue(bp, buffer_list); xfs_buf_relse(bp); /* * Give the dquot another try on the freelist, as the * flushing will take some time. */ goto out_unlock_move_tail; } xfs_dqfunlock(dqp); /* * Prevent lookups now that we are past the point of no return. */ dqp->dq_flags |= XFS_DQ_FREEING; xfs_dqunlock(dqp); ASSERT(dqp->q_nrefs == 0); list_move_tail(&dqp->q_lru, dispose_list); qi->qi_lru_count--; XFS_STATS_DEC(xs_qm_dquot_unused); trace_xfs_dqreclaim_done(dqp); XFS_STATS_INC(xs_qm_dqreclaims); return; /* * Move the dquot to the tail of the list so that we don't spin on it. */ out_unlock_move_tail: xfs_dqunlock(dqp); out_move_tail: list_move_tail(&dqp->q_lru, &qi->qi_lru_list); trace_xfs_dqreclaim_busy(dqp); XFS_STATS_INC(xs_qm_dqreclaim_misses); }
/* * Purge a dquot from all tracking data structures and free it. */ STATIC int xfs_qm_dqpurge( struct xfs_dquot *dqp, void *data) { struct xfs_mount *mp = dqp->q_mount; struct xfs_quotainfo *qi = mp->m_quotainfo; struct xfs_dquot *gdqp = NULL; xfs_dqlock(dqp); if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) { xfs_dqunlock(dqp); return EAGAIN; } /* * If this quota has a group hint attached, prepare for releasing it * now. */ gdqp = dqp->q_gdquot; if (gdqp) { xfs_dqlock(gdqp); dqp->q_gdquot = NULL; } dqp->dq_flags |= XFS_DQ_FREEING; xfs_dqflock(dqp); /* * If we are turning this type of quotas off, we don't care * about the dirty metadata sitting in this dquot. OTOH, if * we're unmounting, we do care, so we flush it and wait. */ if (XFS_DQ_IS_DIRTY(dqp)) { struct xfs_buf *bp = NULL; int error; /* * We don't care about getting disk errors here. We need * to purge this dquot anyway, so we go ahead regardless. */ error = xfs_qm_dqflush(dqp, &bp); if (error) { xfs_warn(mp, "%s: dquot %p flush failed", __func__, dqp); } else { error = xfs_bwrite(bp); xfs_buf_relse(bp); } xfs_dqflock(dqp); } ASSERT(atomic_read(&dqp->q_pincount) == 0); ASSERT(XFS_FORCED_SHUTDOWN(mp) || !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL)); xfs_dqfunlock(dqp); xfs_dqunlock(dqp); radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags), be32_to_cpu(dqp->q_core.d_id)); qi->qi_dquots--; /* * We move dquots to the freelist as soon as their reference count * hits zero, so it really should be on the freelist here. */ mutex_lock(&qi->qi_lru_lock); ASSERT(!list_empty(&dqp->q_lru)); list_del_init(&dqp->q_lru); qi->qi_lru_count--; XFS_STATS_DEC(xs_qm_dquot_unused); mutex_unlock(&qi->qi_lru_lock); xfs_qm_dqdestroy(dqp); if (gdqp) xfs_qm_dqput(gdqp); return 0; }