mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] ocfs2: fix stale extent map cache during COW operations
@ 2025-10-08  4:23 Deepanshu Kartikey
  2025-10-09  9:14 ` Joseph Qi
  0 siblings, 1 reply; 7+ messages in thread
From: Deepanshu Kartikey @ 2025-10-08  4:23 UTC (permalink / raw)
  To: mark, jlbec, joseph.qi
  Cc: ocfs2-devel, linux-kernel, Deepanshu Kartikey,
	syzbot+6fdd8fa3380730a4b22c

The extent map cache can become stale during COW operations, causing
ocfs2_refcount_cal_cow_clusters() to see an outdated extent state.

The problem occurs when:
1. ocfs2_get_clusters() reads and caches an extent with OCFS2_EXT_REFCOUNTED
2. ocfs2_refcount_cow_hunk() performs COW, clearing the REFCOUNTED flag
3. The extent map cache still contains the stale REFCOUNTED flag
4. Subsequent access on the same extent via the cache gets incorrect flags,
   triggering BUG_ON(!(rec->e_flags & OCFS2_EXT_REFCOUNTED))

Fix by clearing the extent map cache at the start of COW operations.
This ensures that ocfs2_get_clusters() always reads fresh extent data
from disk during COW instead of using stale cached data.

Reported-by: syzbot+6fdd8fa3380730a4b22c@syzkaller.appspotmail.com
Tested-by: syzbot+6fdd8fa3380730a4b22c@syzkaller.appspotmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ocfs2/refcounttree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 267b50e8e42e..e8c8fcdc3dd9 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -3451,7 +3451,8 @@ int ocfs2_refcount_cow(struct inode *inode,
 	int ret = 0;
 	u32 p_cluster, num_clusters;
 	unsigned int ext_flags;
-
+	/* Clear extent map cache before COW operations to avoid stale data */
+	ocfs2_extent_map_trunc(inode, 0);
 	while (write_len) {
 		ret = ocfs2_get_clusters(inode, cpos, &p_cluster,
 					 &num_clusters, &ext_flags);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: [PATCH] ocfs2: fix stale extent map cache during COW operations
@ 2025-10-09 14:29 Deepanshu Kartikey
  2025-10-11  4:50 ` Heming Zhao
  0 siblings, 1 reply; 7+ messages in thread
From: Deepanshu Kartikey @ 2025-10-09 14:29 UTC (permalink / raw)
  To: joseph.qi, mark, jlbec
  Cc: ocfs2-devel, linux-kernel, syzbot+6fdd8fa3380730a4b22c


Hi Joseph,

Thank you for the review. You are absolutely right - the cache clearing at the end of ocfs2_refcount_cow_hunk() should handle the COW path correctly.

After further investigation with the syzbot reproducer and extensive debugging, I found the real issue is in the FITRIM/move_extents code path. The bug occurs when:

1. copy_file_range() creates a reflinked extent with flags=0x2 (OCFS2_EXT_REFCOUNTED)
2. ioctl(FITRIM) is called, which triggers ocfs2_move_extents()
3. In __ocfs2_move_extents_range(), the while loop:
   - Calls ocfs2_get_clusters() which reads extent with flags=0x2 and caches it
   - Then calls ocfs2_move_extent() or ocfs2_defrag_extent()
   - Both eventually call __ocfs2_move_extent() which contains:
       replace_rec.e_flags = ext_flags & ~OCFS2_EXT_REFCOUNTED;
   - This clears the refcount flag and writes to disk with flags=0x0
4. However, the extent map cache is NOT cleared after the move operation
5. Cache still contains stale flags=0x2 while disk has flags=0x0
6. Later, when write() triggers COW, ocfs2_refcount_cal_cow_clusters() reads:
   - From cache: flags=0x2 (stale)
   - From disk extent tree: flags=0x0 (correct)
7. The mismatch triggers: BUG_ON(!(rec->e_flags & OCFS2_EXT_REFCOUNTED))

The proper fix should be in __ocfs2_move_extents_range() to clear the extent cache after each move/defrag operation completes. I will send a v2 patch with this fix.

Thanks,
Deepanshu

^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: [PATCH] ocfs2: fix stale extent map cache during COW operations
@ 2025-10-11  7:42 Deepanshu Kartikey
  0 siblings, 0 replies; 7+ messages in thread
From: Deepanshu Kartikey @ 2025-10-11  7:42 UTC (permalink / raw)
  To: heming.zhao, joseph.qi, mark, jlbec
  Cc: ocfs2-devel, linux-kernel, syzbot+6fdd8fa3380730a4b22c


Hi Heming,

Thank you for the detailed analysis and feedback.

I appreciate your review. However, I'm trying to understand your explanation 
better. You mentioned that step 5 (write with zeros) cleans the file data 
and causes the refcount flag mismatch. 

Looking at the C reproducer, I see:
- Step 7: copy_file_range() creates reflinked extent (flags=0x2)
- Step 8: ioctl(fd, 0x40406f06, ...) which is FITRIM
- Step 9: write() triggers the BUG_ON

In my analysis, step 8 (FITRIM) calls ocfs2_move_extents() -> 
__ocfs2_move_extents_range() -> ocfs2_move_extent() -> __ocfs2_move_extent().

Inside __ocfs2_move_extent() at line 50, I found:
    replace_rec.e_flags = ext_flags & ~OCFS2_EXT_REFCOUNTED;

This explicitly clears the OCFS2_EXT_REFCOUNTED flag when writing to disk, 
but the extent cache is not invalidated afterward.

Could you help me understand:
1. How does the write operation in step 5 clear the refcount flag on disk?
2. Are you suggesting there might be two separate bugs - one in the FITRIM 
   path (which v2 fixes) and another in a different path (which v1 would fix)?

My v2 patch has been merged into linux-next. If you believe v1 addresses a 
different bug scenario, I'm happy to submit it as an additional patch.

Thanks for your time and expertise!

Best regards,
Deepanshu

^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: [PATCH] ocfs2: fix stale extent map cache during COW operations
@ 2025-10-11  8:32 Deepanshu Kartikey
  2025-10-11 12:27 ` Heming Zhao
  0 siblings, 1 reply; 7+ messages in thread
From: Deepanshu Kartikey @ 2025-10-11  8:32 UTC (permalink / raw)
  To: heming.zhao, joseph.qi, mark, jlbec
  Cc: ocfs2-devel, linux-kernel, syzbot+6fdd8fa3380730a4b22c

Hi Heming,

Thank you for the detailed analysis and feedback.

After further investigation, I discovered that the ioctl call in the reproducer 
(0x40406f06) is NOT FITRIM as the syzbot comment suggested. Decoding the ioctl 
number shows:
  - Type: 'o' (0x6f)
  - Number: 6
  - This is OCFS2_IOC_MOVE_EXT (defined in fs/ocfs2/ocfs2_ioctl.h:222)

So the actual call path in the reproducer is:
1. copy_file_range() - creates reflinked extent with flags=0x2
2. ioctl(OCFS2_IOC_MOVE_EXT) - calls ocfs2_move_extents() -> 
   __ocfs2_move_extents_range()
3. write() - triggers BUG_ON

Inside __ocfs2_move_extents_range(), the while loop:
  - Calls ocfs2_get_clusters() which caches the extent with flags=0x2
  - Then calls ocfs2_move_extent() -> __ocfs2_move_extent()
  - __ocfs2_move_extent() at line 50 clears the refcount flag on disk:
      replace_rec.e_flags = ext_flags & ~OCFS2_EXT_REFCOUNTED;
  - But the extent cache is not invalidated

This is exactly what my v2 patch fixes by adding ocfs2_extent_map_trunc() 
after the move operation completes.

Thanks for your time!

Best regards,
Deepanshu

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

end of thread, other threads:[~2025-10-11 12:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-08  4:23 [PATCH] ocfs2: fix stale extent map cache during COW operations Deepanshu Kartikey
2025-10-09  9:14 ` Joseph Qi
2025-10-09 14:29 Deepanshu Kartikey
2025-10-11  4:50 ` Heming Zhao
2025-10-11  7:42 Deepanshu Kartikey
2025-10-11  8:32 Deepanshu Kartikey
2025-10-11 12:27 ` Heming Zhao

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

all inboxes | Powered by JetHome®