mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-18 12:45:08 +00:00
gfs2: Fixes to "Implement iomap for block_map"
It turns out that commit 3974320ca6
"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: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
parent
35277995e1
commit
49edd5bf42
1 changed files with 23 additions and 20 deletions
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue