Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: Btrfs: fix fiemap bugs with delalloc Btrfs: set FMODE_EXCL in btrfs_device->mode Btrfs: make btrfs_rm_device() fail gracefully Btrfs: Avoid accessing unmapped kernel address Btrfs: Fix BTRFS_IOC_SUBVOL_SETFLAGS ioctl Btrfs: allow balance to explicitly allocate chunks as it relocates Btrfs: put ENOSPC debugging under a mount option
This commit is contained in:
126
fs/btrfs/inode.c
126
fs/btrfs/inode.c
@ -1913,7 +1913,7 @@ static int btrfs_clean_io_failures(struct inode *inode, u64 start)
|
||||
|
||||
private = 0;
|
||||
if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
|
||||
(u64)-1, 1, EXTENT_DIRTY)) {
|
||||
(u64)-1, 1, EXTENT_DIRTY, 0)) {
|
||||
ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
|
||||
start, &private_failure);
|
||||
if (ret == 0) {
|
||||
@ -5280,6 +5280,128 @@ out:
|
||||
return em;
|
||||
}
|
||||
|
||||
struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
|
||||
size_t pg_offset, u64 start, u64 len,
|
||||
int create)
|
||||
{
|
||||
struct extent_map *em;
|
||||
struct extent_map *hole_em = NULL;
|
||||
u64 range_start = start;
|
||||
u64 end;
|
||||
u64 found;
|
||||
u64 found_end;
|
||||
int err = 0;
|
||||
|
||||
em = btrfs_get_extent(inode, page, pg_offset, start, len, create);
|
||||
if (IS_ERR(em))
|
||||
return em;
|
||||
if (em) {
|
||||
/*
|
||||
* if our em maps to a hole, there might
|
||||
* actually be delalloc bytes behind it
|
||||
*/
|
||||
if (em->block_start != EXTENT_MAP_HOLE)
|
||||
return em;
|
||||
else
|
||||
hole_em = em;
|
||||
}
|
||||
|
||||
/* check to see if we've wrapped (len == -1 or similar) */
|
||||
end = start + len;
|
||||
if (end < start)
|
||||
end = (u64)-1;
|
||||
else
|
||||
end -= 1;
|
||||
|
||||
em = NULL;
|
||||
|
||||
/* ok, we didn't find anything, lets look for delalloc */
|
||||
found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start,
|
||||
end, len, EXTENT_DELALLOC, 1);
|
||||
found_end = range_start + found;
|
||||
if (found_end < range_start)
|
||||
found_end = (u64)-1;
|
||||
|
||||
/*
|
||||
* we didn't find anything useful, return
|
||||
* the original results from get_extent()
|
||||
*/
|
||||
if (range_start > end || found_end <= start) {
|
||||
em = hole_em;
|
||||
hole_em = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* adjust the range_start to make sure it doesn't
|
||||
* go backwards from the start they passed in
|
||||
*/
|
||||
range_start = max(start,range_start);
|
||||
found = found_end - range_start;
|
||||
|
||||
if (found > 0) {
|
||||
u64 hole_start = start;
|
||||
u64 hole_len = len;
|
||||
|
||||
em = alloc_extent_map(GFP_NOFS);
|
||||
if (!em) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* when btrfs_get_extent can't find anything it
|
||||
* returns one huge hole
|
||||
*
|
||||
* make sure what it found really fits our range, and
|
||||
* adjust to make sure it is based on the start from
|
||||
* the caller
|
||||
*/
|
||||
if (hole_em) {
|
||||
u64 calc_end = extent_map_end(hole_em);
|
||||
|
||||
if (calc_end <= start || (hole_em->start > end)) {
|
||||
free_extent_map(hole_em);
|
||||
hole_em = NULL;
|
||||
} else {
|
||||
hole_start = max(hole_em->start, start);
|
||||
hole_len = calc_end - hole_start;
|
||||
}
|
||||
}
|
||||
em->bdev = NULL;
|
||||
if (hole_em && range_start > hole_start) {
|
||||
/* our hole starts before our delalloc, so we
|
||||
* have to return just the parts of the hole
|
||||
* that go until the delalloc starts
|
||||
*/
|
||||
em->len = min(hole_len,
|
||||
range_start - hole_start);
|
||||
em->start = hole_start;
|
||||
em->orig_start = hole_start;
|
||||
/*
|
||||
* don't adjust block start at all,
|
||||
* it is fixed at EXTENT_MAP_HOLE
|
||||
*/
|
||||
em->block_start = hole_em->block_start;
|
||||
em->block_len = hole_len;
|
||||
} else {
|
||||
em->start = range_start;
|
||||
em->len = found;
|
||||
em->orig_start = range_start;
|
||||
em->block_start = EXTENT_MAP_DELALLOC;
|
||||
em->block_len = found;
|
||||
}
|
||||
} else if (hole_em) {
|
||||
return hole_em;
|
||||
}
|
||||
out:
|
||||
|
||||
free_extent_map(hole_em);
|
||||
if (err) {
|
||||
free_extent_map(em);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
return em;
|
||||
}
|
||||
|
||||
static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
|
||||
u64 start, u64 len)
|
||||
{
|
||||
@ -6102,7 +6224,7 @@ out:
|
||||
static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len)
|
||||
{
|
||||
return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent);
|
||||
return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
|
||||
}
|
||||
|
||||
int btrfs_readpage(struct file *file, struct page *page)
|
||||
|
Reference in New Issue
Block a user