From: "Darrick J. Wong" <djwong@kernel.org>
To: Christoph Hellwig <hch@lst.de>
Cc: Carlos Maiolino <cem@kernel.org>,
Hans Holmberg <hans.holmberg@wdc.com>,
linux-xfs@vger.kernel.org
Subject: Re: [PATCH 11/45] xfs: move xfs_bmapi_reserve_delalloc to xfs_iomap.c
Date: Wed, 19 Feb 2025 13:47:46 -0800 [thread overview]
Message-ID: <20250219214746.GW21808@frogsfrogsfrogs> (raw)
In-Reply-To: <20250218081153.3889537-12-hch@lst.de>
On Tue, Feb 18, 2025 at 09:10:14AM +0100, Christoph Hellwig wrote:
> Delalloc reservations are not supported in userspace, and thus it doesn't
> make sense to share this helper with xfsprogs.c. Move it to xfs_iomap.c
> toward the two callers.
>
> Note that there rest of the delalloc handling should probably eventually
> also move out of xfs_bmap.c, but that will require a bit more surgery.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Looks fine,
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> ---
> fs/xfs/libxfs/xfs_bmap.c | 295 +--------------------------------------
> fs/xfs/libxfs/xfs_bmap.h | 5 +-
> fs/xfs/xfs_iomap.c | 279 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 287 insertions(+), 292 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 0ef19f1469ec..5b17e59ed5b8 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -34,7 +34,6 @@
> #include "xfs_ag.h"
> #include "xfs_ag_resv.h"
> #include "xfs_refcount.h"
> -#include "xfs_icache.h"
> #include "xfs_iomap.h"
> #include "xfs_health.h"
> #include "xfs_bmap_item.h"
> @@ -171,18 +170,16 @@ xfs_bmbt_update(
> * Compute the worst-case number of indirect blocks that will be used
> * for ip's delayed extent of length "len".
> */
> -STATIC xfs_filblks_t
> +xfs_filblks_t
> xfs_bmap_worst_indlen(
> - xfs_inode_t *ip, /* incore inode pointer */
> - xfs_filblks_t len) /* delayed extent length */
> + struct xfs_inode *ip, /* incore inode pointer */
> + xfs_filblks_t len) /* delayed extent length */
> {
> - int level; /* btree level number */
> - int maxrecs; /* maximum record count at this level */
> - xfs_mount_t *mp; /* mount structure */
> - xfs_filblks_t rval; /* return value */
> + struct xfs_mount *mp = ip->i_mount;
> + int maxrecs = mp->m_bmap_dmxr[0];
> + int level;
> + xfs_filblks_t rval;
>
> - mp = ip->i_mount;
> - maxrecs = mp->m_bmap_dmxr[0];
> for (level = 0, rval = 0;
> level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK);
> level++) {
> @@ -2571,146 +2568,6 @@ xfs_bmap_add_extent_unwritten_real(
> #undef PREV
> }
>
> -/*
> - * Convert a hole to a delayed allocation.
> - */
> -STATIC void
> -xfs_bmap_add_extent_hole_delay(
> - xfs_inode_t *ip, /* incore inode pointer */
> - int whichfork,
> - struct xfs_iext_cursor *icur,
> - xfs_bmbt_irec_t *new) /* new data to add to file extents */
> -{
> - struct xfs_ifork *ifp; /* inode fork pointer */
> - xfs_bmbt_irec_t left; /* left neighbor extent entry */
> - xfs_filblks_t newlen=0; /* new indirect size */
> - xfs_filblks_t oldlen=0; /* old indirect size */
> - xfs_bmbt_irec_t right; /* right neighbor extent entry */
> - uint32_t state = xfs_bmap_fork_to_state(whichfork);
> - xfs_filblks_t temp; /* temp for indirect calculations */
> -
> - ifp = xfs_ifork_ptr(ip, whichfork);
> - ASSERT(isnullstartblock(new->br_startblock));
> -
> - /*
> - * Check and set flags if this segment has a left neighbor
> - */
> - if (xfs_iext_peek_prev_extent(ifp, icur, &left)) {
> - state |= BMAP_LEFT_VALID;
> - if (isnullstartblock(left.br_startblock))
> - state |= BMAP_LEFT_DELAY;
> - }
> -
> - /*
> - * Check and set flags if the current (right) segment exists.
> - * If it doesn't exist, we're converting the hole at end-of-file.
> - */
> - if (xfs_iext_get_extent(ifp, icur, &right)) {
> - state |= BMAP_RIGHT_VALID;
> - if (isnullstartblock(right.br_startblock))
> - state |= BMAP_RIGHT_DELAY;
> - }
> -
> - /*
> - * Set contiguity flags on the left and right neighbors.
> - * Don't let extents get too large, even if the pieces are contiguous.
> - */
> - if ((state & BMAP_LEFT_VALID) && (state & BMAP_LEFT_DELAY) &&
> - left.br_startoff + left.br_blockcount == new->br_startoff &&
> - left.br_blockcount + new->br_blockcount <= XFS_MAX_BMBT_EXTLEN)
> - state |= BMAP_LEFT_CONTIG;
> -
> - if ((state & BMAP_RIGHT_VALID) && (state & BMAP_RIGHT_DELAY) &&
> - new->br_startoff + new->br_blockcount == right.br_startoff &&
> - new->br_blockcount + right.br_blockcount <= XFS_MAX_BMBT_EXTLEN &&
> - (!(state & BMAP_LEFT_CONTIG) ||
> - (left.br_blockcount + new->br_blockcount +
> - right.br_blockcount <= XFS_MAX_BMBT_EXTLEN)))
> - state |= BMAP_RIGHT_CONTIG;
> -
> - /*
> - * Switch out based on the contiguity flags.
> - */
> - switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) {
> - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
> - /*
> - * New allocation is contiguous with delayed allocations
> - * on the left and on the right.
> - * Merge all three into a single extent record.
> - */
> - temp = left.br_blockcount + new->br_blockcount +
> - right.br_blockcount;
> -
> - oldlen = startblockval(left.br_startblock) +
> - startblockval(new->br_startblock) +
> - startblockval(right.br_startblock);
> - newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
> - oldlen);
> - left.br_startblock = nullstartblock(newlen);
> - left.br_blockcount = temp;
> -
> - xfs_iext_remove(ip, icur, state);
> - xfs_iext_prev(ifp, icur);
> - xfs_iext_update_extent(ip, state, icur, &left);
> - break;
> -
> - case BMAP_LEFT_CONTIG:
> - /*
> - * New allocation is contiguous with a delayed allocation
> - * on the left.
> - * Merge the new allocation with the left neighbor.
> - */
> - temp = left.br_blockcount + new->br_blockcount;
> -
> - oldlen = startblockval(left.br_startblock) +
> - startblockval(new->br_startblock);
> - newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
> - oldlen);
> - left.br_blockcount = temp;
> - left.br_startblock = nullstartblock(newlen);
> -
> - xfs_iext_prev(ifp, icur);
> - xfs_iext_update_extent(ip, state, icur, &left);
> - break;
> -
> - case BMAP_RIGHT_CONTIG:
> - /*
> - * New allocation is contiguous with a delayed allocation
> - * on the right.
> - * Merge the new allocation with the right neighbor.
> - */
> - temp = new->br_blockcount + right.br_blockcount;
> - oldlen = startblockval(new->br_startblock) +
> - startblockval(right.br_startblock);
> - newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
> - oldlen);
> - right.br_startoff = new->br_startoff;
> - right.br_startblock = nullstartblock(newlen);
> - right.br_blockcount = temp;
> - xfs_iext_update_extent(ip, state, icur, &right);
> - break;
> -
> - case 0:
> - /*
> - * New allocation is not contiguous with another
> - * delayed allocation.
> - * Insert a new entry.
> - */
> - oldlen = newlen = 0;
> - xfs_iext_insert(ip, icur, new, state);
> - break;
> - }
> - if (oldlen != newlen) {
> - ASSERT(oldlen > newlen);
> - xfs_add_fdblocks(ip->i_mount, oldlen - newlen);
> -
> - /*
> - * Nothing to do for disk quota accounting here.
> - */
> - xfs_mod_delalloc(ip, 0, (int64_t)newlen - oldlen);
> - }
> -}
> -
> /*
> * Convert a hole to a real allocation.
> */
> @@ -4039,144 +3896,6 @@ xfs_bmapi_read(
> return 0;
> }
>
> -/*
> - * Add a delayed allocation extent to an inode. Blocks are reserved from the
> - * global pool and the extent inserted into the inode in-core extent tree.
> - *
> - * On entry, got refers to the first extent beyond the offset of the extent to
> - * allocate or eof is specified if no such extent exists. On return, got refers
> - * to the extent record that was inserted to the inode fork.
> - *
> - * Note that the allocated extent may have been merged with contiguous extents
> - * during insertion into the inode fork. Thus, got does not reflect the current
> - * state of the inode fork on return. If necessary, the caller can use lastx to
> - * look up the updated record in the inode fork.
> - */
> -int
> -xfs_bmapi_reserve_delalloc(
> - struct xfs_inode *ip,
> - int whichfork,
> - xfs_fileoff_t off,
> - xfs_filblks_t len,
> - xfs_filblks_t prealloc,
> - struct xfs_bmbt_irec *got,
> - struct xfs_iext_cursor *icur,
> - int eof)
> -{
> - struct xfs_mount *mp = ip->i_mount;
> - struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
> - xfs_extlen_t alen;
> - xfs_extlen_t indlen;
> - uint64_t fdblocks;
> - int error;
> - xfs_fileoff_t aoff;
> - bool use_cowextszhint =
> - whichfork == XFS_COW_FORK && !prealloc;
> -
> -retry:
> - /*
> - * Cap the alloc length. Keep track of prealloc so we know whether to
> - * tag the inode before we return.
> - */
> - aoff = off;
> - alen = XFS_FILBLKS_MIN(len + prealloc, XFS_MAX_BMBT_EXTLEN);
> - if (!eof)
> - alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
> - if (prealloc && alen >= len)
> - prealloc = alen - len;
> -
> - /*
> - * If we're targetting the COW fork but aren't creating a speculative
> - * posteof preallocation, try to expand the reservation to align with
> - * the COW extent size hint if there's sufficient free space.
> - *
> - * Unlike the data fork, the CoW cancellation functions will free all
> - * the reservations at inactivation, so we don't require that every
> - * delalloc reservation have a dirty pagecache.
> - */
> - if (use_cowextszhint) {
> - struct xfs_bmbt_irec prev;
> - xfs_extlen_t extsz = xfs_get_cowextsz_hint(ip);
> -
> - if (!xfs_iext_peek_prev_extent(ifp, icur, &prev))
> - prev.br_startoff = NULLFILEOFF;
> -
> - error = xfs_bmap_extsize_align(mp, got, &prev, extsz, 0, eof,
> - 1, 0, &aoff, &alen);
> - ASSERT(!error);
> - }
> -
> - /*
> - * Make a transaction-less quota reservation for delayed allocation
> - * blocks. This number gets adjusted later. We return if we haven't
> - * allocated blocks already inside this loop.
> - */
> - error = xfs_quota_reserve_blkres(ip, alen);
> - if (error)
> - goto out;
> -
> - /*
> - * Split changing sb for alen and indlen since they could be coming
> - * from different places.
> - */
> - indlen = (xfs_extlen_t)xfs_bmap_worst_indlen(ip, alen);
> - ASSERT(indlen > 0);
> -
> - fdblocks = indlen;
> - if (XFS_IS_REALTIME_INODE(ip)) {
> - error = xfs_dec_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
> - if (error)
> - goto out_unreserve_quota;
> - } else {
> - fdblocks += alen;
> - }
> -
> - error = xfs_dec_fdblocks(mp, fdblocks, false);
> - if (error)
> - goto out_unreserve_frextents;
> -
> - ip->i_delayed_blks += alen;
> - xfs_mod_delalloc(ip, alen, indlen);
> -
> - got->br_startoff = aoff;
> - got->br_startblock = nullstartblock(indlen);
> - got->br_blockcount = alen;
> - got->br_state = XFS_EXT_NORM;
> -
> - xfs_bmap_add_extent_hole_delay(ip, whichfork, icur, got);
> -
> - /*
> - * Tag the inode if blocks were preallocated. Note that COW fork
> - * preallocation can occur at the start or end of the extent, even when
> - * prealloc == 0, so we must also check the aligned offset and length.
> - */
> - if (whichfork == XFS_DATA_FORK && prealloc)
> - xfs_inode_set_eofblocks_tag(ip);
> - if (whichfork == XFS_COW_FORK && (prealloc || aoff < off || alen > len))
> - xfs_inode_set_cowblocks_tag(ip);
> -
> - return 0;
> -
> -out_unreserve_frextents:
> - if (XFS_IS_REALTIME_INODE(ip))
> - xfs_add_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
> -out_unreserve_quota:
> - if (XFS_IS_QUOTA_ON(mp))
> - xfs_quota_unreserve_blkres(ip, alen);
> -out:
> - if (error == -ENOSPC || error == -EDQUOT) {
> - trace_xfs_delalloc_enospc(ip, off, len);
> -
> - if (prealloc || use_cowextszhint) {
> - /* retry without any preallocation */
> - use_cowextszhint = false;
> - prealloc = 0;
> - goto retry;
> - }
> - }
> - return error;
> -}
> -
> static int
> xfs_bmapi_allocate(
> struct xfs_bmalloca *bma)
> diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
> index 4b721d935994..4d48087fd3a8 100644
> --- a/fs/xfs/libxfs/xfs_bmap.h
> +++ b/fs/xfs/libxfs/xfs_bmap.h
> @@ -219,10 +219,6 @@ int xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip,
> bool *done, xfs_fileoff_t stop_fsb);
> int xfs_bmap_split_extent(struct xfs_trans *tp, struct xfs_inode *ip,
> xfs_fileoff_t split_offset);
> -int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
> - xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc,
> - struct xfs_bmbt_irec *got, struct xfs_iext_cursor *cur,
> - int eof);
> int xfs_bmapi_convert_delalloc(struct xfs_inode *ip, int whichfork,
> xfs_off_t offset, struct iomap *iomap, unsigned int *seq);
> int xfs_bmap_add_extent_unwritten_real(struct xfs_trans *tp,
> @@ -233,6 +229,7 @@ xfs_extlen_t xfs_bmapi_minleft(struct xfs_trans *tp, struct xfs_inode *ip,
> int fork);
> int xfs_bmap_btalloc_low_space(struct xfs_bmalloca *ap,
> struct xfs_alloc_arg *args);
> +xfs_filblks_t xfs_bmap_worst_indlen(struct xfs_inode *ip, xfs_filblks_t len);
>
> enum xfs_bmap_intent_type {
> XFS_BMAP_MAP = 1,
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index c669b93bb2d1..a724fc2612e3 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -30,6 +30,7 @@
> #include "xfs_reflink.h"
> #include "xfs_health.h"
> #include "xfs_rtbitmap.h"
> +#include "xfs_icache.h"
>
> #define XFS_ALLOC_ALIGN(mp, off) \
> (((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
> @@ -988,6 +989,284 @@ const struct iomap_ops xfs_dax_write_iomap_ops = {
> .iomap_end = xfs_dax_write_iomap_end,
> };
>
> +/*
> + * Convert a hole to a delayed allocation.
> + */
> +static void
> +xfs_bmap_add_extent_hole_delay(
> + struct xfs_inode *ip, /* incore inode pointer */
> + int whichfork,
> + struct xfs_iext_cursor *icur,
> + struct xfs_bmbt_irec *new) /* new data to add to file extents */
> +{
> + struct xfs_ifork *ifp; /* inode fork pointer */
> + xfs_bmbt_irec_t left; /* left neighbor extent entry */
> + xfs_filblks_t newlen=0; /* new indirect size */
> + xfs_filblks_t oldlen=0; /* old indirect size */
> + xfs_bmbt_irec_t right; /* right neighbor extent entry */
> + uint32_t state = xfs_bmap_fork_to_state(whichfork);
> + xfs_filblks_t temp; /* temp for indirect calculations */
> +
> + ifp = xfs_ifork_ptr(ip, whichfork);
> + ASSERT(isnullstartblock(new->br_startblock));
> +
> + /*
> + * Check and set flags if this segment has a left neighbor
> + */
> + if (xfs_iext_peek_prev_extent(ifp, icur, &left)) {
> + state |= BMAP_LEFT_VALID;
> + if (isnullstartblock(left.br_startblock))
> + state |= BMAP_LEFT_DELAY;
> + }
> +
> + /*
> + * Check and set flags if the current (right) segment exists.
> + * If it doesn't exist, we're converting the hole at end-of-file.
> + */
> + if (xfs_iext_get_extent(ifp, icur, &right)) {
> + state |= BMAP_RIGHT_VALID;
> + if (isnullstartblock(right.br_startblock))
> + state |= BMAP_RIGHT_DELAY;
> + }
> +
> + /*
> + * Set contiguity flags on the left and right neighbors.
> + * Don't let extents get too large, even if the pieces are contiguous.
> + */
> + if ((state & BMAP_LEFT_VALID) && (state & BMAP_LEFT_DELAY) &&
> + left.br_startoff + left.br_blockcount == new->br_startoff &&
> + left.br_blockcount + new->br_blockcount <= XFS_MAX_BMBT_EXTLEN)
> + state |= BMAP_LEFT_CONTIG;
> +
> + if ((state & BMAP_RIGHT_VALID) && (state & BMAP_RIGHT_DELAY) &&
> + new->br_startoff + new->br_blockcount == right.br_startoff &&
> + new->br_blockcount + right.br_blockcount <= XFS_MAX_BMBT_EXTLEN &&
> + (!(state & BMAP_LEFT_CONTIG) ||
> + (left.br_blockcount + new->br_blockcount +
> + right.br_blockcount <= XFS_MAX_BMBT_EXTLEN)))
> + state |= BMAP_RIGHT_CONTIG;
> +
> + /*
> + * Switch out based on the contiguity flags.
> + */
> + switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) {
> + case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
> + /*
> + * New allocation is contiguous with delayed allocations
> + * on the left and on the right.
> + * Merge all three into a single extent record.
> + */
> + temp = left.br_blockcount + new->br_blockcount +
> + right.br_blockcount;
> +
> + oldlen = startblockval(left.br_startblock) +
> + startblockval(new->br_startblock) +
> + startblockval(right.br_startblock);
> + newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
> + oldlen);
> + left.br_startblock = nullstartblock(newlen);
> + left.br_blockcount = temp;
> +
> + xfs_iext_remove(ip, icur, state);
> + xfs_iext_prev(ifp, icur);
> + xfs_iext_update_extent(ip, state, icur, &left);
> + break;
> +
> + case BMAP_LEFT_CONTIG:
> + /*
> + * New allocation is contiguous with a delayed allocation
> + * on the left.
> + * Merge the new allocation with the left neighbor.
> + */
> + temp = left.br_blockcount + new->br_blockcount;
> +
> + oldlen = startblockval(left.br_startblock) +
> + startblockval(new->br_startblock);
> + newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
> + oldlen);
> + left.br_blockcount = temp;
> + left.br_startblock = nullstartblock(newlen);
> +
> + xfs_iext_prev(ifp, icur);
> + xfs_iext_update_extent(ip, state, icur, &left);
> + break;
> +
> + case BMAP_RIGHT_CONTIG:
> + /*
> + * New allocation is contiguous with a delayed allocation
> + * on the right.
> + * Merge the new allocation with the right neighbor.
> + */
> + temp = new->br_blockcount + right.br_blockcount;
> + oldlen = startblockval(new->br_startblock) +
> + startblockval(right.br_startblock);
> + newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
> + oldlen);
> + right.br_startoff = new->br_startoff;
> + right.br_startblock = nullstartblock(newlen);
> + right.br_blockcount = temp;
> + xfs_iext_update_extent(ip, state, icur, &right);
> + break;
> +
> + case 0:
> + /*
> + * New allocation is not contiguous with another
> + * delayed allocation.
> + * Insert a new entry.
> + */
> + oldlen = newlen = 0;
> + xfs_iext_insert(ip, icur, new, state);
> + break;
> + }
> + if (oldlen != newlen) {
> + ASSERT(oldlen > newlen);
> + xfs_add_fdblocks(ip->i_mount, oldlen - newlen);
> +
> + /*
> + * Nothing to do for disk quota accounting here.
> + */
> + xfs_mod_delalloc(ip, 0, (int64_t)newlen - oldlen);
> + }
> +}
> +
> +/*
> + * Add a delayed allocation extent to an inode. Blocks are reserved from the
> + * global pool and the extent inserted into the inode in-core extent tree.
> + *
> + * On entry, got refers to the first extent beyond the offset of the extent to
> + * allocate or eof is specified if no such extent exists. On return, got refers
> + * to the extent record that was inserted to the inode fork.
> + *
> + * Note that the allocated extent may have been merged with contiguous extents
> + * during insertion into the inode fork. Thus, got does not reflect the current
> + * state of the inode fork on return. If necessary, the caller can use lastx to
> + * look up the updated record in the inode fork.
> + */
> +static int
> +xfs_bmapi_reserve_delalloc(
> + struct xfs_inode *ip,
> + int whichfork,
> + xfs_fileoff_t off,
> + xfs_filblks_t len,
> + xfs_filblks_t prealloc,
> + struct xfs_bmbt_irec *got,
> + struct xfs_iext_cursor *icur,
> + int eof)
> +{
> + struct xfs_mount *mp = ip->i_mount;
> + struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
> + xfs_extlen_t alen;
> + xfs_extlen_t indlen;
> + uint64_t fdblocks;
> + int error;
> + xfs_fileoff_t aoff;
> + bool use_cowextszhint =
> + whichfork == XFS_COW_FORK && !prealloc;
> +
> +retry:
> + /*
> + * Cap the alloc length. Keep track of prealloc so we know whether to
> + * tag the inode before we return.
> + */
> + aoff = off;
> + alen = XFS_FILBLKS_MIN(len + prealloc, XFS_MAX_BMBT_EXTLEN);
> + if (!eof)
> + alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
> + if (prealloc && alen >= len)
> + prealloc = alen - len;
> +
> + /*
> + * If we're targetting the COW fork but aren't creating a speculative
> + * posteof preallocation, try to expand the reservation to align with
> + * the COW extent size hint if there's sufficient free space.
> + *
> + * Unlike the data fork, the CoW cancellation functions will free all
> + * the reservations at inactivation, so we don't require that every
> + * delalloc reservation have a dirty pagecache.
> + */
> + if (use_cowextszhint) {
> + struct xfs_bmbt_irec prev;
> + xfs_extlen_t extsz = xfs_get_cowextsz_hint(ip);
> +
> + if (!xfs_iext_peek_prev_extent(ifp, icur, &prev))
> + prev.br_startoff = NULLFILEOFF;
> +
> + error = xfs_bmap_extsize_align(mp, got, &prev, extsz, 0, eof,
> + 1, 0, &aoff, &alen);
> + ASSERT(!error);
> + }
> +
> + /*
> + * Make a transaction-less quota reservation for delayed allocation
> + * blocks. This number gets adjusted later. We return if we haven't
> + * allocated blocks already inside this loop.
> + */
> + error = xfs_quota_reserve_blkres(ip, alen);
> + if (error)
> + goto out;
> +
> + /*
> + * Split changing sb for alen and indlen since they could be coming
> + * from different places.
> + */
> + indlen = (xfs_extlen_t)xfs_bmap_worst_indlen(ip, alen);
> + ASSERT(indlen > 0);
> +
> + fdblocks = indlen;
> + if (XFS_IS_REALTIME_INODE(ip)) {
> + error = xfs_dec_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
> + if (error)
> + goto out_unreserve_quota;
> + } else {
> + fdblocks += alen;
> + }
> +
> + error = xfs_dec_fdblocks(mp, fdblocks, false);
> + if (error)
> + goto out_unreserve_frextents;
> +
> + ip->i_delayed_blks += alen;
> + xfs_mod_delalloc(ip, alen, indlen);
> +
> + got->br_startoff = aoff;
> + got->br_startblock = nullstartblock(indlen);
> + got->br_blockcount = alen;
> + got->br_state = XFS_EXT_NORM;
> +
> + xfs_bmap_add_extent_hole_delay(ip, whichfork, icur, got);
> +
> + /*
> + * Tag the inode if blocks were preallocated. Note that COW fork
> + * preallocation can occur at the start or end of the extent, even when
> + * prealloc == 0, so we must also check the aligned offset and length.
> + */
> + if (whichfork == XFS_DATA_FORK && prealloc)
> + xfs_inode_set_eofblocks_tag(ip);
> + if (whichfork == XFS_COW_FORK && (prealloc || aoff < off || alen > len))
> + xfs_inode_set_cowblocks_tag(ip);
> +
> + return 0;
> +
> +out_unreserve_frextents:
> + if (XFS_IS_REALTIME_INODE(ip))
> + xfs_add_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
> +out_unreserve_quota:
> + if (XFS_IS_QUOTA_ON(mp))
> + xfs_quota_unreserve_blkres(ip, alen);
> +out:
> + if (error == -ENOSPC || error == -EDQUOT) {
> + trace_xfs_delalloc_enospc(ip, off, len);
> +
> + if (prealloc || use_cowextszhint) {
> + /* retry without any preallocation */
> + use_cowextszhint = false;
> + prealloc = 0;
> + goto retry;
> + }
> + }
> + return error;
> +}
> +
> static int
> xfs_buffered_write_iomap_begin(
> struct inode *inode,
> --
> 2.45.2
>
>
next prev parent reply other threads:[~2025-02-19 21:47 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-18 8:10 support for zoned devices v3 Christoph Hellwig
2025-02-18 8:10 ` [PATCH 01/45] xfs: reflow xfs_dec_freecounter Christoph Hellwig
2025-02-18 8:10 ` [PATCH 02/45] xfs: generalize the freespace and reserved blocks handling Christoph Hellwig
2025-02-19 22:11 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 03/45] xfs: support reserved blocks for the rt extent counter Christoph Hellwig
2025-02-25 18:05 ` Darrick J. Wong
2025-02-26 1:20 ` Christoph Hellwig
2025-02-18 8:10 ` [PATCH 04/45] xfs: trace in-memory freecounter reservations Christoph Hellwig
2025-02-18 8:10 ` [PATCH 05/45] xfs: preserve RT reservations across remounts Christoph Hellwig
2025-02-18 8:10 ` [PATCH 06/45] xfs: fixup the metabtree reservation in xrep_reap_metadir_fsblocks Christoph Hellwig
2025-02-19 18:41 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 07/45] xfs: make metabtree reservations global Christoph Hellwig
2025-02-19 18:44 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 08/45] xfs: reduce metafile reservations Christoph Hellwig
2025-02-18 8:10 ` [PATCH 09/45] xfs: factor out a xfs_rt_check_size helper Christoph Hellwig
2025-02-18 8:10 ` [PATCH 10/45] xfs: add a rtg_blocks helper Christoph Hellwig
2025-02-18 8:10 ` [PATCH 11/45] xfs: move xfs_bmapi_reserve_delalloc to xfs_iomap.c Christoph Hellwig
2025-02-19 21:47 ` Darrick J. Wong [this message]
2025-02-18 8:10 ` [PATCH 12/45] xfs: skip always_cow inodes in xfs_reflink_trim_around_shared Christoph Hellwig
2025-02-18 8:10 ` [PATCH 13/45] xfs: refine the unaligned check for always COW inodes in xfs_file_dio_write Christoph Hellwig
2025-02-18 8:10 ` [PATCH 14/45] xfs: support XFS_BMAPI_REMAP in xfs_bmap_del_extent_delay Christoph Hellwig
2025-02-18 8:10 ` [PATCH 15/45] xfs: add a xfs_rtrmap_highest_rgbno helper Christoph Hellwig
2025-02-18 8:10 ` [PATCH 16/45] xfs: define the zoned on-disk format Christoph Hellwig
2025-02-18 8:10 ` [PATCH 17/45] xfs: allow internal RT devices for zoned mode Christoph Hellwig
2025-02-18 8:10 ` [PATCH 18/45] xfs: export zoned geometry via XFS_FSOP_GEOM Christoph Hellwig
2025-02-18 8:10 ` [PATCH 19/45] xfs: disable sb_frextents for zoned file systems Christoph Hellwig
2025-02-18 8:10 ` [PATCH 20/45] xfs: disable FITRIM for zoned RT devices Christoph Hellwig
2025-02-18 8:10 ` [PATCH 21/45] xfs: don't call xfs_can_free_eofblocks from ->release for zoned inodes Christoph Hellwig
2025-02-18 8:10 ` [PATCH 22/45] xfs: skip zoned RT inodes in xfs_inodegc_want_queue_rt_file Christoph Hellwig
2025-02-18 8:10 ` [PATCH 23/45] xfs: parse and validate hardware zone information Christoph Hellwig
2025-02-18 8:10 ` [PATCH 24/45] xfs: add the zoned space allocator Christoph Hellwig
2025-02-19 21:58 ` Darrick J. Wong
2025-02-20 6:17 ` Christoph Hellwig
2025-02-18 8:10 ` [PATCH 25/45] xfs: add support for zoned space reservations Christoph Hellwig
2025-02-19 22:00 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 26/45] xfs: implement zoned garbage collection Christoph Hellwig
2025-02-19 22:02 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 27/45] xfs: implement buffered writes to zoned RT devices Christoph Hellwig
2025-02-19 21:47 ` Darrick J. Wong
2025-02-20 6:16 ` Christoph Hellwig
2025-02-20 16:57 ` Darrick J. Wong
2025-02-25 17:59 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 28/45] xfs: implement direct " Christoph Hellwig
2025-02-18 8:10 ` [PATCH 29/45] xfs: wire up zoned block freeing in xfs_rtextent_free_finish_item Christoph Hellwig
2025-02-18 8:10 ` [PATCH 30/45] xfs: hide reserved RT blocks from statfs Christoph Hellwig
2025-02-18 8:10 ` [PATCH 31/45] xfs: support growfs on zoned file systems Christoph Hellwig
2025-02-18 8:10 ` [PATCH 32/45] xfs: allow COW forks on zoned file systems in xchk_bmap Christoph Hellwig
2025-02-18 8:10 ` [PATCH 33/45] xfs: support xchk_xref_is_used_rt_space on zoned file systems Christoph Hellwig
2025-02-18 8:10 ` [PATCH 34/45] xfs: support xrep_require_rtext_inuse " Christoph Hellwig
2025-02-18 8:10 ` [PATCH 35/45] xfs: enable fsmap reporting for internal RT devices Christoph Hellwig
2025-02-18 8:10 ` [PATCH 36/45] xfs: disable reflink for zoned file systems Christoph Hellwig
2025-02-18 8:10 ` [PATCH 37/45] xfs: disable rt quotas " Christoph Hellwig
2025-02-18 8:10 ` [PATCH 38/45] xfs: enable the zoned RT device feature Christoph Hellwig
2025-02-18 8:10 ` [PATCH 39/45] xfs: support zone gaps Christoph Hellwig
2025-02-18 8:10 ` [PATCH 40/45] xfs: add a max_open_zones mount option Christoph Hellwig
2025-02-18 8:10 ` [PATCH 41/45] xfs: support write life time based data placement Christoph Hellwig
2025-02-19 18:49 ` Darrick J. Wong
2025-02-18 8:10 ` [PATCH 42/45] xfs: wire up the show_stats super operation Christoph Hellwig
2025-02-18 8:10 ` [PATCH 43/45] xfs: export zone stats in /proc/*/mountstats Christoph Hellwig
2025-02-18 8:10 ` [PATCH 44/45] xfs: contain more sysfs code in xfs_sysfs.c Christoph Hellwig
2025-02-18 8:10 ` [PATCH 45/45] xfs: export max_open_zones in sysfs Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250219214746.GW21808@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=cem@kernel.org \
--cc=hans.holmberg@wdc.com \
--cc=hch@lst.de \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox