| // 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); |
| } |