Skip to content

Commit 70499cd

Browse files
AstralBobAndreas Gruenbacher
authored andcommitted
gfs2: Never call gfs2_block_zero_range with an open transaction
Before this patch, some functions started transactions then they called gfs2_block_zero_range. However, gfs2_block_zero_range, like writes, can start transactions, which results in a recursive transaction error. For example: do_shrink trunc_start gfs2_trans_begin <------------------------------------------------ gfs2_block_zero_range iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops); iomap_apply ... iomap_zero_range_actor iomap_begin gfs2_iomap_begin gfs2_iomap_begin_write actor (iomap_zero_range_actor) iomap_zero iomap_write_begin gfs2_iomap_page_prepare gfs2_trans_begin <------------------------ This patch reorders the callers of gfs2_block_zero_range so that they only start their transactions after the call. It also adds a BUG_ON to ensure this doesn't happen again. Fixes: 2257e46 ("gfs2: implement gfs2_block_zero_range using iomap_zero_range") Cc: [email protected] # v5.5+ Signed-off-by: Bob Peterson <[email protected]> Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent b0be23b commit 70499cd

File tree

1 file changed

+39
-30
lines changed

1 file changed

+39
-30
lines changed

fs/gfs2/bmap.c

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,9 +1351,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
13511351
return ret;
13521352
}
13531353

1354+
/*
1355+
* NOTE: Never call gfs2_block_zero_range with an open transaction because it
1356+
* uses iomap write to perform its actions, which begin their own transactions
1357+
* (iomap_begin, page_prepare, etc.)
1358+
*/
13541359
static int gfs2_block_zero_range(struct inode *inode, loff_t from,
13551360
unsigned int length)
13561361
{
1362+
BUG_ON(current->journal_info);
13571363
return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);
13581364
}
13591365

@@ -1414,6 +1420,16 @@ static int trunc_start(struct inode *inode, u64 newsize)
14141420
u64 oldsize = inode->i_size;
14151421
int error;
14161422

1423+
if (!gfs2_is_stuffed(ip)) {
1424+
unsigned int blocksize = i_blocksize(inode);
1425+
unsigned int offs = newsize & (blocksize - 1);
1426+
if (offs) {
1427+
error = gfs2_block_zero_range(inode, newsize,
1428+
blocksize - offs);
1429+
if (error)
1430+
return error;
1431+
}
1432+
}
14171433
if (journaled)
14181434
error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
14191435
else
@@ -1427,19 +1443,10 @@ static int trunc_start(struct inode *inode, u64 newsize)
14271443

14281444
gfs2_trans_add_meta(ip->i_gl, dibh);
14291445

1430-
if (gfs2_is_stuffed(ip)) {
1446+
if (gfs2_is_stuffed(ip))
14311447
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
1432-
} else {
1433-
unsigned int blocksize = i_blocksize(inode);
1434-
unsigned int offs = newsize & (blocksize - 1);
1435-
if (offs) {
1436-
error = gfs2_block_zero_range(inode, newsize,
1437-
blocksize - offs);
1438-
if (error)
1439-
goto out;
1440-
}
1448+
else
14411449
ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
1442-
}
14431450

14441451
i_size_write(inode, newsize);
14451452
ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
@@ -2448,25 +2455,7 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
24482455
loff_t start, end;
24492456
int error;
24502457

2451-
start = round_down(offset, blocksize);
2452-
end = round_up(offset + length, blocksize) - 1;
2453-
error = filemap_write_and_wait_range(inode->i_mapping, start, end);
2454-
if (error)
2455-
return error;
2456-
2457-
if (gfs2_is_jdata(ip))
2458-
error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
2459-
GFS2_JTRUNC_REVOKES);
2460-
else
2461-
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
2462-
if (error)
2463-
return error;
2464-
2465-
if (gfs2_is_stuffed(ip)) {
2466-
error = stuffed_zero_range(inode, offset, length);
2467-
if (error)
2468-
goto out;
2469-
} else {
2458+
if (!gfs2_is_stuffed(ip)) {
24702459
unsigned int start_off, end_len;
24712460

24722461
start_off = offset & (blocksize - 1);
@@ -2489,6 +2478,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
24892478
}
24902479
}
24912480

2481+
start = round_down(offset, blocksize);
2482+
end = round_up(offset + length, blocksize) - 1;
2483+
error = filemap_write_and_wait_range(inode->i_mapping, start, end);
2484+
if (error)
2485+
return error;
2486+
2487+
if (gfs2_is_jdata(ip))
2488+
error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
2489+
GFS2_JTRUNC_REVOKES);
2490+
else
2491+
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
2492+
if (error)
2493+
return error;
2494+
2495+
if (gfs2_is_stuffed(ip)) {
2496+
error = stuffed_zero_range(inode, offset, length);
2497+
if (error)
2498+
goto out;
2499+
}
2500+
24922501
if (gfs2_is_jdata(ip)) {
24932502
BUG_ON(!current->journal_info);
24942503
gfs2_journaled_truncate_range(inode, offset, length);

0 commit comments

Comments
 (0)