xfs: refactor the ioend merging code

Introduce two nicely abstracted helper, which can be moved to the iomap
code later.  Also use list_first_entry_or_null to simplify the code a
bit.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Christoph Hellwig 2019-10-17 13:12:07 -07:00 committed by Darrick J. Wong
parent 4e087a3b31
commit 433dad94ec

View File

@ -116,6 +116,22 @@ xfs_destroy_ioend(
}
}
static void
xfs_destroy_ioends(
struct xfs_ioend *ioend,
int error)
{
struct list_head tmp;
list_replace_init(&ioend->io_list, &tmp);
xfs_destroy_ioend(ioend, error);
while ((ioend = list_first_entry_or_null(&tmp, struct xfs_ioend,
io_list))) {
list_del_init(&ioend->io_list);
xfs_destroy_ioend(ioend, error);
}
}
/*
* Fast and loose check if this write could update the on-disk inode size.
*/
@ -230,7 +246,6 @@ STATIC void
xfs_end_ioend(
struct xfs_ioend *ioend)
{
struct list_head ioend_list;
struct xfs_inode *ip = XFS_I(ioend->io_inode);
xfs_off_t offset = ioend->io_offset;
size_t size = ioend->io_size;
@ -275,16 +290,7 @@ xfs_end_ioend(
done:
if (ioend->io_append_trans)
error = xfs_setfilesize_ioend(ioend, error);
list_replace_init(&ioend->io_list, &ioend_list);
xfs_destroy_ioend(ioend, error);
while (!list_empty(&ioend_list)) {
ioend = list_first_entry(&ioend_list, struct xfs_ioend,
io_list);
list_del_init(&ioend->io_list);
xfs_destroy_ioend(ioend, error);
}
xfs_destroy_ioends(ioend, error);
memalloc_nofs_restore(nofs_flag);
}
@ -333,17 +339,18 @@ xfs_ioend_try_merge(
struct xfs_ioend *ioend,
struct list_head *more_ioends)
{
struct xfs_ioend *next_ioend;
struct xfs_ioend *next;
while (!list_empty(more_ioends)) {
next_ioend = list_first_entry(more_ioends, struct xfs_ioend,
io_list);
if (!xfs_ioend_can_merge(ioend, next_ioend))
INIT_LIST_HEAD(&ioend->io_list);
while ((next = list_first_entry_or_null(more_ioends, struct xfs_ioend,
io_list))) {
if (!xfs_ioend_can_merge(ioend, next))
break;
list_move_tail(&next_ioend->io_list, &ioend->io_list);
ioend->io_size += next_ioend->io_size;
if (next_ioend->io_append_trans)
xfs_ioend_merge_append_transactions(ioend, next_ioend);
list_move_tail(&next->io_list, &ioend->io_list);
ioend->io_size += next->io_size;
if (next->io_append_trans)
xfs_ioend_merge_append_transactions(ioend, next);
}
}
@ -366,29 +373,33 @@ xfs_ioend_compare(
return 0;
}
static void
xfs_sort_ioends(
struct list_head *ioend_list)
{
list_sort(NULL, ioend_list, xfs_ioend_compare);
}
/* Finish all pending io completions. */
void
xfs_end_io(
struct work_struct *work)
{
struct xfs_inode *ip;
struct xfs_inode *ip =
container_of(work, struct xfs_inode, i_ioend_work);
struct xfs_ioend *ioend;
struct list_head completion_list;
struct list_head tmp;
unsigned long flags;
ip = container_of(work, struct xfs_inode, i_ioend_work);
spin_lock_irqsave(&ip->i_ioend_lock, flags);
list_replace_init(&ip->i_ioend_list, &completion_list);
list_replace_init(&ip->i_ioend_list, &tmp);
spin_unlock_irqrestore(&ip->i_ioend_lock, flags);
list_sort(NULL, &completion_list, xfs_ioend_compare);
while (!list_empty(&completion_list)) {
ioend = list_first_entry(&completion_list, struct xfs_ioend,
io_list);
xfs_sort_ioends(&tmp);
while ((ioend = list_first_entry_or_null(&tmp, struct xfs_ioend,
io_list))) {
list_del_init(&ioend->io_list);
xfs_ioend_try_merge(ioend, &completion_list);
xfs_ioend_try_merge(ioend, &tmp);
xfs_end_ioend(ioend);
}
}