// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2025 Christoph Hellwig. * All Rights Reserved. */ #include "xfs_platform.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_bmap_util.h" #include "xfs_reflink.h" #include "xfs_zone_alloc.h" #include "xfs_ioend.h" static void xfs_ioend_put_open_zones( struct iomap_ioend *ioend) { struct iomap_ioend *tmp; /* * Put the open zone for all ioends merged into this one (if any). */ list_for_each_entry(tmp, &ioend->io_list, io_list) xfs_open_zone_put(tmp->io_private); /* * The main ioend might not have an open zone if the submission failed * before xfs_zone_alloc_and_submit got called. */ if (ioend->io_private) xfs_open_zone_put(ioend->io_private); } static void xfs_end_ioend_write( struct iomap_ioend *ioend) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_mount *mp = ip->i_mount; bool is_zoned = xfs_is_zoned_inode(ip); xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; unsigned int nofs_flag; int error; /* * We can allocate memory here while doing writeback on behalf of * memory reclaim. To avoid memory allocation deadlocks set the * task-wide nofs context for the following operations. */ nofs_flag = memalloc_nofs_save(); /* * Just clean up the in-memory structures if the fs has been shut down. */ if (xfs_is_shutdown(mp)) { error = -EIO; goto done; } /* * Clean up all COW blocks and underlying data fork delalloc blocks on * I/O error. The delalloc punch is required because this ioend was * mapped to blocks in the COW fork and the associated pages are no * longer dirty. If we don't remove delalloc blocks here, they become * stale and can corrupt free space accounting on unmount. */ error = blk_status_to_errno(ioend->io_bio.bi_status); if (unlikely(error)) { /* * Zoned writes update the in-core open zone accounting before * I/O submission. A failed write leaves that state * inconsistent, so shut down the filesystem instead of letting * later writers wait forever for open zone space to become * available. */ if (is_zoned) { xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); goto done; } if (ioend->io_flags & IOMAP_IOEND_SHARED) { ASSERT(!is_zoned); xfs_reflink_cancel_cow_range(ip, offset, size, true); xfs_bmap_punch_delalloc_range(ip, XFS_DATA_FORK, offset, offset + size, NULL); } goto done; } /* * Success: commit the COW or unwritten blocks if needed. */ if (is_zoned) error = xfs_zoned_end_io(ip, offset, size, ioend->io_sector, ioend->io_private, NULLFSBLOCK); else if (ioend->io_flags & IOMAP_IOEND_SHARED) error = xfs_reflink_end_cow(ip, offset, size); else if (ioend->io_flags & IOMAP_IOEND_UNWRITTEN) error = xfs_iomap_write_unwritten(ip, offset, size, false); if (!error && !(ioend->io_flags & IOMAP_IOEND_DIRECT) && xfs_ioend_is_append(ioend)) error = xfs_setfilesize(ip, offset, size); done: if (is_zoned) xfs_ioend_put_open_zones(ioend); iomap_finish_ioends(ioend, error); memalloc_nofs_restore(nofs_flag); } /* * Finish all pending IO completions that require transactional modifications. * * We try to merge physical and logically contiguous ioends before completion to * minimise the number of transactions we need to perform during IO completion. * Both unwritten extent conversion and COW remapping need to iterate and modify * one physical extent at a time, so we gain nothing by merging physically * discontiguous extents here. * * The ioend chain length that we can be processing here is largely unbound in * length and we may have to perform significant amounts of work on each ioend * to complete it. Hence we have to be careful about holding the CPU for too * long in this loop. */ void xfs_end_io( struct work_struct *work) { struct xfs_inode *ip = container_of(work, struct xfs_inode, i_ioend_work); struct iomap_ioend *ioend; struct list_head tmp; unsigned long flags; spin_lock_irqsave(&ip->i_ioend_lock, flags); list_replace_init(&ip->i_ioend_list, &tmp); spin_unlock_irqrestore(&ip->i_ioend_lock, flags); iomap_sort_ioends(&tmp); while ((ioend = list_first_entry_or_null(&tmp, struct iomap_ioend, io_list))) { list_del_init(&ioend->io_list); iomap_ioend_try_merge(ioend, &tmp); if (bio_op(&ioend->io_bio) == REQ_OP_READ) iomap_finish_ioends(ioend, blk_status_to_errno(ioend->io_bio.bi_status)); else xfs_end_ioend_write(ioend); cond_resched(); } } void xfs_end_bio( struct bio *bio) { struct iomap_ioend *ioend = iomap_ioend_from_bio(bio); struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_mount *mp = ip->i_mount; unsigned long flags; /* * For Appends record the actually written block number and set the * boundary flag if needed. */ if (IS_ENABLED(CONFIG_XFS_RT) && bio_is_zone_append(bio)) { ioend->io_sector = bio->bi_iter.bi_sector; xfs_mark_rtg_boundary(ioend); } spin_lock_irqsave(&ip->i_ioend_lock, flags); if (list_empty(&ip->i_ioend_list)) WARN_ON_ONCE(!queue_work(mp->m_unwritten_workqueue, &ip->i_ioend_work)); list_add_tail(&ioend->io_list, &ip->i_ioend_list); spin_unlock_irqrestore(&ip->i_ioend_lock, flags); }