linux-next: manual merge of the vfs-brauner tree with the exfat tree
Subsystems (2)
Mark Brown
maintainerHi 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
fs/exfat/file.c +0 -0
@@@ -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) { 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;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) {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 ;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;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;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) 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 ;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;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 = { 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 ;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, .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.
Namjae Jeon
maintainerQuoted 13 lines · Mark Brown
Hi all,
Today's linux-next merge of the vfs-brauner tree got a conflict in:
fs/exfat/file.cbetween commit:
9b373eacd6e6c4("exfat: add iomap buffered I/O support")from the exfat tree and commit:
Quoted 8 lines
5f36c9ca333360("fs: Renamegeneric_file_fsync()tosimple_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
@@@ -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;Looks good to me:)
To avoid merge conflicts, I will wait for Christian to send his PR to Linus first. I’ll then include this change and submit exfat's PR afterward.
Thanks!