From: "Darrick J. Wong" <djwong@kernel.org>
To: Christoph Hellwig <hch@lst.de>
Cc: Christian Brauner <brauner@kernel.org>,
Alexander Viro <viro@zeniv.linux.org.uk>,
Chandan Babu R <chandan.babu@oracle.com>,
Brian Foster <bfoster@redhat.com>, Jens Axboe <axboe@kernel.dk>,
Jan Kara <jack@suse.cz>, Theodore Ts'o <tytso@mit.edu>,
linux-block@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-xfs@vger.kernel.org, linux-ext4@vger.kernel.org
Subject: Re: [PATCH 6/6] xfs: refactor xfs_file_fallocate
Date: Tue, 27 Aug 2024 09:07:03 -0700 [thread overview]
Message-ID: <20240827160703.GU865349@frogsfrogsfrogs> (raw)
In-Reply-To: <20240827065123.1762168-7-hch@lst.de>
On Tue, Aug 27, 2024 at 08:50:50AM +0200, Christoph Hellwig wrote:
> Refactor xfs_file_fallocate into separate helpers for each mode,
> two factors for i_size handling and a single switch statement over the
> supported modes.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Much less complicated now! :)
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
--D
> ---
> fs/xfs/xfs_file.c | 330 +++++++++++++++++++++++++++++-----------------
> 1 file changed, 208 insertions(+), 122 deletions(-)
>
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 489bc1b173c268..f6e4912769a0d5 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -852,6 +852,192 @@ static inline bool xfs_file_sync_writes(struct file *filp)
> return false;
> }
>
> +static int
> +xfs_falloc_newsize(
> + struct file *file,
> + int mode,
> + loff_t offset,
> + loff_t len,
> + loff_t *new_size)
> +{
> + struct inode *inode = file_inode(file);
> +
> + if ((mode & FALLOC_FL_KEEP_SIZE) || offset + len <= i_size_read(inode))
> + return 0;
> + *new_size = offset + len;
> + return inode_newsize_ok(inode, *new_size);
> +}
> +
> +static int
> +xfs_falloc_setsize(
> + struct file *file,
> + loff_t new_size)
> +{
> + struct iattr iattr = {
> + .ia_valid = ATTR_SIZE,
> + .ia_size = new_size,
> + };
> +
> + if (!new_size)
> + return 0;
> + return xfs_vn_setattr_size(file_mnt_idmap(file), file_dentry(file),
> + &iattr);
> +}
> +
> +static int
> +xfs_falloc_collapse_range(
> + struct file *file,
> + loff_t offset,
> + loff_t len)
> +{
> + struct inode *inode = file_inode(file);
> + loff_t new_size = i_size_read(inode) - len;
> + int error;
> +
> + if (!xfs_is_falloc_aligned(XFS_I(inode), offset, len))
> + return -EINVAL;
> +
> + /*
> + * There is no need to overlap collapse range with EOF, in which case it
> + * is effectively a truncate operation
> + */
> + if (offset + len >= i_size_read(inode))
> + return -EINVAL;
> +
> + error = xfs_collapse_file_space(XFS_I(inode), offset, len);
> + if (error)
> + return error;
> + return xfs_falloc_setsize(file, new_size);
> +}
> +
> +static int
> +xfs_falloc_insert_range(
> + struct file *file,
> + loff_t offset,
> + loff_t len)
> +{
> + struct inode *inode = file_inode(file);
> + loff_t isize = i_size_read(inode);
> + int error;
> +
> + if (!xfs_is_falloc_aligned(XFS_I(inode), offset, len))
> + return -EINVAL;
> +
> + /*
> + * New inode size must not exceed ->s_maxbytes, accounting for
> + * possible signed overflow.
> + */
> + if (inode->i_sb->s_maxbytes - isize < len)
> + return -EFBIG;
> +
> + /* Offset should be less than i_size */
> + if (offset >= isize)
> + return -EINVAL;
> +
> + error = xfs_falloc_setsize(file, isize + len);
> + if (error)
> + return error;
> +
> + /*
> + * Perform hole insertion now that the file size has been updated so
> + * that if we crash during the operation we don't leave shifted extents
> + * past EOF and hence losing access to the data that is contained within
"...and hence lose access to the data..."
> + * them.
> + */
> + return xfs_insert_file_space(XFS_I(inode), offset, len);
> +}
> +
> +/*
> + * Punch a hole and prealloc the range. We use a hole punch rather than
> + * unwritten extent conversion for two reasons:
> + *
> + * 1.) Hole punch handles partial block zeroing for us.
> + * 2.) If prealloc returns ENOSPC, the file range is still zero-valued by
> + * virtue of the hole punch.
> + */
> +static int
> +xfs_falloc_zero_range(
> + struct file *file,
> + int mode,
> + loff_t offset,
> + loff_t len)
> +{
> + struct inode *inode = file_inode(file);
> + unsigned int blksize = i_blocksize(inode);
> + loff_t new_size = 0;
> + int error;
> +
> + trace_xfs_zero_file_space(XFS_I(inode));
> +
> + error = xfs_falloc_newsize(file, mode, offset, len, &new_size);
> + if (error)
> + return error;
> +
> + error = xfs_free_file_space(XFS_I(inode), offset, len);
> + if (error)
> + return error;
> +
> + len = round_up(offset + len, blksize) - round_down(offset, blksize);
> + offset = round_down(offset, blksize);
> + error = xfs_alloc_file_space(XFS_I(inode), offset, len);
> + if (error)
> + return error;
> + return xfs_falloc_setsize(file, new_size);
> +}
> +
> +static int
> +xfs_falloc_unshare_range(
> + struct file *file,
> + int mode,
> + loff_t offset,
> + loff_t len)
> +{
> + struct inode *inode = file_inode(file);
> + loff_t new_size = 0;
> + int error;
> +
> + error = xfs_falloc_newsize(file, mode, offset, len, &new_size);
> + if (error)
> + return error;
> +
> + error = xfs_reflink_unshare(XFS_I(inode), offset, len);
> + if (error)
> + return error;
> +
> + error = xfs_alloc_file_space(XFS_I(inode), offset, len);
> + if (error)
> + return error;
> + return xfs_falloc_setsize(file, new_size);
> +}
> +
> +static int
> +xfs_falloc_allocate_range(
> + struct file *file,
> + int mode,
> + loff_t offset,
> + loff_t len)
> +{
> + struct inode *inode = file_inode(file);
> + loff_t new_size = 0;
> + int error;
> +
> + /*
> + * If always_cow mode we can't use preallocations and thus should not
> + * create them.
> + */
> + if (xfs_is_always_cow_inode(XFS_I(inode)))
> + return -EOPNOTSUPP;
> +
> + error = xfs_falloc_newsize(file, mode, offset, len, &new_size);
> + if (error)
> + return error;
> +
> + error = xfs_alloc_file_space(XFS_I(inode), offset, len);
> + if (error)
> + return error;
> + return xfs_falloc_setsize(file, new_size);
> +}
> +
> #define XFS_FALLOC_FL_SUPPORTED \
> (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | \
> FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | \
> @@ -868,8 +1054,6 @@ xfs_file_fallocate(
> struct xfs_inode *ip = XFS_I(inode);
> long error;
> uint iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
> - loff_t new_size = 0;
> - bool do_file_insert = false;
>
> if (!S_ISREG(inode->i_mode))
> return -EINVAL;
> @@ -894,129 +1078,31 @@ xfs_file_fallocate(
> if (error)
> goto out_unlock;
>
> - if (mode & FALLOC_FL_PUNCH_HOLE) {
> + switch (mode & FALLOC_FL_MODE_MASK) {
> + case FALLOC_FL_PUNCH_HOLE:
> error = xfs_free_file_space(ip, offset, len);
> - if (error)
> - goto out_unlock;
> - } else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
> - if (!xfs_is_falloc_aligned(ip, offset, len)) {
> - error = -EINVAL;
> - goto out_unlock;
> - }
> -
> - /*
> - * There is no need to overlap collapse range with EOF,
> - * in which case it is effectively a truncate operation
> - */
> - if (offset + len >= i_size_read(inode)) {
> - error = -EINVAL;
> - goto out_unlock;
> - }
> -
> - new_size = i_size_read(inode) - len;
> -
> - error = xfs_collapse_file_space(ip, offset, len);
> - if (error)
> - goto out_unlock;
> - } else if (mode & FALLOC_FL_INSERT_RANGE) {
> - loff_t isize = i_size_read(inode);
> -
> - if (!xfs_is_falloc_aligned(ip, offset, len)) {
> - error = -EINVAL;
> - goto out_unlock;
> - }
> -
> - /*
> - * New inode size must not exceed ->s_maxbytes, accounting for
> - * possible signed overflow.
> - */
> - if (inode->i_sb->s_maxbytes - isize < len) {
> - error = -EFBIG;
> - goto out_unlock;
> - }
> - new_size = isize + len;
> -
> - /* Offset should be less than i_size */
> - if (offset >= isize) {
> - error = -EINVAL;
> - goto out_unlock;
> - }
> - do_file_insert = true;
> - } else {
> - if (!(mode & FALLOC_FL_KEEP_SIZE) &&
> - offset + len > i_size_read(inode)) {
> - new_size = offset + len;
> - error = inode_newsize_ok(inode, new_size);
> - if (error)
> - goto out_unlock;
> - }
> -
> - if (mode & FALLOC_FL_ZERO_RANGE) {
> - /*
> - * Punch a hole and prealloc the range. We use a hole
> - * punch rather than unwritten extent conversion for two
> - * reasons:
> - *
> - * 1.) Hole punch handles partial block zeroing for us.
> - * 2.) If prealloc returns ENOSPC, the file range is
> - * still zero-valued by virtue of the hole punch.
> - */
> - unsigned int blksize = i_blocksize(inode);
> -
> - trace_xfs_zero_file_space(ip);
> -
> - error = xfs_free_file_space(ip, offset, len);
> - if (error)
> - goto out_unlock;
> -
> - len = round_up(offset + len, blksize) -
> - round_down(offset, blksize);
> - offset = round_down(offset, blksize);
> - } else if (mode & FALLOC_FL_UNSHARE_RANGE) {
> - error = xfs_reflink_unshare(ip, offset, len);
> - if (error)
> - goto out_unlock;
> - } else {
> - /*
> - * If always_cow mode we can't use preallocations and
> - * thus should not create them.
> - */
> - if (xfs_is_always_cow_inode(ip)) {
> - error = -EOPNOTSUPP;
> - goto out_unlock;
> - }
> - }
> -
> - error = xfs_alloc_file_space(ip, offset, len);
> - if (error)
> - goto out_unlock;
> - }
> -
> - /* Change file size if needed */
> - if (new_size) {
> - struct iattr iattr;
> -
> - iattr.ia_valid = ATTR_SIZE;
> - iattr.ia_size = new_size;
> - error = xfs_vn_setattr_size(file_mnt_idmap(file),
> - file_dentry(file), &iattr);
> - if (error)
> - goto out_unlock;
> - }
> -
> - /*
> - * Perform hole insertion now that the file size has been
> - * updated so that if we crash during the operation we don't
> - * leave shifted extents past EOF and hence losing access to
> - * the data that is contained within them.
> - */
> - if (do_file_insert) {
> - error = xfs_insert_file_space(ip, offset, len);
> - if (error)
> - goto out_unlock;
> + break;
> + case FALLOC_FL_COLLAPSE_RANGE:
> + error = xfs_falloc_collapse_range(file, offset, len);
> + break;
> + case FALLOC_FL_INSERT_RANGE:
> + error = xfs_falloc_insert_range(file, offset, len);
> + break;
> + case FALLOC_FL_ZERO_RANGE:
> + error = xfs_falloc_zero_range(file, mode, offset, len);
> + break;
> + case FALLOC_FL_UNSHARE_RANGE:
> + error = xfs_falloc_unshare_range(file, mode, offset, len);
> + break;
> + case FALLOC_FL_ALLOCATE_RANGE:
> + error = xfs_falloc_allocate_range(file, mode, offset, len);
> + break;
> + default:
> + error = -EOPNOTSUPP;
> + break;
> }
>
> - if (xfs_file_sync_writes(file))
> + if (!error && xfs_file_sync_writes(file))
> error = xfs_log_force_inode(ip);
>
> out_unlock:
> --
> 2.43.0
>
>
next prev parent reply other threads:[~2024-08-27 16:07 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-27 6:50 sort out the fallocate mode mess v2 Christoph Hellwig
2024-08-27 6:50 ` [PATCH 1/6] block: remove checks for FALLOC_FL_NO_HIDE_STALE Christoph Hellwig
2024-08-27 14:55 ` Darrick J. Wong
2024-08-28 14:58 ` Christian Brauner
2024-08-28 15:31 ` Jan Kara
2024-08-27 6:50 ` [PATCH 2/6] ext4: remove tracing " Christoph Hellwig
2024-08-27 14:56 ` Darrick J. Wong
2024-08-28 4:04 ` Christoph Hellwig
2024-08-28 15:31 ` Jan Kara
2024-08-27 6:50 ` [PATCH 3/6] fs: sort out the fallocate mode vs flag mess Christoph Hellwig
2024-08-27 14:55 ` Darrick J. Wong
2024-08-28 4:05 ` Christoph Hellwig
2024-08-28 15:34 ` Jan Kara
2024-08-27 6:50 ` [PATCH 4/6] xfs: call xfs_flush_unmap_range from xfs_free_file_space Christoph Hellwig
2024-08-27 16:03 ` Darrick J. Wong
2024-08-28 4:06 ` Christoph Hellwig
2024-08-29 3:03 ` Dave Chinner
2024-08-29 3:54 ` Christoph Hellwig
2024-08-27 6:50 ` [PATCH 5/6] xfs: move the xfs_is_always_cow_inode check into xfs_alloc_file_space Christoph Hellwig
2024-08-27 16:03 ` Darrick J. Wong
2024-08-27 6:50 ` [PATCH 6/6] xfs: refactor xfs_file_fallocate Christoph Hellwig
2024-08-27 16:07 ` Darrick J. Wong [this message]
2024-08-28 4:07 ` Christoph Hellwig
2024-08-29 3:11 ` Dave Chinner
2024-08-29 3:56 ` Christoph Hellwig
-- strict thread matches above, loose matches on Subject: below --
2024-08-21 6:30 sort out the fallocate mode mess Christoph Hellwig
2024-08-21 6:30 ` [PATCH 6/6] xfs: refactor xfs_file_fallocate Christoph Hellwig
2024-08-21 12:44 ` Brian Foster
2024-08-21 12:57 ` Christoph Hellwig
2024-08-21 13:09 ` Brian Foster
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=20240827160703.GU865349@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=axboe@kernel.dk \
--cc=bfoster@redhat.com \
--cc=brauner@kernel.org \
--cc=chandan.babu@oracle.com \
--cc=hch@lst.de \
--cc=jack@suse.cz \
--cc=linux-block@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=viro@zeniv.linux.org.uk \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.