Commit 49edd5bf authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Bob Peterson

gfs2: Fixes to "Implement iomap for block_map"

It turns out that commit 3974320c "Implement iomap for block_map"
introduced a few bugs that trigger occasional failures with xfstest
generic/476:

In gfs2_iomap_begin, we jump to do_alloc when we determine that we are
beyond the end of the allocated metadata (height > ip->i_height).
There, we can end up calling hole_size with a metapath that doesn't
match the current metadata tree, which doesn't make sense.  After
untangling the code at do_alloc, fix this by checking if the block we
are looking for is within the range of allocated metadata.

In addition, add a BUG() in case gfs2_iomap_begin is accidentally called
for reading stuffed files: this is handled separately.  Make sure we
don't truncate iomap->length for reads beyond the end of the file; in
that case, the entire range counts as a hole.

Finally, revert to taking a bitmap write lock when doing allocations.
It's unclear why that change didn't lead to any failures during testing.
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
parent 35277995
...@@ -716,7 +716,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, ...@@ -716,7 +716,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
__be64 *ptr; __be64 *ptr;
sector_t lblock; sector_t lblock;
sector_t lend; sector_t lend;
int ret; int ret = 0;
int eob; int eob;
unsigned int len; unsigned int len;
struct buffer_head *bh; struct buffer_head *bh;
...@@ -728,12 +728,14 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, ...@@ -728,12 +728,14 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
goto out; goto out;
} }
if ((flags & IOMAP_REPORT) && gfs2_is_stuffed(ip)) { if (gfs2_is_stuffed(ip)) {
gfs2_stuffed_iomap(inode, iomap); if (flags & IOMAP_REPORT) {
if (pos >= iomap->length) gfs2_stuffed_iomap(inode, iomap);
return -ENOENT; if (pos >= iomap->length)
ret = 0; ret = -ENOENT;
goto out; goto out;
}
BUG_ON(!(flags & IOMAP_WRITE));
} }
lblock = pos >> inode->i_blkbits; lblock = pos >> inode->i_blkbits;
...@@ -744,7 +746,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, ...@@ -744,7 +746,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
iomap->type = IOMAP_HOLE; iomap->type = IOMAP_HOLE;
iomap->length = (u64)(lend - lblock) << inode->i_blkbits; iomap->length = (u64)(lend - lblock) << inode->i_blkbits;
iomap->flags = IOMAP_F_MERGED; iomap->flags = IOMAP_F_MERGED;
bmap_lock(ip, 0); bmap_lock(ip, flags & IOMAP_WRITE);
/* /*
* Directory data blocks have a struct gfs2_meta_header header, so the * Directory data blocks have a struct gfs2_meta_header header, so the
...@@ -787,27 +789,28 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, ...@@ -787,27 +789,28 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
iomap->flags |= IOMAP_F_BOUNDARY; iomap->flags |= IOMAP_F_BOUNDARY;
iomap->length = (u64)len << inode->i_blkbits; iomap->length = (u64)len << inode->i_blkbits;
ret = 0;
out_release: out_release:
release_metapath(&mp); release_metapath(&mp);
bmap_unlock(ip, 0); bmap_unlock(ip, flags & IOMAP_WRITE);
out: out:
trace_gfs2_iomap_end(ip, iomap, ret); trace_gfs2_iomap_end(ip, iomap, ret);
return ret; return ret;
do_alloc: do_alloc:
if (!(flags & IOMAP_WRITE)) { if (flags & IOMAP_WRITE) {
if (pos >= i_size_read(inode)) { ret = gfs2_iomap_alloc(inode, iomap, flags, &mp);
} else if (flags & IOMAP_REPORT) {
loff_t size = i_size_read(inode);
if (pos >= size)
ret = -ENOENT; ret = -ENOENT;
goto out_release; else if (height <= ip->i_height)
} iomap->length = hole_size(inode, lblock, &mp);
ret = 0; else
iomap->length = hole_size(inode, lblock, &mp); iomap->length = size - pos;
goto out_release; } else {
if (height <= ip->i_height)
iomap->length = hole_size(inode, lblock, &mp);
} }
ret = gfs2_iomap_alloc(inode, iomap, flags, &mp);
goto out_release; goto out_release;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment