All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mark Brown <broonie@kernel.org>
To: Christian Brauner <brauner@kernel.org>
Cc: Jan Kara <jack@suse.cz>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Linux Next Mailing List <linux-next@vger.kernel.org>,
	Namjae Jeon <linkinjeon@kernel.org>
Subject: linux-next: manual merge of the vfs-brauner tree with the exfat tree
Date: Fri, 27 Mar 2026 17:35:51 +0000	[thread overview]
Message-ID: <aca_9wyB29931jgP@sirena.co.uk> (raw)

[-- Attachment #1: Type: text/plain, Size: 12558 bytes --]

Hi all,

Today's linux-next merge of the vfs-brauner tree got a conflict in:

  fs/exfat/file.c

between commit:

  9b373eacd6e6c4 ("exfat: add iomap buffered I/O support")

from the exfat tree and commit:

  5f36c9ca333360 ("fs: Rename generic_file_fsync() to simple_fsync()")

from the vfs-brauner tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating

diff --combined fs/exfat/file.c
index 9a30c32b3a0526,4e8d34a75b6638..00000000000000
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@@ -13,12 -13,9 +13,12 @@@
  #include <linux/msdos_fs.h>
  #include <linux/writeback.h>
  #include <linux/filelock.h>
 +#include <linux/falloc.h>
 +#include <linux/iomap.h>
  
  #include "exfat_raw.h"
  #include "exfat_fs.h"
 +#include "iomap.h"
  
  static int exfat_cont_expand(struct inode *inode, loff_t size)
  {
@@@ -57,7 -54,7 +57,7 @@@
  	clu.flags = ei->flags;
  
  	ret = exfat_alloc_cluster(inode, new_num_clusters - num_clusters,
 -			&clu, inode_needs_sync(inode));
 +			&clu, inode_needs_sync(inode), false);
  	if (ret)
  		return ret;
  
@@@ -93,45 -90,6 +93,45 @@@ free_clu
  	return -EIO;
  }
  
 +/*
 + * Preallocate space for a file. This implements exfat's fallocate file
 + * operation, which gets called from sys_fallocate system call. User space
 + * requests len bytes at offset. In contrary to fat, we only support
 + * FALLOC_FL_ALLOCATE_RANGE because by leaving the valid data length(VDL)
 + * field, it is unnecessary to zero out the newly allocated clusters.
 + */
 +static long exfat_fallocate(struct file *file, int mode,
 +			  loff_t offset, loff_t len)
 +{
 +	struct inode *inode = file->f_mapping->host;
 +	loff_t newsize = offset + len;
 +	int err = 0;
 +
 +	/* No support for other modes */
 +	if (mode != FALLOC_FL_ALLOCATE_RANGE)
 +		return -EOPNOTSUPP;
 +
 +	/* No support for dir */
 +	if (!S_ISREG(inode->i_mode))
 +		return -EOPNOTSUPP;
 +
 +	if (unlikely(exfat_forced_shutdown(inode->i_sb)))
 +		return -EIO;
 +
 +	inode_lock(inode);
 +
 +	if (newsize <= i_size_read(inode))
 +		goto error;
 +
 +	/* This is just an expanding truncate */
 +	err = exfat_cont_expand(inode, newsize);
 +
 +error:
 +	inode_unlock(inode);
 +
 +	return err;
 +}
 +
  static bool exfat_allow_set_time(struct mnt_idmap *idmap,
  				 struct exfat_sb_info *sbi, struct inode *inode)
  {
@@@ -337,18 -295,7 +337,18 @@@ int exfat_setattr(struct mnt_idmap *idm
  
  	if ((attr->ia_valid & ATTR_SIZE) &&
  	    attr->ia_size > i_size_read(inode)) {
 +		loff_t old_size = i_size_read(inode);
 +
  		error = exfat_cont_expand(inode, attr->ia_size);
 +		if (!error && attr->ia_size > old_size &&
 +		    old_size % PAGE_SIZE != 0) {
 +			loff_t len = min_t(loff_t,
 +					round_up(old_size, PAGE_SIZE) - old_size,
 +					attr->ia_size - old_size);
 +			error = iomap_zero_range(inode, old_size, len,
 +					NULL, &exfat_read_iomap_ops,
 +					&exfat_iomap_folio_ops, NULL);
 +		}
  		if (error || attr->ia_valid == ATTR_SIZE)
  			return error;
  		attr->ia_valid &= ~ATTR_SIZE;
@@@ -395,10 -342,7 +395,10 @@@
  	exfat_truncate_inode_atime(inode);
  
  	if (attr->ia_valid & ATTR_SIZE) {
 -		error = exfat_block_truncate_page(inode, attr->ia_size);
 +		inode_dio_wait(inode);
 +		error = iomap_truncate_page(inode, attr->ia_size, NULL,
 +				&exfat_read_iomap_ops,
 +				&exfat_iomap_folio_ops, NULL);
  		if (error)
  			goto out;
  
@@@ -633,14 -577,10 +633,14 @@@ int exfat_file_fsync(struct file *filp
  	if (unlikely(exfat_forced_shutdown(inode->i_sb)))
  		return -EIO;
  
 -	err = simple_fsync_noflush(filp, start, end, datasync);
 +	err = file_write_and_wait_range(filp, start, end);
  	if (err)
  		return err;
  
 +	if (!datasync)
 +		err = __exfat_write_inode(inode, 1);
 +	write_inode_now(inode, !datasync);
 +
  	err = sync_blockdev(inode->i_sb->s_bdev);
  	if (err)
  		return err;
@@@ -648,72 -588,44 +648,72 @@@
  	return blkdev_issue_flush(inode->i_sb->s_bdev);
  }
  
 -static int exfat_extend_valid_size(struct inode *inode, loff_t new_valid_size)
 +int exfat_extend_valid_size(struct inode *inode, loff_t off, bool bsync)
  {
 -	int err;
 -	loff_t pos;
  	struct exfat_inode_info *ei = EXFAT_I(inode);
 -	struct address_space *mapping = inode->i_mapping;
 -	const struct address_space_operations *ops = mapping->a_ops;
 +	struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
 +	loff_t old_valid_size;
 +	int ret = 0;
  
 -	pos = ei->valid_size;
 -	while (pos < new_valid_size) {
 -		u32 len;
 -		struct folio *folio;
 -		unsigned long off;
 +	mutex_lock(&sbi->s_lock);
 +	old_valid_size = ei->valid_size;
 +	mutex_unlock(&sbi->s_lock);
  
 -		len = PAGE_SIZE - (pos & (PAGE_SIZE - 1));
 -		if (pos + len > new_valid_size)
 -			len = new_valid_size - pos;
 -
 -		err = ops->write_begin(NULL, mapping, pos, len, &folio, NULL);
 -		if (err)
 -			goto out;
 -
 -		off = offset_in_folio(folio, pos);
 -		folio_zero_new_buffers(folio, off, off + len);
 -
 -		err = ops->write_end(NULL, mapping, pos, len, len, folio, NULL);
 -		if (err < 0)
 -			goto out;
 -		pos += len;
 -
 -		balance_dirty_pages_ratelimited(mapping);
 -		cond_resched();
 +	if (old_valid_size < off) {
 +		ret = iomap_zero_range(inode, old_valid_size,
 +				off - old_valid_size, NULL,
 +				&exfat_write_iomap_ops, &exfat_iomap_folio_ops,
 +				NULL);
 +		if (!ret && bsync)
 +			ret = filemap_write_and_wait_range(inode->i_mapping,
 +							   old_valid_size,
 +							   off - 1);
  	}
  
 -	return 0;
 +	return ret;
 +}
  
 +static ssize_t exfat_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 +{
 +	ssize_t ret;
 +
 +	ret = iomap_dio_rw(iocb, from, &exfat_write_iomap_ops,
 +			&exfat_write_dio_ops, 0, NULL, 0);
 +	if (ret == -ENOTBLK)
 +		ret = 0;
 +	else if (ret < 0)
 +		goto out;
 +
 +	if (iov_iter_count(from)) {
 +		loff_t offset, end;
 +		ssize_t written;
 +		int ret2;
 +
 +		offset = iocb->ki_pos;
 +		iocb->ki_flags &= ~IOCB_DIRECT;
 +		written = iomap_file_buffered_write(iocb, from,
 +				&exfat_write_iomap_ops, &exfat_iomap_folio_ops,
 +				NULL);
 +		if (written < 0) {
 +			ret = written;
 +			goto out;
 +		}
 +
 +		ret += written;
 +		end = iocb->ki_pos + written - 1;
 +		ret2 = filemap_write_and_wait_range(iocb->ki_filp->f_mapping,
 +				offset, end);
 +		if (ret2) {
 +			ret = -EIO;
 +			goto out;
 +		}
 +		if (!ret2)
 +			invalidate_mapping_pages(iocb->ki_filp->f_mapping,
 +					offset >> PAGE_SHIFT,
 +					end >> PAGE_SHIFT);
 +	}
  out:
 -	return err;
 +	return ret;
  }
  
  static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
@@@ -724,7 -636,6 +724,7 @@@
  	struct exfat_inode_info *ei = EXFAT_I(inode);
  	loff_t pos = iocb->ki_pos;
  	loff_t valid_size;
 +	int err;
  
  	if (unlikely(exfat_forced_shutdown(inode->i_sb)))
  		return -EIO;
@@@ -740,18 -651,28 +740,18 @@@
  	if (ret <= 0)
  		goto unlock;
  
 -	if (iocb->ki_flags & IOCB_DIRECT) {
 -		unsigned long align = pos | iov_iter_alignment(iter);
 -
 -		if (!IS_ALIGNED(align, i_blocksize(inode)) &&
 -		    !IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev))) {
 -			ret = -EINVAL;
 -			goto unlock;
 -		}
 +	err = file_modified(iocb->ki_filp);
 +	if (err) {
 +		ret = err;
 +		goto unlock;
  	}
  
 -	if (pos > valid_size) {
 -		ret = exfat_extend_valid_size(inode, pos);
 -		if (ret < 0 && ret != -ENOSPC) {
 -			exfat_err(inode->i_sb,
 -				"write: fail to zero from %llu to %llu(%zd)",
 -				valid_size, pos, ret);
 -		}
 -		if (ret < 0)
 -			goto unlock;
 -	}
 -
 -	ret = __generic_file_write_iter(iocb, iter);
 +	if (iocb->ki_flags & IOCB_DIRECT)
 +		ret = exfat_dio_write_iter(iocb, iter);
 +	else
 +		ret = iomap_file_buffered_write(iocb, iter,
 +				&exfat_write_iomap_ops, &exfat_iomap_folio_ops,
 +				NULL);
  	if (ret < 0)
  		goto unlock;
  
@@@ -778,52 -699,37 +778,52 @@@ unlock
  static ssize_t exfat_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
  {
  	struct inode *inode = file_inode(iocb->ki_filp);
 +	ssize_t ret;
  
  	if (unlikely(exfat_forced_shutdown(inode->i_sb)))
  		return -EIO;
  
 -	return generic_file_read_iter(iocb, iter);
 +	inode_lock_shared(inode);
 +
 +	if (iocb->ki_flags & IOCB_DIRECT) {
 +		size_t count = iov_iter_count(iter);
 +
 +		if ((iocb->ki_pos | count) & (inode->i_sb->s_blocksize - 1)) {
 +			ret = -EINVAL;
 +			goto inode_unlock;
 +		}
 +
 +		file_accessed(iocb->ki_filp);
 +		ret = iomap_dio_rw(iocb, iter, &exfat_read_iomap_ops, NULL, 0,
 +				NULL, 0);
 +	} else {
 +		ret = generic_file_read_iter(iocb, iter);
 +	}
 +
 +inode_unlock:
 +	inode_unlock_shared(inode);
 +
 +	return ret;
  }
  
  static vm_fault_t exfat_page_mkwrite(struct vm_fault *vmf)
  {
 -	int err;
  	struct inode *inode = file_inode(vmf->vma->vm_file);
 -	struct exfat_inode_info *ei = EXFAT_I(inode);
 -	loff_t new_valid_size;
 +	vm_fault_t ret;
  
  	if (!inode_trylock(inode))
  		return VM_FAULT_RETRY;
  
 -	new_valid_size = ((loff_t)vmf->pgoff + 1) << PAGE_SHIFT;
 -	new_valid_size = min(new_valid_size, i_size_read(inode));
 -
 -	if (ei->valid_size < new_valid_size) {
 -		err = exfat_extend_valid_size(inode, new_valid_size);
 -		if (err < 0) {
 -			inode_unlock(inode);
 -			return vmf_fs_error(err);
 -		}
 -	}
 +	sb_start_pagefault(inode->i_sb);
 +	file_update_time(vmf->vma->vm_file);
  
 +	filemap_invalidate_lock_shared(inode->i_mapping);
 +	ret = iomap_page_mkwrite(vmf, &exfat_mkwrite_iomap_ops, NULL);
 +	filemap_invalidate_unlock_shared(inode->i_mapping);
 +	sb_end_pagefault(inode->i_sb);
  	inode_unlock(inode);
  
 -	return filemap_page_mkwrite(vmf);
 +	return ret;
  }
  
  static const struct vm_operations_struct exfat_file_vm_ops = {
@@@ -839,21 -745,6 +839,21 @@@ static int exfat_file_mmap_prepare(stru
  	if (unlikely(exfat_forced_shutdown(file_inode(desc->file)->i_sb)))
  		return -EIO;
  
 +	if (vma_desc_test_flags(desc, VMA_WRITE_BIT)) {
 +		struct inode *inode = file_inode(file);
 +		loff_t from, to;
 +		int err;
 +
 +		from = ((loff_t)desc->pgoff << PAGE_SHIFT);
 +		to = min_t(loff_t, i_size_read(inode),
 +				from + vma_desc_size(desc));
 +		if (EXFAT_I(inode)->valid_size < to) {
 +			err = exfat_extend_valid_size(inode, to, false);
 +			if (err)
 +				return err;
 +		}
 +	}
 +
  	file_accessed(file);
  	desc->vm_ops = &exfat_file_vm_ops;
  	return 0;
@@@ -868,50 -759,8 +868,50 @@@ static ssize_t exfat_splice_read(struc
  	return filemap_splice_read(in, ppos, pipe, len, flags);
  }
  
 +static int exfat_file_open(struct inode *inode, struct file *filp)
 +{
 +	int err;
 +
 +	if (unlikely(exfat_forced_shutdown(inode->i_sb)))
 +		return -EIO;
 +
 +	err = generic_file_open(inode, filp);
 +	if (err)
 +		return err;
 +
 +	filp->f_mode |= FMODE_CAN_ODIRECT;
 +
 +	return 0;
 +}
 +
 +static loff_t exfat_file_llseek(struct file *file, loff_t offset, int whence)
 +{
 +	struct inode *inode = file->f_mapping->host;
 +
 +	switch (whence) {
 +	case SEEK_HOLE:
 +		inode_lock_shared(inode);
 +		offset = iomap_seek_hole(inode, offset, &exfat_read_iomap_ops);
 +		inode_unlock_shared(inode);
 +		break;
 +	case SEEK_DATA:
 +		inode_lock_shared(inode);
 +		offset = iomap_seek_data(inode, offset, &exfat_read_iomap_ops);
 +		inode_unlock_shared(inode);
 +		break;
 +	default:
 +		return generic_file_llseek_size(file, offset, whence,
 +						inode->i_sb->s_maxbytes,
 +						i_size_read(inode));
 +	}
 +	if (offset < 0)
 +		return offset;
 +	return vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 +}
 +
  const struct file_operations exfat_file_operations = {
 -	.llseek		= generic_file_llseek,
 +	.open		= exfat_file_open,
 +	.llseek		= exfat_file_llseek,
  	.read_iter	= exfat_file_read_iter,
  	.write_iter	= exfat_file_write_iter,
  	.unlocked_ioctl = exfat_ioctl,
@@@ -922,7 -771,6 +922,7 @@@
  	.fsync		= exfat_file_fsync,
  	.splice_read	= exfat_splice_read,
  	.splice_write	= iter_file_splice_write,
 +	.fallocate	= exfat_fallocate,
  	.setlease	= generic_setlease,
  };
  
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

             reply	other threads:[~2026-03-27 17:35 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-27 17:35 Mark Brown [this message]
2026-03-28  1:01 ` linux-next: manual merge of the vfs-brauner tree with the exfat tree Namjae Jeon
  -- strict thread matches above, loose matches on Subject: below --
2026-10-13 13:21 Mark Brown
2026-10-13 13:21 Mark Brown
2024-08-11 22:10 Stephen Rothwell
2024-08-12  0:54 ` Namjae Jeon
2024-09-16 22:22 ` Stephen Rothwell
2024-09-17  6:44   ` Namjae Jeon

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=aca_9wyB29931jgP@sirena.co.uk \
    --to=broonie@kernel.org \
    --cc=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=linkinjeon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-next@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 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.