mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-28 03:46:12 +00:00
scoutfs: limit get_block bh use
We were seeing __block_write_begin spin when staging writes were called after a read of an offline region saw an error. It turns out that the way __block_write_begin iterates through buffer heads on a page will livelock if b_size is 0. Our get_block was clearing b_blocknr and b_size before doing anything. It'd set them when it allocated blocks or found existing mapped blocks. But it'd leave them 0 on an error and trigger this hang. So we'll back off and only do the same things to the result bh that ext2/3 do, presumably that's what's actually supported. We only set mapped, set or clear new, and set b_size to less than the input b_size. While we're at it we remove a totally bogus extent flag check that's done before seeing if the next extent we found even intersects with the logical block that we're searching for. The extra test is performed again correctly inside the check for the extents overlapping. It is an artifact from the days when the "extents" were a single block and didn't need to check for overlaps. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+2
-9
@@ -995,9 +995,6 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
u64 off;
|
||||
int ret;
|
||||
|
||||
bh->b_blocknr = 0;
|
||||
bh->b_size = 0;
|
||||
|
||||
ext.blk_off = iblock;
|
||||
ext.blocks = 1;
|
||||
ext.blkno = 0;
|
||||
@@ -1026,11 +1023,6 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
trace_printk("found nei "EXTF"\n", EXTA(&ext));
|
||||
}
|
||||
|
||||
if ((ext.flags & SCOUTFS_FILE_EXTENT_OFFLINE) && !si->staging) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* use the extent if it intersects */
|
||||
if (iblock >= ext.blk_off && iblock < (ext.blk_off + ext.blocks)) {
|
||||
|
||||
@@ -1045,8 +1037,9 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
/* found online extent */
|
||||
off = iblock - ext.blk_off;
|
||||
map_bh(bh, inode->i_sb, ext.blkno + off);
|
||||
bh->b_size = min_t(u64, SIZE_MAX,
|
||||
bh->b_size = min_t(u64, bh->b_size,
|
||||
(ext.blocks - off) << SCOUTFS_BLOCK_SHIFT);
|
||||
clear_buffer_new(bh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user