public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] udf: Fix race between file type conversion and writeback
@ 2026-03-25 16:22 Jan Kara
  2026-03-26  5:47 ` Christoph Hellwig
  0 siblings, 1 reply; 3+ messages in thread
From: Jan Kara @ 2026-03-25 16:22 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Christoph Hellwig, Jan Kara, Jianzhou Zhao

udf_setsize() can race with udf_writepages() as follows:

udf_setsize()			udf_writepages()
				  if (iinfo->i_alloc_type ==
						ICBTAG_FLAG_AD_IN_ICB)
  err = udf_expand_file_adinicb(inode);
  err = udf_extend_file(inode, newsize);
				    udf_adinicb_writepages()
				      memcpy_from_file_folio() - crash
					because inode size is too big.

Fix the problem by rechecking file type under folio lock in
udf_writepages() which properly serializes with
udf_expand_file_adinicb(). Since it is quite difficult to implement this
locking with current writeback_iter() logic, let's just opencode the
logic necessary to prepare (the only) folio the inode can have for
writeback.

Reported-by: Jianzhou Zhao <luckd0g@163.com>
Link: https://lore.kernel.org/all/f622c01.67ac.19cdbdd777d.Coremail.luckd0g@163.com
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/udf/inode.c | 53 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 20 deletions(-)

Changes since v1:
* opencode folio_prepare_writeback() in UDF instead of exporting it

I'll merge this fix through my tree.

diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 7fae8002344a..c85b0239660c 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -181,34 +181,47 @@ static void udf_write_failed(struct address_space *mapping, loff_t to)
 	}
 }
 
-static int udf_adinicb_writepages(struct address_space *mapping,
-		      struct writeback_control *wbc)
+static int udf_writepages(struct address_space *mapping,
+			  struct writeback_control *wbc)
 {
 	struct inode *inode = mapping->host;
 	struct udf_inode_info *iinfo = UDF_I(inode);
-	struct folio *folio = NULL;
-	int error = 0;
 
-	while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
-		BUG_ON(!folio_test_locked(folio));
-		BUG_ON(folio->index != 0);
+	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+		struct folio *folio;
+		bool dirty = false;
+
+		folio = filemap_lock_folio(mapping, 0);
+		if (IS_ERR(folio))
+			return 0;
+		/*
+		 * Recheck inode type under folio lock when we are protected
+		 * against udf_expand_file_adinicb(). Bail to standard writeback
+		 * path if file got expanded.
+		 */
+		if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+			folio_unlock(folio);
+			goto mpage_writeback;
+		}
+		if (!folio_test_dirty(folio))
+			goto unlock_folio;
+		if (folio_test_writeback(folio)) {
+			if (wbc->sync_mode == WB_SYNC_NONE)
+				goto unlock_folio;
+			folio_wait_writeback(folio);
+		}
+		if (!folio_clear_dirty_for_io(folio))
+			goto unlock_folio;
 		memcpy_from_file_folio(iinfo->i_data + iinfo->i_lenEAttr, folio,
 				0, i_size_read(inode));
+		dirty = true;
+unlock_folio:
 		folio_unlock(folio);
+		if (dirty)
+			mark_inode_dirty(inode);
+		return 0;
 	}
-
-	mark_inode_dirty(inode);
-	return 0;
-}
-
-static int udf_writepages(struct address_space *mapping,
-			  struct writeback_control *wbc)
-{
-	struct inode *inode = mapping->host;
-	struct udf_inode_info *iinfo = UDF_I(inode);
-
-	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-		return udf_adinicb_writepages(mapping, wbc);
+mpage_writeback:
 	return mpage_writepages(mapping, wbc, udf_get_block_wb);
 }
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] udf: Fix race between file type conversion and writeback
  2026-03-25 16:22 [PATCH v2] udf: Fix race between file type conversion and writeback Jan Kara
@ 2026-03-26  5:47 ` Christoph Hellwig
  2026-03-26 12:29   ` Jan Kara
  0 siblings, 1 reply; 3+ messages in thread
From: Christoph Hellwig @ 2026-03-26  5:47 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, Christoph Hellwig, Jianzhou Zhao

On Wed, Mar 25, 2026 at 05:22:10PM +0100, Jan Kara wrote:
> udf_setsize() can race with udf_writepages() as follows:
> 
> udf_setsize()			udf_writepages()
> 				  if (iinfo->i_alloc_type ==
> 						ICBTAG_FLAG_AD_IN_ICB)
>   err = udf_expand_file_adinicb(inode);
>   err = udf_extend_file(inode, newsize);
> 				    udf_adinicb_writepages()
> 				      memcpy_from_file_folio() - crash
> 					because inode size is too big.
> 
> Fix the problem by rechecking file type under folio lock in
> udf_writepages() which properly serializes with
> udf_expand_file_adinicb(). Since it is quite difficult to implement this
> locking with current writeback_iter() logic, let's just opencode the
> logic necessary to prepare (the only) folio the inode can have for
> writeback.

Still not a fan of open coding this logic, which is even worse than
the previous export.  Inline data is a relatively common case in
various file systems, and we should be able to handle it in common
code.  So having a callback in mpage_writepages seems much better,
but if you detest that we could just export mpage_write_folio and
mpage_bio_submit_write (and make mpage_data public) instead.  I think
that's significantly worse than just adding the callback, but still
much better than open coding more writeback internals, something I
want to get away from.


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] udf: Fix race between file type conversion and writeback
  2026-03-26  5:47 ` Christoph Hellwig
@ 2026-03-26 12:29   ` Jan Kara
  0 siblings, 0 replies; 3+ messages in thread
From: Jan Kara @ 2026-03-26 12:29 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jan Kara, linux-fsdevel, Jianzhou Zhao

On Wed 25-03-26 22:47:40, Christoph Hellwig wrote:
> On Wed, Mar 25, 2026 at 05:22:10PM +0100, Jan Kara wrote:
> > udf_setsize() can race with udf_writepages() as follows:
> > 
> > udf_setsize()			udf_writepages()
> > 				  if (iinfo->i_alloc_type ==
> > 						ICBTAG_FLAG_AD_IN_ICB)
> >   err = udf_expand_file_adinicb(inode);
> >   err = udf_extend_file(inode, newsize);
> > 				    udf_adinicb_writepages()
> > 				      memcpy_from_file_folio() - crash
> > 					because inode size is too big.
> > 
> > Fix the problem by rechecking file type under folio lock in
> > udf_writepages() which properly serializes with
> > udf_expand_file_adinicb(). Since it is quite difficult to implement this
> > locking with current writeback_iter() logic, let's just opencode the
> > logic necessary to prepare (the only) folio the inode can have for
> > writeback.
> 
> Still not a fan of open coding this logic, which is even worse than
> the previous export.  Inline data is a relatively common case in
> various file systems, and we should be able to handle it in common
> code.

I agree inline data is relatively common but as far as I was checking UDF
is the only filesystem using mpage_writepages() that is supporting inline
data (well, OCFS2 does as well but it doesn't bother with inline data
writeback - it handles only write(2) to files with inline data which modify
on disk content directly, they expand the file to extents in case of mmap).
So a special hook in mpage_writepages() for UDF looks like a bit of an
overkill to me.

> So having a callback in mpage_writepages seems much better,
> but if you detest that we could just export mpage_write_folio and
> mpage_bio_submit_write (and make mpage_data public) instead.  I think
> that's significantly worse than just adding the callback, but still
> much better than open coding more writeback internals, something I
> want to get away from.

I agree the callback is better than making all that mpage infrastructure
public. I still think exporting folio_prepare_writeback() would be less
burden than the callback but frankly I don't think it matters enough to
argue further. I just want to get that race fixed :).

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-03-26 12:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-25 16:22 [PATCH v2] udf: Fix race between file type conversion and writeback Jan Kara
2026-03-26  5:47 ` Christoph Hellwig
2026-03-26 12:29   ` Jan Kara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox