/* * This is called by the efd item code below to release references to * the given efi item. Each efd calls this with the number of * extents that it has logged, and when the sum of these reaches * the total number of extents logged by this efi item we can free * the efi item. * * Freeing the efi item requires that we remove it from the AIL. * We'll use the AIL lock to protect our counters as well as * the removal from the AIL. */ void xfs_efi_release(xfs_efi_log_item_t *efip, uint nextents) { xfs_mount_t *mp; int extents_left; SPLDECL(s); mp = efip->efi_item.li_mountp; ASSERT(efip->efi_next_extent > 0); ASSERT(efip->efi_flags & XFS_EFI_COMMITTED); AIL_LOCK(mp, s); ASSERT(efip->efi_next_extent >= nextents); efip->efi_next_extent -= nextents; extents_left = efip->efi_next_extent; if (extents_left == 0) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); xfs_efi_item_free(efip); } else { AIL_UNLOCK(mp, s); } }
/* * This is called when the transaction that should be committing the * EFD corresponding to the given EFI is aborted. The committed and * canceled flags are used to coordinate the freeing of the EFI and * the references by the transaction that committed it. */ STATIC void xfs_efi_cancel( xfs_efi_log_item_t *efip) { int nexts; int size; xfs_mount_t *mp; SPLDECL(s); mp = efip->efi_item.li_mountp; AIL_LOCK(mp, s); if (efip->efi_flags & XFS_EFI_COMMITTED) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); nexts = efip->efi_format.efi_nextents; if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { size = sizeof(xfs_efi_log_item_t); size += (nexts - 1) * sizeof(xfs_extent_t); kmem_free(efip, size); } else { kmem_zone_free(xfs_efi_zone, efip); } } else { efip->efi_flags |= XFS_EFI_CANCELED; AIL_UNLOCK(mp, s); } return; }
/* * like unpin only we have to also clear the xaction descriptor * pointing the log item if we free the item. This routine duplicates * unpin because efi_flags is protected by the AIL lock. Freeing * the descriptor and then calling unpin would force us to drop the AIL * lock which would open up a race condition. */ STATIC void xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) { xfs_mount_t *mp; xfs_log_item_desc_t *lidp; SPLDECL(s); mp = efip->efi_item.li_mountp; AIL_LOCK(mp, s); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * free the xaction descriptor pointing to this item */ lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip); xfs_trans_free_item(tp, lidp); /* * pull the item off the AIL. * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; AIL_UNLOCK(mp, s); } }
/*ARGSUSED*/ void xfs_iflush_done( xfs_buf_t *bp, xfs_inode_log_item_t *iip) { xfs_inode_t *ip; SPLDECL(s); ip = iip->ili_inode; /* * We only want to pull the item from the AIL if it is * actually there and its location in the log has not * changed since we started the flush. Thus, we only bother * if the ili_logged flag is set and the inode's lsn has not * changed. First we check the lsn outside * the lock since it's cheaper, and then we recheck while * holding the lock before removing the inode from the AIL. */ if (iip->ili_logged && (iip->ili_item.li_lsn == iip->ili_flush_lsn)) { AIL_LOCK(ip->i_mount, s); if (iip->ili_item.li_lsn == iip->ili_flush_lsn) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(ip->i_mount, (xfs_log_item_t*)iip, s); } else { AIL_UNLOCK(ip->i_mount, s); } } iip->ili_logged = 0; /* * Clear the ili_last_fields bits now that we know that the * data corresponding to them is safely on disk. */ iip->ili_last_fields = 0; /* * Release the inode's flush lock since we're done with it. */ xfs_ifunlock(ip); return; }
/* * This is called to unpin the buffer associated with the buf log * item which was previously pinned with a call to xfs_buf_item_pin(). * Just call bunpin() on the buffer to do this. * * Also drop the reference to the buf item for the current transaction. * If the XFS_BLI_STALE flag is set and we are the last reference, * then free up the buf log item and unlock the buffer. */ void xfs_buf_item_unpin( xfs_buf_log_item_t *bip, int stale) { xfs_mount_t *mp; xfs_buf_t *bp; int freed; SPLDECL(s); bp = bip->bli_buf; ASSERT(bp != NULL); ASSERT(XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *) == bip); ASSERT(atomic_read(&bip->bli_refcount) > 0); xfs_buf_item_trace("UNPIN", bip); xfs_buftrace("XFS_UNPIN", bp); freed = atomic_dec_and_test(&bip->bli_refcount); mp = bip->bli_item.li_mountp; xfs_bunpin(bp); if (freed && stale) { ASSERT(bip->bli_flags & XFS_BLI_STALE); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); ASSERT(XFS_BUF_ISSTALE(bp)); ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); xfs_buf_item_trace("UNPIN STALE", bip); xfs_buftrace("XFS_UNPIN STALE", bp); /* * If we get called here because of an IO error, we may * or may not have the item on the AIL. xfs_trans_delete_ail() * will take care of that situation. * xfs_trans_delete_ail() drops the AIL lock. */ if (bip->bli_flags & XFS_BLI_STALE_INODE) { xfs_buf_do_callbacks(bp, (xfs_log_item_t *)bip); XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); } else { AIL_LOCK(mp,s); xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); xfs_buf_item_relse(bp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); } xfs_buf_relse(bp); }
/*ARGSUSED*/ STATIC xfs_lsn_t xfs_qm_qoffend_logitem_committed( xfs_qoff_logitem_t *qfe, xfs_lsn_t lsn) { xfs_qoff_logitem_t *qfs; qfs = qfe->qql_start_lip; spin_lock(&qfs->qql_item.li_mountp->m_ail_lock); /* * Delete the qoff-start logitem from the AIL. * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs); kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); return (xfs_lsn_t)-1; }
/*ARGSUSED*/ STATIC void xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) { xfs_mount_t *mp; mp = efip->efi_item.li_mountp; spin_lock(&mp->m_ail_lock); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; spin_unlock(&mp->m_ail_lock); } }
/*ARGSUSED*/ STATIC void xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) { xfs_mount_t *mp; SPLDECL(s); mp = efip->efi_item.li_mountp; AIL_LOCK(mp, s); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; AIL_UNLOCK(mp, s); } }
/* * like unpin only we have to also clear the xaction descriptor * pointing the log item if we free the item. This routine duplicates * unpin because efi_flags is protected by the AIL lock. Freeing * the descriptor and then calling unpin would force us to drop the AIL * lock which would open up a race condition. */ STATIC void xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) { int nexts; int size; xfs_mount_t *mp; xfs_log_item_desc_t *lidp; SPLDECL(s); mp = efip->efi_item.li_mountp; AIL_LOCK(mp, s); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * free the xaction descriptor pointing to this item */ lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip); xfs_trans_free_item(tp, lidp); /* * pull the item off the AIL. * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); /* * now free the item itself */ nexts = efip->efi_format.efi_nextents; if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { size = sizeof(xfs_efi_log_item_t); size += (nexts - 1) * sizeof(xfs_extent_t); kmem_free(efip, size); } else { kmem_zone_free(xfs_efi_zone, efip); } } else { efip->efi_flags |= XFS_EFI_COMMITTED; AIL_UNLOCK(mp, s); } return; }
/* * This is the inode flushing abort routine. It is called * from xfs_iflush when the filesystem is shutting down to clean * up the inode state. * It is responsible for removing the inode item * from the AIL if it has not been re-logged, and unlocking the inode's * flush lock. */ void xfs_iflush_abort( xfs_inode_t *ip) { xfs_inode_log_item_t *iip; xfs_mount_t *mp; SPLDECL(s); iip = ip->i_itemp; mp = ip->i_mount; if (iip) { if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { AIL_LOCK(mp, s); if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip, s); } else AIL_UNLOCK(mp, s); } iip->ili_logged = 0; /* * Clear the ili_last_fields bits now that we know that the * data corresponding to them is safely on disk. */ iip->ili_last_fields = 0; /* * Clear the inode logging fields so no more flushes are * attempted. */ iip->ili_format.ilf_fields = 0; } /* * Release the inode's flush lock since we're done with it. */ xfs_ifunlock(ip); }
/* * This is called by the efd item code below to release references to * the given efi item. Each efd calls this with the number of * extents that it has logged, and when the sum of these reaches * the total number of extents logged by this efi item we can free * the efi item. * * Freeing the efi item requires that we remove it from the AIL. * We'll use the AIL lock to protect our counters as well as * the removal from the AIL. */ void xfs_efi_release(xfs_efi_log_item_t *efip, uint nextents) { xfs_mount_t *mp; int extents_left; uint size; int nexts; SPLDECL(s); mp = efip->efi_item.li_mountp; ASSERT(efip->efi_next_extent > 0); ASSERT(efip->efi_flags & XFS_EFI_COMMITTED); AIL_LOCK(mp, s); ASSERT(efip->efi_next_extent >= nextents); efip->efi_next_extent -= nextents; extents_left = efip->efi_next_extent; if (extents_left == 0) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); } else { AIL_UNLOCK(mp, s); } if (extents_left == 0) { nexts = efip->efi_format.efi_nextents; if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { size = sizeof(xfs_efi_log_item_t); size += (nexts - 1) * sizeof(xfs_extent_t); kmem_free(efip, size); } else { kmem_zone_free(xfs_efi_zone, efip); } } }
/*ARGSUSED*/ STATIC void xfs_qm_dqflush_done( xfs_buf_t *bp, xfs_dq_logitem_t *qip) { xfs_dquot_t *dqp; SPLDECL(s); dqp = qip->qli_dquot; /* * We only want to pull the item from the AIL if its * location in the log has not changed since we started the flush. * Thus, we only bother if the dquot's lsn has * not changed. First we check the lsn outside the lock * since it's cheaper, and then we recheck while * holding the lock before removing the dquot from the AIL. */ if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && qip->qli_item.li_lsn == qip->qli_flush_lsn) { AIL_LOCK(dqp->q_mount, s); /* * xfs_trans_delete_ail() drops the AIL lock. */ if (qip->qli_item.li_lsn == qip->qli_flush_lsn) xfs_trans_delete_ail(dqp->q_mount, (xfs_log_item_t*)qip, s); else AIL_UNLOCK(dqp->q_mount, s); } /* * Release the dq's flush lock since we're done with it. */ xfs_dqfunlock(dqp); }