This patch switches the regular file operations on iomap-based ones. The hfsplus_aops is redefined as the iomap-based operations. As a result, hfsplus_direct_IO() has been completely removed as a user of blockdev_direct_IO(). Also, unnecessary LEGACY_DIRECT_IO dependency has been removed from Kconfig. Signed-off-by: Viacheslav Dubeyko cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org --- fs/hfsplus/Kconfig | 1 - fs/hfsplus/extents.c | 39 +++++++---- fs/hfsplus/hfsplus_fs.h | 1 + fs/hfsplus/inode.c | 142 +++++++++++++++++++--------------------- 4 files changed, 96 insertions(+), 87 deletions(-) diff --git a/fs/hfsplus/Kconfig b/fs/hfsplus/Kconfig index 865a1966f395..b4432c64db3b 100644 --- a/fs/hfsplus/Kconfig +++ b/fs/hfsplus/Kconfig @@ -5,7 +5,6 @@ config HFSPLUS_FS select BUFFER_HEAD select NLS select NLS_UTF8 - select LEGACY_DIRECT_IO select FS_IOMAP help If you say Y here, you will be able to mount extended format diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index c1c9b21814a0..8f7f560cec64 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c @@ -15,6 +15,7 @@ #include "hfsplus_fs.h" #include "hfsplus_raw.h" +#include "iomap.h" /* Compare two extents keys, returns 0 on same, pos/neg for difference */ int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, @@ -605,20 +606,32 @@ void hfsplus_file_truncate(struct inode *inode) inode->i_ino, (long long)hip->phys_size, inode->i_size); if (inode->i_size > hip->phys_size) { - struct address_space *mapping = inode->i_mapping; - struct folio *folio; - void *fsdata = NULL; - loff_t size = inode->i_size; + if (S_ISREG(inode->i_mode)) { + res = hfsplus_iomap_cont_expand(inode, inode->i_size); + if (res) + return; + + mark_inode_dirty(inode); + } else { + struct address_space *mapping = inode->i_mapping; + struct folio *folio; + void *fsdata = NULL; + + res = hfsplus_write_begin(NULL, mapping, + inode->i_size, 0, + &folio, &fsdata); + if (res) + return; + + res = generic_write_end(NULL, mapping, + inode->i_size, 0, 0, + folio, fsdata); + if (res < 0) + return; + + mark_inode_dirty(inode); + } - res = hfsplus_write_begin(NULL, mapping, size, 0, - &folio, &fsdata); - if (res) - return; - res = generic_write_end(NULL, mapping, size, 0, 0, - folio, fsdata); - if (res < 0) - return; - mark_inode_dirty(inode); return; } else if (inode->i_size == hip->phys_size) return; diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index ea0e35119d73..79d9134b284e 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -461,6 +461,7 @@ void hfsplus_file_truncate(struct inode *inode); /* inode.c */ extern const struct address_space_operations hfsplus_aops; +extern const struct address_space_operations hfsplus_symlink_aops; extern const struct address_space_operations hfsplus_btree_aops; extern const struct dentry_operations hfsplus_dentry_operations; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 9d25e6224ee5..1ac99ce0dd3b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -18,12 +18,14 @@ #include #include #include +#include #include "hfsplus_fs.h" #include "hfsplus_raw.h" #include "xattr.h" +#include "iomap.h" -static int hfsplus_read_folio(struct file *file, struct folio *folio) +static int hfsplus_legacy_read_folio(struct file *file, struct folio *folio) { return block_read_full_folio(folio, hfsplus_get_block); } @@ -128,66 +130,7 @@ static bool hfsplus_release_folio(struct folio *folio, gfp_t mask) return res ? try_to_free_buffers(folio) : false; } -static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - loff_t isize; - size_t count = iov_iter_count(iter); - loff_t end = iocb->ki_pos + count; - ssize_t ret; - - /* - * The hfsplus_get_block() only allows creating the next sequential block. - * For direct writes beyond EOF, expand the file first. - */ - if (iov_iter_rw(iter) == WRITE && iocb->ki_pos > i_size_read(inode)) { - loff_t start_off, end_off; - loff_t start_page, end_page; - - isize = i_size_read(inode); - - /* - * Wait for any in-flight DIO on this inode to finish before - * calling generic_cont_expand_simple(). - */ - inode_dio_wait(inode); - - ret = generic_cont_expand_simple(inode, iocb->ki_pos); - if (ret) - return ret; - - start_off = isize; - end_off = (end > 0) ? end - 1 : end; - - ret = filemap_write_and_wait_range(mapping, start_off, end_off); - if (ret) - return ret; - - start_page = start_off >> PAGE_SHIFT; - end_page = end_off >> PAGE_SHIFT; - - invalidate_inode_pages2_range(mapping, start_page, end_page); - } - - ret = blockdev_direct_IO(iocb, inode, iter, hfsplus_get_block); - - /* - * In case of error extending write may have instantiated a few - * blocks outside i_size. Trim these off again. - */ - if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { - isize = i_size_read(inode); - - if (end > isize) - hfsplus_write_failed(mapping, end); - } - - return ret; -} - -static int hfsplus_writepages(struct address_space *mapping, +static int hfsplus_legacy_writepages(struct address_space *mapping, struct writeback_control *wbc) { return mpage_writepages(mapping, wbc, hfsplus_get_block); @@ -196,8 +139,8 @@ static int hfsplus_writepages(struct address_space *mapping, const struct address_space_operations hfsplus_btree_aops = { .dirty_folio = block_dirty_folio, .invalidate_folio = block_invalidate_folio, - .read_folio = hfsplus_read_folio, - .writepages = hfsplus_writepages, + .read_folio = hfsplus_legacy_read_folio, + .writepages = hfsplus_legacy_writepages, .write_begin = hfsplus_write_begin, .write_end = generic_write_end, .migrate_folio = buffer_migrate_folio, @@ -205,18 +148,59 @@ const struct address_space_operations hfsplus_btree_aops = { .release_folio = hfsplus_release_folio, }; -const struct address_space_operations hfsplus_aops = { +const struct address_space_operations hfsplus_symlink_aops = { .dirty_folio = block_dirty_folio, .invalidate_folio = block_invalidate_folio, - .read_folio = hfsplus_read_folio, + .read_folio = hfsplus_legacy_read_folio, .write_begin = hfsplus_write_begin, .write_end = generic_write_end, .bmap = hfsplus_bmap, - .direct_IO = hfsplus_direct_IO, - .writepages = hfsplus_writepages, + .writepages = hfsplus_legacy_writepages, .migrate_folio = buffer_migrate_folio, }; +static int hfsplus_read_folio(struct file *file, struct folio *folio) +{ + iomap_bio_read_folio(folio, &hfsplus_iomap_ops); + return 0; +} + +static void hfsplus_readahead(struct readahead_control *rac) +{ + iomap_bio_readahead(rac, &hfsplus_iomap_ops); +} + +static int hfsplus_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct iomap_writepage_ctx wpc = { + .inode = mapping->host, + .wbc = wbc, + .ops = &hfsplus_writeback_ops, + }; + + return iomap_writepages(&wpc); +} + +static sector_t hfsplus_aop_bmap(struct address_space *mapping, sector_t block) +{ + return iomap_bmap(mapping, block, &hfsplus_iomap_ops); +} + +const struct address_space_operations hfsplus_aops = { + .read_folio = hfsplus_read_folio, + .readahead = hfsplus_readahead, + .writepages = hfsplus_writepages, + .dirty_folio = iomap_dirty_folio, + .bmap = hfsplus_aop_bmap, + .migrate_folio = filemap_migrate_folio, + .is_partially_uptodate = iomap_is_partially_uptodate, + .error_remove_folio = generic_error_remove_folio, + .release_folio = iomap_release_folio, + .invalidate_folio = iomap_invalidate_folio, + .swap_activate = hfsplus_iomap_swap_activate, +}; + const struct dentry_operations hfsplus_dentry_operations = { .d_hash = hfsplus_hash_dentry, .d_compare = hfsplus_compare_dentry, @@ -290,10 +274,22 @@ static int hfsplus_setattr(struct mnt_idmap *idmap, attr->ia_size != i_size_read(inode)) { inode_dio_wait(inode); if (attr->ia_size > inode->i_size) { - error = generic_cont_expand_simple(inode, - attr->ia_size); - if (error) - return error; + if (S_ISREG(inode->i_mode)) { + loff_t old_size = inode->i_size; + + i_size_write(inode, attr->ia_size); + error = hfsplus_iomap_cont_expand(inode, + attr->ia_size); + if (error) { + i_size_write(inode, old_size); + return error; + } + } else { + error = generic_cont_expand_simple(inode, + attr->ia_size); + if (error) + return error; + } } truncate_setsize(inode, attr->ia_size); hfsplus_file_truncate(inode); @@ -399,7 +395,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, struct inode *dir, sbi->file_count++; inode->i_op = &hfsplus_symlink_inode_operations; inode_nohighmem(inode); - inode->i_mapping->a_ops = &hfsplus_aops; + inode->i_mapping->a_ops = &hfsplus_symlink_aops; hip->clump_blocks = 1; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { @@ -540,7 +536,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &hfsplus_symlink_inode_operations; inode_nohighmem(inode); - inode->i_mapping->a_ops = &hfsplus_aops; + inode->i_mapping->a_ops = &hfsplus_symlink_aops; } else { inode->i_op = &hfsplus_special_inode_operations; init_special_inode(inode, inode->i_mode, -- 2.43.0