[RFC PATCH 5/9] ext4: remove dead inline data write code

Yun Zhou <[email protected]> Mon, 27 Jul 2026 18:54:37 +0800
Newsgroups org.kernel.vger.linux-ext4,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Now that inline data write paths for regular files always convert to
block format, the following unreachable dead code is removed:

- ext4_write_inline_data_end(): was called from write_end when
  EXT4_WRITE_DATA_INLINE was set in fsdata, which no longer happens
- ext4_convert_inline_data_to_extent(): was the unsafe convert path
  (no restore on failure), replaced by ext4_convert_inline_data()
- EXT4_WRITE_DATA_INLINE flag and all associated checks in inode.c

Signed-off-by: Yun Zhou <[email protected]>
---
 fs/ext4/ext4.h   |   3 -
 fs/ext4/inline.c | 210 -----------------------------------------------
 fs/ext4/inode.c  |  22 -----
 3 files changed, 235 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 5f0448b960fe..832bc1f3b600 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3148,7 +3148,6 @@ int do_journal_get_write_access(handle_t *handle, struct inode *inode,
 				struct buffer_head *bh);
 void ext4_set_inode_mapping_order(struct inode *inode);
 #define FALL_BACK_TO_NONDELALLOC 1
-#define EXT4_WRITE_DATA_INLINE	 2
 
 typedef enum {
 	EXT4_IGET_NORMAL =	0,
@@ -3759,8 +3758,6 @@ extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
 extern void ext4_update_final_de(void *de_buf, int old_size, int new_size);
 
 int ext4_readpage_inline(struct inode *inode, struct folio *folio);
-int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
-			       unsigned copied, struct folio *folio);
 extern int ext4_generic_write_inline_data(struct address_space *mapping,
 					  struct inode *inode,
 					  loff_t pos, unsigned len,
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 0803fa8eade7..5c6202add3d8 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -568,122 +568,6 @@ 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)
-{
-	int ret, needed_blocks, no_expand;
-	handle_t *handle = NULL;
-	int retries = 0, sem_held = 0;
-	struct folio *folio = NULL;
-	unsigned from, to;
-	struct ext4_iloc iloc;
-
-	if (!ext4_has_inline_data(inode)) {
-		/*
-		 * clear the flag so that no new write
-		 * will trap here again.
-		 */
-		ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
-		return 0;
-	}
-
-	needed_blocks = ext4_chunk_trans_extent(inode, 1);
-
-	ret = ext4_get_inode_loc(inode, &iloc);
-	if (ret)
-		return ret;
-
-retry:
-	handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks);
-	if (IS_ERR(handle)) {
-		ret = PTR_ERR(handle);
-		handle = NULL;
-		goto out;
-	}
-
-	/* We cannot recurse into the filesystem as the transaction is already
-	 * started */
-	folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS,
-			mapping_gfp_mask(mapping));
-	if (IS_ERR(folio)) {
-		ret = PTR_ERR(folio);
-		goto out_nofolio;
-	}
-
-	ext4_write_lock_xattr(inode, &no_expand);
-	sem_held = 1;
-	/* If some one has already done this for us, just exit. */
-	if (!ext4_has_inline_data(inode)) {
-		ret = 0;
-		goto out;
-	}
-
-	from = 0;
-	to = ext4_get_inline_size(inode);
-	if (!folio_test_uptodate(folio)) {
-		ret = ext4_read_inline_folio(inode, folio);
-		if (ret < 0)
-			goto out;
-	}
-
-	ext4_fc_track_inode(handle, inode);
-	ret = ext4_destroy_inline_data_nolock(handle, inode);
-	if (ret)
-		goto out;
-
-	if (ext4_should_dioread_nolock(inode)) {
-		ret = ext4_block_write_begin(handle, folio, from, to,
-					     ext4_get_block_unwritten);
-	} else
-		ret = ext4_block_write_begin(handle, folio, from, to,
-					     ext4_get_block);
-	clear_buffer_new(folio_buffers(folio));
-
-	if (!ret && ext4_should_journal_data(inode)) {
-		ret = ext4_walk_page_buffers(handle, inode,
-					     folio_buffers(folio), from, to,
-					     NULL, do_journal_get_write_access);
-	}
-
-	if (ret) {
-		folio_unlock(folio);
-		folio_put(folio);
-		folio = NULL;
-		ext4_orphan_add(handle, inode);
-		ext4_write_unlock_xattr(inode, &no_expand);
-		sem_held = 0;
-		ext4_journal_stop(handle);
-		handle = NULL;
-		ext4_truncate_failed_write(inode);
-		/*
-		 * If truncate failed early the inode might
-		 * still be on the orphan list; we need to
-		 * make sure the inode is removed from the
-		 * orphan list in that case.
-		 */
-		if (inode->i_nlink)
-			ext4_orphan_del(NULL, inode);
-	}
-
-	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
-		goto retry;
-
-	if (folio)
-		block_commit_write(folio, from, to);
-out:
-	if (folio) {
-		folio_unlock(folio);
-		folio_put(folio);
-	}
-out_nofolio:
-	if (sem_held)
-		ext4_write_unlock_xattr(inode, &no_expand);
-	if (handle)
-		ext4_journal_stop(handle);
-	brelse(iloc.bh);
-	return ret;
-}
-
 /*
  * Prepare the write for the inline data.
  * If the data can be written into the inode, we just read
@@ -712,100 +596,6 @@ int ext4_generic_write_inline_data(struct address_space *mapping,
 	return ret;
 }
 
-int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
-			       unsigned copied, struct folio *folio)
-{
-	handle_t *handle = ext4_journal_current_handle();
-	int no_expand;
-	void *kaddr;
-	struct ext4_iloc iloc;
-	int ret = 0, ret2;
-
-	if (unlikely(copied < len) && !folio_test_uptodate(folio))
-		copied = 0;
-
-	if (likely(copied)) {
-		ret = ext4_get_inode_loc(inode, &iloc);
-		if (ret) {
-			folio_unlock(folio);
-			folio_put(folio);
-			ext4_std_error(inode->i_sb, ret);
-			goto out;
-		}
-		ext4_write_lock_xattr(inode, &no_expand);
-		/*
-		 * We could have raced with ext4_page_mkwrite() converting
-		 * the inode and clearing the inline data flag, so we just
-		 * release resources and retry the whole write.
-		 */
-		if (unlikely(!ext4_has_inline_data(inode))) {
-			ext4_write_unlock_xattr(inode, &no_expand);
-			brelse(iloc.bh);
-			folio_unlock(folio);
-			folio_put(folio);
-			ext4_journal_stop(handle);
-			return 0;
-		}
-
-		/*
-		 * ei->i_inline_off may have changed since
-		 * ext4_write_begin() called
-		 * ext4_convert_inline_data()
-		 */
-		(void) ext4_find_inline_data_nolock(inode);
-
-		kaddr = kmap_local_folio(folio, 0);
-		ext4_write_inline_data(inode, &iloc, kaddr, pos, copied);
-		kunmap_local(kaddr);
-		folio_mark_uptodate(folio);
-		/* clear dirty flag so that writepages wouldn't work for us. */
-		folio_clear_dirty(folio);
-
-		ext4_write_unlock_xattr(inode, &no_expand);
-		brelse(iloc.bh);
-
-		/*
-		 * It's important to update i_size while still holding folio
-		 * lock: page writeout could otherwise come in and zero
-		 * beyond i_size.
-		 */
-		ext4_update_inode_size(inode, pos + copied);
-	}
-	folio_unlock(folio);
-	folio_put(folio);
-
-	/*
-	 * Don't mark the inode dirty under folio lock. First, it unnecessarily
-	 * makes the holding time of folio lock longer. Second, it forces lock
-	 * ordering of folio lock and transaction start for journaling
-	 * filesystems.
-	 */
-	if (likely(copied))
-		mark_inode_dirty(inode);
-out:
-	/*
-	 * If we didn't copy as much data as expected, we need to trim back
-	 * size of xattr containing inline data.
-	 */
-	if (pos + len > inode->i_size && ext4_can_truncate(inode))
-		ext4_orphan_add(handle, inode);
-
-	ret2 = ext4_journal_stop(handle);
-	if (!ret)
-		ret = ret2;
-	if (pos + len > inode->i_size) {
-		ext4_truncate_failed_write(inode);
-		/*
-		 * If truncate failed early the inode might still be
-		 * on the orphan list; we need to make sure the inode
-		 * is removed from the orphan list in that case.
-		 */
-		if (inode->i_nlink)
-			ext4_orphan_del(NULL, inode);
-	}
-	return ret ? ret : copied;
-}
-
 /*
  * Try to make the page cache and handle ready for the inline data case.
  * We can call this function in 2 cases:
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index f9e1f0a6024d..2256fb3826a9 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1300,8 +1300,6 @@ static int ext4_write_begin(const struct kiocb *iocb,
 	if (unlikely(ret))
 		return ret;
 
-	*fsdata = (void *)((unsigned long)*fsdata & ~EXT4_WRITE_DATA_INLINE);
-
 	trace_ext4_write_begin(inode, pos, len);
 	/*
 	 * Reserve one block more for addition to orphan list in case
@@ -1315,10 +1313,6 @@ static int ext4_write_begin(const struct kiocb *iocb,
 		ret = ext4_convert_inline_data(inode);
 		if (ret < 0)
 			return ret;
-		if (ret == 1) {
-			*fsdata = (void *)((unsigned long)*fsdata | EXT4_WRITE_DATA_INLINE);
-			return 0;
-		}
 	}
 
 	/*
@@ -1451,10 +1445,6 @@ static int ext4_write_end(const struct kiocb *iocb,
 
 	trace_ext4_write_end(inode, pos, len, copied);
 
-	if ((unsigned long)fsdata & EXT4_WRITE_DATA_INLINE)
-		return ext4_write_inline_data_end(inode, pos, len, copied,
-						  folio);
-
 	copied = block_write_end(pos, len, copied, folio);
 	/*
 	 * it's important to update i_size while still holding folio lock:
@@ -1560,10 +1550,6 @@ static int ext4_journalled_write_end(const struct kiocb *iocb,
 
 	BUG_ON(!ext4_handle_valid(handle));
 
-	if ((unsigned long)fsdata & EXT4_WRITE_DATA_INLINE)
-		return ext4_write_inline_data_end(inode, pos, len, copied,
-						  folio);
-
 	if (unlikely(copied < len) && !folio_test_uptodate(folio)) {
 		copied = 0;
 		ext4_journalled_zero_new_buffers(handle, inode, folio,
@@ -3172,10 +3158,6 @@ static int ext4_da_write_begin(const struct kiocb *iocb,
 						     foliop, true);
 		if (ret < 0)
 			return ret;
-		if (ret == 1) {
-			*fsdata = (void *)((unsigned long)*fsdata | EXT4_WRITE_DATA_INLINE);
-			return 0;
-		}
 	}
 
 retry:
@@ -3312,10 +3294,6 @@ static int ext4_da_write_end(const struct kiocb *iocb,
 
 	trace_ext4_da_write_end(inode, pos, len, copied);
 
-	if (write_mode & EXT4_WRITE_DATA_INLINE)
-		return ext4_write_inline_data_end(inode, pos, len, copied,
-						  folio);
-
 	if (unlikely(copied < len) && !folio_test_uptodate(folio))
 		copied = 0;
 
-- 
2.43.0