]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
d533bbf59f80f37b5f8ce782cf3e305b069444da
[thirdparty/kernel/stable-queue.git] /
1 From 2eb13dd8159ae8a5ccdfbccb9c353f3920a9057a Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Mon, 2 Nov 2020 17:14:06 -0800
4 Subject: xfs: fix missing CoW blocks writeback conversion retry
5
6 From: Darrick J. Wong <darrick.wong@oracle.com>
7
8 [ Upstream commit c2f09217a4305478c55adc9a98692488dd19cd32 ]
9
10 In commit 7588cbeec6df, we tried to fix a race stemming from the lack of
11 coordination between higher level code that wants to allocate and remap
12 CoW fork extents into the data fork. Christoph cites as examples the
13 always_cow mode, and a directio write completion racing with writeback.
14
15 According to the comments before the goto retry, we want to restart the
16 lookup to catch the extent in the data fork, but we don't actually reset
17 whichfork or cow_fsb, which means the second try executes using stale
18 information. Up until now I think we've gotten lucky that either
19 there's something left in the CoW fork to cause cow_fsb to be reset, or
20 either data/cow fork sequence numbers have advanced enough to force a
21 fresh lookup from the data fork. However, if we reach the retry with an
22 empty stable CoW fork and a stable data fork, neither of those things
23 happens. The retry foolishly re-calls xfs_convert_blocks on the CoW
24 fork which fails again. This time, we toss the write.
25
26 I've recently been working on extending reflink to the realtime device.
27 When the realtime extent size is larger than a single block, we have to
28 force the page cache to CoW the entire rt extent if a write (or
29 fallocate) are not aligned with the rt extent size. The strategy I've
30 chosen to deal with this is derived from Dave's blocksize > pagesize
31 series: dirtying around the write range, and ensuring that writeback
32 always starts mapping on an rt extent boundary. This has brought this
33 race front and center, since generic/522 blows up immediately.
34
35 However, I'm pretty sure this is a bug outright, independent of that.
36
37 Fixes: 7588cbeec6df ("xfs: retry COW fork delalloc conversion when no extent was found")
38 Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
39 Reviewed-by: Christoph Hellwig <hch@lst.de>
40 Signed-off-by: Sasha Levin <sashal@kernel.org>
41 ---
42 fs/xfs/xfs_aops.c | 6 ++++--
43 1 file changed, 4 insertions(+), 2 deletions(-)
44
45 diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
46 index b35611882ff9c..e4210779cd79e 100644
47 --- a/fs/xfs/xfs_aops.c
48 +++ b/fs/xfs/xfs_aops.c
49 @@ -346,8 +346,8 @@ xfs_map_blocks(
50 ssize_t count = i_blocksize(inode);
51 xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
52 xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count);
53 - xfs_fileoff_t cow_fsb = NULLFILEOFF;
54 - int whichfork = XFS_DATA_FORK;
55 + xfs_fileoff_t cow_fsb;
56 + int whichfork;
57 struct xfs_bmbt_irec imap;
58 struct xfs_iext_cursor icur;
59 int retries = 0;
60 @@ -381,6 +381,8 @@ xfs_map_blocks(
61 * landed in a hole and we skip the block.
62 */
63 retry:
64 + cow_fsb = NULLFILEOFF;
65 + whichfork = XFS_DATA_FORK;
66 xfs_ilock(ip, XFS_ILOCK_SHARED);
67 ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_BTREE ||
68 (ip->i_df.if_flags & XFS_IFEXTENTS));
69 --
70 2.27.0
71