diff mbox series

[6/7] ext4: Convert to buffered_write_operations

Message ID 20240528164829.2105447-7-willy@infradead.org
State Not Applicable
Headers show
Series Start moving write_begin/write_end out of aops | expand

Commit Message

Matthew Wilcox May 28, 2024, 4:48 p.m. UTC
Pass the appropriate buffered_write_operations to filemap_perform_write().
Saves a lot of page<->folio conversions.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 fs/buffer.c      |   2 +-
 fs/ext4/ext4.h   |  24 ++++-----
 fs/ext4/file.c   |  12 ++++-
 fs/ext4/inline.c |  66 ++++++++++-------------
 fs/ext4/inode.c  | 134 ++++++++++++++++++++---------------------------
 5 files changed, 108 insertions(+), 130 deletions(-)

Comments

kernel test robot May 28, 2024, 11:42 p.m. UTC | #1
Hi Matthew,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.10-rc1 next-20240528]
[cannot apply to tytso-ext4/dev jack-fs/for_next hch-configfs/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Matthew-Wilcox-Oracle/fs-Introduce-buffered_write_operations/20240529-005213
base:   linus/master
patch link:    https://lore.kernel.org/r/20240528164829.2105447-7-willy%40infradead.org
patch subject: [PATCH 6/7] ext4: Convert to buffered_write_operations
config: hexagon-defconfig (https://download.01.org/0day-ci/archive/20240529/202405290727.QWBqNxqa-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project bafda89a0944d947fc4b3b5663185e07a397ac30)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240529/202405290727.QWBqNxqa-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405290727.QWBqNxqa-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from fs/ext4/inline.c:7:
   In file included from include/linux/iomap.h:7:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:10:
   In file included from include/linux/mm.h:2253:
   include/linux/vmstat.h:514:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     514 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
   In file included from fs/ext4/inline.c:7:
   In file included from include/linux/iomap.h:7:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:14:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:548:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     548 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:561:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     561 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from fs/ext4/inline.c:7:
   In file included from include/linux/iomap.h:7:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:14:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:574:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     574 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from fs/ext4/inline.c:7:
   In file included from include/linux/iomap.h:7:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:14:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:585:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     585 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:595:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     595 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:605:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     605 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
>> fs/ext4/inline.c:914:7: warning: variable 'folio' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
     914 |                 if (ret == -ENOSPC &&
         |                     ^~~~~~~~~~~~~~~~~
     915 |                     ext4_should_retry_alloc(inode->i_sb, &retries))
         |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   fs/ext4/inline.c:956:9: note: uninitialized use occurs here
     956 |         return folio;
         |                ^~~~~
   fs/ext4/inline.c:914:3: note: remove the 'if' if its condition is always true
     914 |                 if (ret == -ENOSPC &&
         |                 ^~~~~~~~~~~~~~~~~~~~~
     915 |                     ext4_should_retry_alloc(inode->i_sb, &retries))
         |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     916 |                         goto retry_journal;
>> fs/ext4/inline.c:914:7: warning: variable 'folio' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
     914 |                 if (ret == -ENOSPC &&
         |                     ^~~~~~~~~~~~~~
   fs/ext4/inline.c:956:9: note: uninitialized use occurs here
     956 |         return folio;
         |                ^~~~~
   fs/ext4/inline.c:914:7: note: remove the '&&' if its condition is always true
     914 |                 if (ret == -ENOSPC &&
         |                     ^~~~~~~~~~~~~~~~~
>> fs/ext4/inline.c:907:6: warning: variable 'folio' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     907 |         if (ret && ret != -ENOSPC)
         |             ^~~~~~~~~~~~~~~~~~~~~
   fs/ext4/inline.c:956:9: note: uninitialized use occurs here
     956 |         return folio;
         |                ^~~~~
   fs/ext4/inline.c:907:2: note: remove the 'if' if its condition is always false
     907 |         if (ret && ret != -ENOSPC)
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
     908 |                 goto out_journal;
         |                 ~~~~~~~~~~~~~~~~
   fs/ext4/inline.c:901:6: warning: variable 'folio' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     901 |         if (IS_ERR(handle)) {
         |             ^~~~~~~~~~~~~~
   fs/ext4/inline.c:956:9: note: uninitialized use occurs here
     956 |         return folio;
         |                ^~~~~
   fs/ext4/inline.c:901:2: note: remove the 'if' if its condition is always false
     901 |         if (IS_ERR(handle)) {
         |         ^~~~~~~~~~~~~~~~~~~~~
     902 |                 ret = PTR_ERR(handle);
         |                 ~~~~~~~~~~~~~~~~~~~~~~
     903 |                 goto out;
         |                 ~~~~~~~~~
     904 |         }
         |         ~
   fs/ext4/inline.c:891:21: note: initialize the variable 'folio' to silence this warning
     891 |         struct folio *folio;
         |                            ^
         |                             = NULL
   11 warnings generated.


vim +914 fs/ext4/inline.c

9c3569b50f12e47 Tao Ma                  2012-12-10  877  
9c3569b50f12e47 Tao Ma                  2012-12-10  878  /*
9c3569b50f12e47 Tao Ma                  2012-12-10  879   * Prepare the write for the inline data.
8d6ce136790268f Shijie Luo              2020-01-23  880   * If the data can be written into the inode, we just read
9c3569b50f12e47 Tao Ma                  2012-12-10  881   * the page and make it uptodate, and start the journal.
9c3569b50f12e47 Tao Ma                  2012-12-10  882   * Otherwise read the page, makes it dirty so that it can be
9c3569b50f12e47 Tao Ma                  2012-12-10  883   * handle in writepages(the i_disksize update is left to the
9c3569b50f12e47 Tao Ma                  2012-12-10  884   * normal ext4_da_write_end).
9c3569b50f12e47 Tao Ma                  2012-12-10  885   */
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  886) struct folio *ext4_da_write_inline_data_begin(struct address_space *mapping,
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  887) 		struct inode *inode, loff_t pos, size_t len)
9c3569b50f12e47 Tao Ma                  2012-12-10  888  {
09355d9d038a159 Ritesh Harjani          2022-01-17  889  	int ret;
9c3569b50f12e47 Tao Ma                  2012-12-10  890  	handle_t *handle;
9a9d01f081ea29a Matthew Wilcox          2023-03-24  891  	struct folio *folio;
9c3569b50f12e47 Tao Ma                  2012-12-10  892  	struct ext4_iloc iloc;
625ef8a3acd111d Lukas Czerner           2018-10-02  893  	int retries = 0;
9c3569b50f12e47 Tao Ma                  2012-12-10  894  
9c3569b50f12e47 Tao Ma                  2012-12-10  895  	ret = ext4_get_inode_loc(inode, &iloc);
9c3569b50f12e47 Tao Ma                  2012-12-10  896  	if (ret)
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  897) 		return ERR_PTR(ret);
9c3569b50f12e47 Tao Ma                  2012-12-10  898  
bc0ca9df3b2abb1 Jan Kara                2014-01-06  899  retry_journal:
9924a92a8c21757 Theodore Ts'o           2013-02-08  900  	handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
9c3569b50f12e47 Tao Ma                  2012-12-10  901  	if (IS_ERR(handle)) {
9c3569b50f12e47 Tao Ma                  2012-12-10  902  		ret = PTR_ERR(handle);
9c3569b50f12e47 Tao Ma                  2012-12-10  903  		goto out;
9c3569b50f12e47 Tao Ma                  2012-12-10  904  	}
9c3569b50f12e47 Tao Ma                  2012-12-10  905  
9c3569b50f12e47 Tao Ma                  2012-12-10  906  	ret = ext4_prepare_inline_data(handle, inode, pos + len);
9c3569b50f12e47 Tao Ma                  2012-12-10 @907  	if (ret && ret != -ENOSPC)
52e4477758eef45 Jan Kara                2014-01-06  908  		goto out_journal;
9c3569b50f12e47 Tao Ma                  2012-12-10  909  
9c3569b50f12e47 Tao Ma                  2012-12-10  910  	if (ret == -ENOSPC) {
8bc1379b82b8e80 Theodore Ts'o           2018-06-16  911  		ext4_journal_stop(handle);
9c3569b50f12e47 Tao Ma                  2012-12-10  912  		ret = ext4_da_convert_inline_data_to_extent(mapping,
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  913) 							    inode);
bc0ca9df3b2abb1 Jan Kara                2014-01-06 @914  		if (ret == -ENOSPC &&
bc0ca9df3b2abb1 Jan Kara                2014-01-06  915  		    ext4_should_retry_alloc(inode->i_sb, &retries))
bc0ca9df3b2abb1 Jan Kara                2014-01-06  916  			goto retry_journal;
9c3569b50f12e47 Tao Ma                  2012-12-10  917  		goto out;
9c3569b50f12e47 Tao Ma                  2012-12-10  918  	}
9c3569b50f12e47 Tao Ma                  2012-12-10  919  
36d116e99da7e45 Matthew Wilcox (Oracle  2022-02-22  920) 	/*
36d116e99da7e45 Matthew Wilcox (Oracle  2022-02-22  921) 	 * We cannot recurse into the filesystem as the transaction
36d116e99da7e45 Matthew Wilcox (Oracle  2022-02-22  922) 	 * is already started.
36d116e99da7e45 Matthew Wilcox (Oracle  2022-02-22  923) 	 */
9a9d01f081ea29a Matthew Wilcox          2023-03-24  924  	folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS,
9a9d01f081ea29a Matthew Wilcox          2023-03-24  925  					mapping_gfp_mask(mapping));
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  926) 	if (IS_ERR(folio))
52e4477758eef45 Jan Kara                2014-01-06  927  		goto out_journal;
9c3569b50f12e47 Tao Ma                  2012-12-10  928  
9c3569b50f12e47 Tao Ma                  2012-12-10  929  	down_read(&EXT4_I(inode)->xattr_sem);
9c3569b50f12e47 Tao Ma                  2012-12-10  930  	if (!ext4_has_inline_data(inode)) {
9c3569b50f12e47 Tao Ma                  2012-12-10  931  		ret = 0;
9c3569b50f12e47 Tao Ma                  2012-12-10  932  		goto out_release_page;
9c3569b50f12e47 Tao Ma                  2012-12-10  933  	}
9c3569b50f12e47 Tao Ma                  2012-12-10  934  
9a9d01f081ea29a Matthew Wilcox          2023-03-24  935  	if (!folio_test_uptodate(folio)) {
6b87fbe4155007c Matthew Wilcox          2023-03-24  936  		ret = ext4_read_inline_folio(inode, folio);
9c3569b50f12e47 Tao Ma                  2012-12-10  937  		if (ret < 0)
9c3569b50f12e47 Tao Ma                  2012-12-10  938  			goto out_release_page;
9c3569b50f12e47 Tao Ma                  2012-12-10  939  	}
188c299e2a26cc3 Jan Kara                2021-08-16  940  	ret = ext4_journal_get_write_access(handle, inode->i_sb, iloc.bh,
188c299e2a26cc3 Jan Kara                2021-08-16  941  					    EXT4_JTR_NONE);
362eca70b53389b Theodore Ts'o           2018-07-10  942  	if (ret)
362eca70b53389b Theodore Ts'o           2018-07-10  943  		goto out_release_page;
9c3569b50f12e47 Tao Ma                  2012-12-10  944  
9c3569b50f12e47 Tao Ma                  2012-12-10  945  	up_read(&EXT4_I(inode)->xattr_sem);
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  946) 	goto out;
9c3569b50f12e47 Tao Ma                  2012-12-10  947  out_release_page:
9c3569b50f12e47 Tao Ma                  2012-12-10  948  	up_read(&EXT4_I(inode)->xattr_sem);
9a9d01f081ea29a Matthew Wilcox          2023-03-24  949  	folio_unlock(folio);
9a9d01f081ea29a Matthew Wilcox          2023-03-24  950  	folio_put(folio);
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  951) 	folio = ERR_PTR(ret);
52e4477758eef45 Jan Kara                2014-01-06  952  out_journal:
9c3569b50f12e47 Tao Ma                  2012-12-10  953  	ext4_journal_stop(handle);
52e4477758eef45 Jan Kara                2014-01-06  954  out:
9c3569b50f12e47 Tao Ma                  2012-12-10  955  	brelse(iloc.bh);
8ca000469995a1f Matthew Wilcox (Oracle  2024-05-28  956) 	return folio;
9c3569b50f12e47 Tao Ma                  2012-12-10  957  }
9c3569b50f12e47 Tao Ma                  2012-12-10  958
diff mbox series

Patch

diff --git a/fs/buffer.c b/fs/buffer.c
index 4064b21fe499..98f116e8abde 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2299,7 +2299,7 @@  int block_write_end(struct file *file, struct address_space *mapping,
 			loff_t pos, unsigned len, unsigned copied,
 			struct page *page, void *fsdata)
 {
-	return buffer_write_end(file, mapping, pos, len, copied,
+	return __buffer_write_end(file, mapping, pos, len, copied,
 			page_folio(page));
 }
 EXPORT_SYMBOL(block_write_end);
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 983dad8c07ec..b6f7509e3f55 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2971,8 +2971,6 @@  int ext4_walk_page_buffers(handle_t *handle,
 				     struct buffer_head *bh));
 int do_journal_get_write_access(handle_t *handle, struct inode *inode,
 				struct buffer_head *bh);
-#define FALL_BACK_TO_NONDELALLOC 1
-#define CONVERT_INLINE_DATA	 2
 
 typedef enum {
 	EXT4_IGET_NORMAL =	0,
@@ -3011,6 +3009,7 @@  extern int ext4_break_layouts(struct inode *);
 extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length);
 extern void ext4_set_inode_flags(struct inode *, bool init);
 extern int ext4_alloc_da_blocks(struct inode *inode);
+int ext4_nonda_switch(struct super_block *sb);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_normal_submit_inode_data_buffers(struct jbd2_inode *jinode);
@@ -3026,6 +3025,10 @@  extern void ext4_da_update_reserve_space(struct inode *inode,
 extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk,
 			      ext4_fsblk_t pblk, ext4_lblk_t len);
 
+extern const struct buffered_write_operations ext4_bw_ops;
+extern const struct buffered_write_operations ext4_journalled_bw_ops;
+extern const struct buffered_write_operations ext4_da_bw_ops;
+
 /* indirect.c */
 extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
 				struct ext4_map_blocks *map, int flags);
@@ -3551,17 +3554,12 @@  extern int ext4_find_inline_data_nolock(struct inode *inode);
 extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
 
 int ext4_readpage_inline(struct inode *inode, struct folio *folio);
-extern int ext4_try_to_write_inline_data(struct address_space *mapping,
-					 struct inode *inode,
-					 loff_t pos, unsigned len,
-					 struct page **pagep);
-int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
-			       unsigned copied, struct folio *folio);
-extern int ext4_da_write_inline_data_begin(struct address_space *mapping,
-					   struct inode *inode,
-					   loff_t pos, unsigned len,
-					   struct page **pagep,
-					   void **fsdata);
+struct folio *ext4_try_to_write_inline_data(struct address_space *mapping,
+		struct inode *inode, loff_t pos, size_t len);
+size_t ext4_write_inline_data_end(struct inode *inode, loff_t pos, size_t len,
+			       size_t copied, struct folio *folio);
+struct folio *ext4_da_write_inline_data_begin(struct address_space *mapping,
+		struct inode *inode, loff_t pos, size_t len);
 extern int ext4_try_add_inline_entry(handle_t *handle,
 				     struct ext4_filename *fname,
 				     struct inode *dir, struct inode *inode);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index c89e434db6b7..08c2772966a9 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -287,16 +287,26 @@  static ssize_t ext4_buffered_write_iter(struct kiocb *iocb,
 {
 	ssize_t ret;
 	struct inode *inode = file_inode(iocb->ki_filp);
+	const struct buffered_write_operations *ops;
 
 	if (iocb->ki_flags & IOCB_NOWAIT)
 		return -EOPNOTSUPP;
 
+	if (ext4_should_journal_data(inode))
+		ops = &ext4_journalled_bw_ops;
+	else if (test_opt(inode->i_sb, DELALLOC) &&
+		 !ext4_nonda_switch(inode->i_sb) &&
+		 !ext4_verity_in_progress(inode))
+		ops = &ext4_da_bw_ops;
+	else
+		ops = &ext4_bw_ops;
+
 	inode_lock(inode);
 	ret = ext4_write_checks(iocb, from);
 	if (ret <= 0)
 		goto out;
 
-	ret = generic_perform_write(iocb, from);
+	ret = filemap_perform_write(iocb, from, ops, NULL);
 
 out:
 	inode_unlock(inode);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index d5bd1e3a5d36..cb5cb2cc9c2b 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -538,8 +538,9 @@  int ext4_readpage_inline(struct inode *inode, struct folio *folio)
 	return ret >= 0 ? 0 : ret;
 }
 
-static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
-					      struct inode *inode)
+/* Returns NULL on success, ERR_PTR on failure */
+static void *ext4_convert_inline_data_to_extent(struct address_space *mapping,
+		struct inode *inode)
 {
 	int ret, needed_blocks, no_expand;
 	handle_t *handle = NULL;
@@ -554,14 +555,14 @@  static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
 		 * will trap here again.
 		 */
 		ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
-		return 0;
+		return NULL;
 	}
 
 	needed_blocks = ext4_writepage_trans_blocks(inode);
 
 	ret = ext4_get_inode_loc(inode, &iloc);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 retry:
 	handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks);
@@ -648,7 +649,7 @@  static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
 	if (handle)
 		ext4_journal_stop(handle);
 	brelse(iloc.bh);
-	return ret;
+	return ERR_PTR(ret);
 }
 
 /*
@@ -657,10 +658,8 @@  static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
  * in the inode also. If not, create the page the handle, move the data
  * to the page make it update and let the later codes create extent for it.
  */
-int ext4_try_to_write_inline_data(struct address_space *mapping,
-				  struct inode *inode,
-				  loff_t pos, unsigned len,
-				  struct page **pagep)
+struct folio *ext4_try_to_write_inline_data(struct address_space *mapping,
+		struct inode *inode, loff_t pos, size_t len)
 {
 	int ret;
 	handle_t *handle;
@@ -672,7 +671,7 @@  int ext4_try_to_write_inline_data(struct address_space *mapping,
 
 	ret = ext4_get_inode_loc(inode, &iloc);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 	/*
 	 * The possible write could happen in the inode,
@@ -680,7 +679,7 @@  int ext4_try_to_write_inline_data(struct address_space *mapping,
 	 */
 	handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
 	if (IS_ERR(handle)) {
-		ret = PTR_ERR(handle);
+		folio = ERR_CAST(handle);
 		handle = NULL;
 		goto out;
 	}
@@ -703,17 +702,14 @@  int ext4_try_to_write_inline_data(struct address_space *mapping,
 
 	folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS,
 					mapping_gfp_mask(mapping));
-	if (IS_ERR(folio)) {
-		ret = PTR_ERR(folio);
+	if (IS_ERR(folio))
 		goto out;
-	}
 
-	*pagep = &folio->page;
 	down_read(&EXT4_I(inode)->xattr_sem);
 	if (!ext4_has_inline_data(inode)) {
-		ret = 0;
 		folio_unlock(folio);
 		folio_put(folio);
+		folio = NULL;
 		goto out_up_read;
 	}
 
@@ -726,21 +722,22 @@  int ext4_try_to_write_inline_data(struct address_space *mapping,
 		}
 	}
 
-	ret = 1;
 	handle = NULL;
 out_up_read:
 	up_read(&EXT4_I(inode)->xattr_sem);
 out:
-	if (handle && (ret != 1))
+	if (ret < 0)
+		folio = ERR_PTR(ret);
+	if (handle && IS_ERR_OR_NULL(folio))
 		ext4_journal_stop(handle);
 	brelse(iloc.bh);
-	return ret;
+	return folio;
 convert:
 	return ext4_convert_inline_data_to_extent(mapping, inode);
 }
 
-int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
-			       unsigned copied, struct folio *folio)
+size_t ext4_write_inline_data_end(struct inode *inode, loff_t pos, size_t len,
+		size_t copied, struct folio *folio)
 {
 	handle_t *handle = ext4_journal_current_handle();
 	int no_expand;
@@ -831,8 +828,7 @@  int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
  *    need to start the journal since the file's metadata isn't changed now.
  */
 static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping,
-						 struct inode *inode,
-						 void **fsdata)
+						 struct inode *inode)
 {
 	int ret = 0, inline_size;
 	struct folio *folio;
@@ -869,7 +865,6 @@  static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping,
 	folio_mark_dirty(folio);
 	folio_mark_uptodate(folio);
 	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
-	*fsdata = (void *)CONVERT_INLINE_DATA;
 
 out:
 	up_read(&EXT4_I(inode)->xattr_sem);
@@ -888,11 +883,8 @@  static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping,
  * handle in writepages(the i_disksize update is left to the
  * normal ext4_da_write_end).
  */
-int ext4_da_write_inline_data_begin(struct address_space *mapping,
-				    struct inode *inode,
-				    loff_t pos, unsigned len,
-				    struct page **pagep,
-				    void **fsdata)
+struct folio *ext4_da_write_inline_data_begin(struct address_space *mapping,
+		struct inode *inode, loff_t pos, size_t len)
 {
 	int ret;
 	handle_t *handle;
@@ -902,7 +894,7 @@  int ext4_da_write_inline_data_begin(struct address_space *mapping,
 
 	ret = ext4_get_inode_loc(inode, &iloc);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 retry_journal:
 	handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
@@ -918,8 +910,7 @@  int ext4_da_write_inline_data_begin(struct address_space *mapping,
 	if (ret == -ENOSPC) {
 		ext4_journal_stop(handle);
 		ret = ext4_da_convert_inline_data_to_extent(mapping,
-							    inode,
-							    fsdata);
+							    inode);
 		if (ret == -ENOSPC &&
 		    ext4_should_retry_alloc(inode->i_sb, &retries))
 			goto retry_journal;
@@ -932,10 +923,8 @@  int ext4_da_write_inline_data_begin(struct address_space *mapping,
 	 */
 	folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS,
 					mapping_gfp_mask(mapping));
-	if (IS_ERR(folio)) {
-		ret = PTR_ERR(folio);
+	if (IS_ERR(folio))
 		goto out_journal;
-	}
 
 	down_read(&EXT4_I(inode)->xattr_sem);
 	if (!ext4_has_inline_data(inode)) {
@@ -954,18 +943,17 @@  int ext4_da_write_inline_data_begin(struct address_space *mapping,
 		goto out_release_page;
 
 	up_read(&EXT4_I(inode)->xattr_sem);
-	*pagep = &folio->page;
-	brelse(iloc.bh);
-	return 1;
+	goto out;
 out_release_page:
 	up_read(&EXT4_I(inode)->xattr_sem);
 	folio_unlock(folio);
 	folio_put(folio);
+	folio = ERR_PTR(ret);
 out_journal:
 	ext4_journal_stop(handle);
 out:
 	brelse(iloc.bh);
-	return ret;
+	return folio;
 }
 
 #ifdef INLINE_DIR_DEBUG
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 4bae9ccf5fe0..e9526e55e86c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1014,7 +1014,7 @@  int do_journal_get_write_access(handle_t *handle, struct inode *inode,
 
 #ifdef CONFIG_FS_ENCRYPTION
 static int ext4_block_write_begin(struct folio *folio, loff_t pos, unsigned len,
-				  get_block_t *get_block)
+				  get_block_t *get_block, void **fsdata)
 {
 	unsigned from = pos & (PAGE_SIZE - 1);
 	unsigned to = from + len;
@@ -1114,9 +1114,9 @@  static int ext4_block_write_begin(struct folio *folio, loff_t pos, unsigned len,
  * and the ext4_write_end().  So doing the jbd2_journal_start at the start of
  * ext4_write_begin() is the right place.
  */
-static int ext4_write_begin(struct file *file, struct address_space *mapping,
-			    loff_t pos, unsigned len,
-			    struct page **pagep, void **fsdata)
+static struct folio *ext4_write_begin(struct file *file,
+		struct address_space *mapping, loff_t pos, size_t len,
+		void **fsdata)
 {
 	struct inode *inode = mapping->host;
 	int ret, needed_blocks;
@@ -1127,7 +1127,7 @@  static int ext4_write_begin(struct file *file, struct address_space *mapping,
 	unsigned from, to;
 
 	if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-		return -EIO;
+		return ERR_PTR(-EIO);
 
 	trace_ext4_write_begin(inode, pos, len);
 	/*
@@ -1140,12 +1140,9 @@  static int ext4_write_begin(struct file *file, struct address_space *mapping,
 	to = from + len;
 
 	if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
-		ret = ext4_try_to_write_inline_data(mapping, inode, pos, len,
-						    pagep);
-		if (ret < 0)
-			return ret;
-		if (ret == 1)
-			return 0;
+		folio = ext4_try_to_write_inline_data(mapping, inode, pos, len);
+		if (folio)
+			return folio;
 	}
 
 	/*
@@ -1159,7 +1156,7 @@  static int ext4_write_begin(struct file *file, struct address_space *mapping,
 	folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
 					mapping_gfp_mask(mapping));
 	if (IS_ERR(folio))
-		return PTR_ERR(folio);
+		return folio;
 	/*
 	 * The same as page allocation, we prealloc buffer heads before
 	 * starting the handle.
@@ -1173,7 +1170,7 @@  static int ext4_write_begin(struct file *file, struct address_space *mapping,
 	handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks);
 	if (IS_ERR(handle)) {
 		folio_put(folio);
-		return PTR_ERR(handle);
+		return ERR_CAST(handle);
 	}
 
 	folio_lock(folio);
@@ -1190,9 +1187,10 @@  static int ext4_write_begin(struct file *file, struct address_space *mapping,
 #ifdef CONFIG_FS_ENCRYPTION
 	if (ext4_should_dioread_nolock(inode))
 		ret = ext4_block_write_begin(folio, pos, len,
-					     ext4_get_block_unwritten);
+					     ext4_get_block_unwritten, fsdata);
 	else
-		ret = ext4_block_write_begin(folio, pos, len, ext4_get_block);
+		ret = ext4_block_write_begin(folio, pos, len, ext4_get_block,
+				fsdata);
 #else
 	if (ext4_should_dioread_nolock(inode))
 		ret = __block_write_begin(&folio->page, pos, len,
@@ -1239,10 +1237,9 @@  static int ext4_write_begin(struct file *file, struct address_space *mapping,
 		    ext4_should_retry_alloc(inode->i_sb, &retries))
 			goto retry_journal;
 		folio_put(folio);
-		return ret;
+		return ERR_PTR(ret);
 	}
-	*pagep = &folio->page;
-	return ret;
+	return folio;
 }
 
 /* For write_end() in data=journal mode */
@@ -1266,12 +1263,10 @@  static int write_end_fn(handle_t *handle, struct inode *inode,
  * ext4 never places buffers on inode->i_mapping->i_private_list.  metadata
  * buffers are managed internally.
  */
-static int ext4_write_end(struct file *file,
-			  struct address_space *mapping,
-			  loff_t pos, unsigned len, unsigned copied,
-			  struct page *page, void *fsdata)
+static size_t ext4_write_end(struct file *file, struct address_space *mapping,
+		loff_t pos, size_t len, size_t copied, struct folio *folio,
+		void **fsdata)
 {
-	struct folio *folio = page_folio(page);
 	handle_t *handle = ext4_journal_current_handle();
 	struct inode *inode = mapping->host;
 	loff_t old_size = inode->i_size;
@@ -1286,7 +1281,7 @@  static int ext4_write_end(struct file *file,
 		return ext4_write_inline_data_end(inode, pos, len, copied,
 						  folio);
 
-	copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
+	copied = __buffer_write_end(file, mapping, pos, len, copied, folio);
 	/*
 	 * it's important to update i_size while still holding folio lock:
 	 * page writeout could otherwise come in and zero beyond i_size.
@@ -1370,12 +1365,10 @@  static void ext4_journalled_zero_new_buffers(handle_t *handle,
 	} while (bh != head);
 }
 
-static int ext4_journalled_write_end(struct file *file,
-				     struct address_space *mapping,
-				     loff_t pos, unsigned len, unsigned copied,
-				     struct page *page, void *fsdata)
+static size_t ext4_journalled_write_end(struct file *file,
+		struct address_space *mapping, loff_t pos, size_t len,
+		size_t copied, struct folio *folio, void **fsdata)
 {
-	struct folio *folio = page_folio(page);
 	handle_t *handle = ext4_journal_current_handle();
 	struct inode *inode = mapping->host;
 	loff_t old_size = inode->i_size;
@@ -2816,7 +2809,7 @@  static int ext4_dax_writepages(struct address_space *mapping,
 	return ret;
 }
 
-static int ext4_nonda_switch(struct super_block *sb)
+int ext4_nonda_switch(struct super_block *sb)
 {
 	s64 free_clusters, dirty_clusters;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2850,45 +2843,35 @@  static int ext4_nonda_switch(struct super_block *sb)
 	return 0;
 }
 
-static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
-			       loff_t pos, unsigned len,
-			       struct page **pagep, void **fsdata)
+static struct folio *ext4_da_write_begin(struct file *file,
+		struct address_space *mapping, loff_t pos, size_t len,
+		void **fsdata)
 {
 	int ret, retries = 0;
 	struct folio *folio;
-	pgoff_t index;
 	struct inode *inode = mapping->host;
 
 	if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-		return -EIO;
+		return ERR_PTR(-EIO);
 
-	index = pos >> PAGE_SHIFT;
-
-	if (ext4_nonda_switch(inode->i_sb) || ext4_verity_in_progress(inode)) {
-		*fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
-		return ext4_write_begin(file, mapping, pos,
-					len, pagep, fsdata);
-	}
-	*fsdata = (void *)0;
 	trace_ext4_da_write_begin(inode, pos, len);
 
 	if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
-		ret = ext4_da_write_inline_data_begin(mapping, inode, pos, len,
-						      pagep, fsdata);
-		if (ret < 0)
-			return ret;
-		if (ret == 1)
-			return 0;
+		folio = ext4_da_write_inline_data_begin(mapping, inode, pos,
+				len);
+		if (folio)
+			return folio;
 	}
 
 retry:
-	folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
+	folio = __filemap_get_folio(mapping, pos / PAGE_SIZE, FGP_WRITEBEGIN,
 			mapping_gfp_mask(mapping));
 	if (IS_ERR(folio))
-		return PTR_ERR(folio);
+		return folio;
 
 #ifdef CONFIG_FS_ENCRYPTION
-	ret = ext4_block_write_begin(folio, pos, len, ext4_da_get_block_prep);
+	ret = ext4_block_write_begin(folio, pos, len, ext4_da_get_block_prep,
+			fsdata);
 #else
 	ret = __block_write_begin(&folio->page, pos, len, ext4_da_get_block_prep);
 #endif
@@ -2906,11 +2889,10 @@  static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
 		if (ret == -ENOSPC &&
 		    ext4_should_retry_alloc(inode->i_sb, &retries))
 			goto retry;
-		return ret;
+		return ERR_PTR(ret);
 	}
 
-	*pagep = &folio->page;
-	return ret;
+	return folio;
 }
 
 /*
@@ -2936,9 +2918,8 @@  static int ext4_da_should_update_i_disksize(struct folio *folio,
 	return 1;
 }
 
-static int ext4_da_do_write_end(struct address_space *mapping,
-			loff_t pos, unsigned len, unsigned copied,
-			struct folio *folio)
+static size_t ext4_da_do_write_end(struct address_space *mapping, loff_t pos,
+		size_t len, size_t copied, struct folio *folio)
 {
 	struct inode *inode = mapping->host;
 	loff_t old_size = inode->i_size;
@@ -2998,23 +2979,15 @@  static int ext4_da_do_write_end(struct address_space *mapping,
 	return copied;
 }
 
-static int ext4_da_write_end(struct file *file,
-			     struct address_space *mapping,
-			     loff_t pos, unsigned len, unsigned copied,
-			     struct page *page, void *fsdata)
+static size_t ext4_da_write_end(struct file *file,
+		struct address_space *mapping, loff_t pos, size_t len,
+		size_t copied, struct folio *folio, void **fsdata)
 {
 	struct inode *inode = mapping->host;
-	int write_mode = (int)(unsigned long)fsdata;
-	struct folio *folio = page_folio(page);
-
-	if (write_mode == FALL_BACK_TO_NONDELALLOC)
-		return ext4_write_end(file, mapping, pos,
-				      len, copied, &folio->page, fsdata);
 
 	trace_ext4_da_write_end(inode, pos, len, copied);
 
-	if (write_mode != CONVERT_INLINE_DATA &&
-	    ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) &&
+	if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) &&
 	    ext4_has_inline_data(inode))
 		return ext4_write_inline_data_end(inode, pos, len, copied,
 						  folio);
@@ -3521,8 +3494,6 @@  static const struct address_space_operations ext4_aops = {
 	.read_folio		= ext4_read_folio,
 	.readahead		= ext4_readahead,
 	.writepages		= ext4_writepages,
-	.write_begin		= ext4_write_begin,
-	.write_end		= ext4_write_end,
 	.dirty_folio		= ext4_dirty_folio,
 	.bmap			= ext4_bmap,
 	.invalidate_folio	= ext4_invalidate_folio,
@@ -3537,8 +3508,6 @@  static const struct address_space_operations ext4_journalled_aops = {
 	.read_folio		= ext4_read_folio,
 	.readahead		= ext4_readahead,
 	.writepages		= ext4_writepages,
-	.write_begin		= ext4_write_begin,
-	.write_end		= ext4_journalled_write_end,
 	.dirty_folio		= ext4_journalled_dirty_folio,
 	.bmap			= ext4_bmap,
 	.invalidate_folio	= ext4_journalled_invalidate_folio,
@@ -3553,8 +3522,6 @@  static const struct address_space_operations ext4_da_aops = {
 	.read_folio		= ext4_read_folio,
 	.readahead		= ext4_readahead,
 	.writepages		= ext4_writepages,
-	.write_begin		= ext4_da_write_begin,
-	.write_end		= ext4_da_write_end,
 	.dirty_folio		= ext4_dirty_folio,
 	.bmap			= ext4_bmap,
 	.invalidate_folio	= ext4_invalidate_folio,
@@ -3572,6 +3539,21 @@  static const struct address_space_operations ext4_dax_aops = {
 	.swap_activate		= ext4_iomap_swap_activate,
 };
 
+const struct buffered_write_operations ext4_bw_ops = {
+	.write_begin		= ext4_write_begin,
+	.write_end		= ext4_write_end,
+};
+
+const struct buffered_write_operations ext4_journalled_bw_ops = {
+	.write_begin		= ext4_write_begin,
+	.write_end		= ext4_journalled_write_end,
+};
+
+const struct buffered_write_operations ext4_da_bw_ops = {
+	.write_begin		= ext4_da_write_begin,
+	.write_end		= ext4_da_write_end,
+};
+
 void ext4_set_aops(struct inode *inode)
 {
 	switch (ext4_inode_journal_mode(inode)) {