Commit a69a1dc2 authored by Dave Chinner's avatar Dave Chinner Committed by Darrick J. Wong

xfs: factor xfs_iflush_done

xfs_iflush_done() does 3 distinct operations to the inodes attached
to the buffer. Separate these operations out into functions so that
it is easier to modify these operations independently in future.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
parent 5717ea4d
...@@ -641,101 +641,63 @@ xfs_inode_item_destroy( ...@@ -641,101 +641,63 @@ xfs_inode_item_destroy(
/* /*
* This is the inode flushing I/O completion routine. It is called * We only want to pull the item from the AIL if it is actually there
* from interrupt level when the buffer containing the inode is * and its location in the log has not changed since we started the
* flushed to disk. It is responsible for removing the inode item * flush. Thus, we only bother if the inode's lsn has not changed.
* from the AIL if it has not been re-logged, and unlocking the inode's
* flush lock.
*
* To reduce AIL lock traffic as much as possible, we scan the buffer log item
* list for other inodes that will run this function. We remove them from the
* buffer list so we can process all the inode IO completions in one AIL lock
* traversal.
*
* Note: Now that we attach the log item to the buffer when we first log the
* inode in memory, we can have unflushed inodes on the buffer list here. These
* inodes will have a zero ili_last_fields, so skip over them here.
*/ */
void static void
xfs_iflush_done( xfs_iflush_ail_updates(
struct xfs_buf *bp) struct xfs_ail *ailp,
struct list_head *list)
{ {
struct xfs_inode_log_item *iip; struct xfs_log_item *lip;
struct xfs_log_item *lip, *n; xfs_lsn_t tail_lsn = 0;
struct xfs_ail *ailp = bp->b_mount->m_ail;
int need_ail = 0;
LIST_HEAD(tmp);
/* /* this is an opencoded batch version of xfs_trans_ail_delete */
* Pull the attached inodes from the buffer one at a time and take the spin_lock(&ailp->ail_lock);
* appropriate action on them. list_for_each_entry(lip, list, li_bio_list) {
*/ xfs_lsn_t lsn;
list_for_each_entry_safe(lip, n, &bp->b_li_list, li_bio_list) {
iip = INODE_ITEM(lip);
if (xfs_iflags_test(iip->ili_inode, XFS_ISTALE)) {
xfs_iflush_abort(iip->ili_inode);
continue;
}
if (!iip->ili_last_fields) clear_bit(XFS_LI_FAILED, &lip->li_flags);
if (INODE_ITEM(lip)->ili_flush_lsn != lip->li_lsn)
continue; continue;
list_move_tail(&lip->li_bio_list, &tmp); lsn = xfs_ail_delete_one(ailp, lip);
if (!tail_lsn && lsn)
/* Do an unlocked check for needing the AIL lock. */ tail_lsn = lsn;
if (iip->ili_flush_lsn == lip->li_lsn ||
test_bit(XFS_LI_FAILED, &lip->li_flags))
need_ail++;
} }
xfs_ail_update_finish(ailp, tail_lsn);
}
/* /*
* We only want to pull the item from the AIL if it is actually there * Walk the list of inodes that have completed their IOs. If they are clean
* and its location in the log has not changed since we started the * remove them from the list and dissociate them from the buffer. Buffers that
* flush. Thus, we only bother if the inode's lsn has not changed. * are still dirty remain linked to the buffer and on the list. Caller must
*/ * handle them appropriately.
if (need_ail) { */
xfs_lsn_t tail_lsn = 0; static void
xfs_iflush_finish(
/* this is an opencoded batch version of xfs_trans_ail_delete */ struct xfs_buf *bp,
spin_lock(&ailp->ail_lock); struct list_head *list)
list_for_each_entry(lip, &tmp, li_bio_list) { {
clear_bit(XFS_LI_FAILED, &lip->li_flags); struct xfs_log_item *lip, *n;
if (lip->li_lsn == INODE_ITEM(lip)->ili_flush_lsn) {
xfs_lsn_t lsn = xfs_ail_delete_one(ailp, lip);
if (!tail_lsn && lsn)
tail_lsn = lsn;
}
}
xfs_ail_update_finish(ailp, tail_lsn);
}
/* list_for_each_entry_safe(lip, n, list, li_bio_list) {
* Clean up and unlock the flush lock now we are done. We can clear the struct xfs_inode_log_item *iip = INODE_ITEM(lip);
* ili_last_fields bits now that we know that the data corresponding to
* them is safely on disk.
*/
list_for_each_entry_safe(lip, n, &tmp, li_bio_list) {
bool drop_buffer = false; bool drop_buffer = false;
list_del_init(&lip->li_bio_list);
iip = INODE_ITEM(lip);
spin_lock(&iip->ili_lock); spin_lock(&iip->ili_lock);
/* /*
* Remove the reference to the cluster buffer if the inode is * Remove the reference to the cluster buffer if the inode is
* clean in memory. Drop the buffer reference once we've dropped * clean in memory and drop the buffer reference once we've
* the locks we hold. If the inode is dirty in memory, we need * dropped the locks we hold.
* to put the inode item back on the buffer list for another
* pass through the flush machinery.
*/ */
ASSERT(iip->ili_item.li_buf == bp); ASSERT(iip->ili_item.li_buf == bp);
if (!iip->ili_fields) { if (!iip->ili_fields) {
iip->ili_item.li_buf = NULL; iip->ili_item.li_buf = NULL;
list_del_init(&lip->li_bio_list);
drop_buffer = true; drop_buffer = true;
} else {
list_add(&lip->li_bio_list, &bp->b_li_list);
} }
iip->ili_last_fields = 0; iip->ili_last_fields = 0;
iip->ili_flush_lsn = 0; iip->ili_flush_lsn = 0;
...@@ -746,6 +708,51 @@ xfs_iflush_done( ...@@ -746,6 +708,51 @@ xfs_iflush_done(
} }
} }
/*
* Inode buffer IO completion routine. It is responsible for removing inodes
* attached to the buffer from the AIL if they have not been re-logged, as well
* as completing the flush and unlocking the inode.
*/
void
xfs_iflush_done(
struct xfs_buf *bp)
{
struct xfs_log_item *lip, *n;
LIST_HEAD(flushed_inodes);
LIST_HEAD(ail_updates);
/*
* Pull the attached inodes from the buffer one at a time and take the
* appropriate action on them.
*/
list_for_each_entry_safe(lip, n, &bp->b_li_list, li_bio_list) {
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
if (xfs_iflags_test(iip->ili_inode, XFS_ISTALE)) {
xfs_iflush_abort(iip->ili_inode);
continue;
}
if (!iip->ili_last_fields)
continue;
/* Do an unlocked check for needing the AIL lock. */
if (iip->ili_flush_lsn == lip->li_lsn ||
test_bit(XFS_LI_FAILED, &lip->li_flags))
list_move_tail(&lip->li_bio_list, &ail_updates);
else
list_move_tail(&lip->li_bio_list, &flushed_inodes);
}
if (!list_empty(&ail_updates)) {
xfs_iflush_ail_updates(bp->b_mount->m_ail, &ail_updates);
list_splice_tail(&ail_updates, &flushed_inodes);
}
xfs_iflush_finish(bp, &flushed_inodes);
if (!list_empty(&flushed_inodes))
list_splice_tail(&flushed_inodes, &bp->b_li_list);
}
/* /*
* This is the inode flushing abort routine. It is called from xfs_iflush when * 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 * the filesystem is shutting down to clean up the inode state. It is
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment