Commit 66cea28a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull btrfs fixes from Chris Mason:
 "Some fixes that Dave Sterba collected.

  We've been hitting an early enospc problem on production machines that
  Omar tracked down to an old int->u64 mistake. I waited a bit on this
  pull to make sure it was really the problem from production, but it's
  on ~2100 hosts now and I think we're good.

  Omar also noticed a commit in the queue would make new early ENOSPC
  problems. I pulled that out for now, which is why the top three
  commits are younger than the rest.

  Otherwise these are all fixes, some explaining very old bugs that
  we've been poking at for a while"

* 'for-linus-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: fix delalloc accounting leak caused by u32 overflow
  Btrfs: clear EXTENT_DEFRAG bits in finish_ordered_io
  btrfs: tree-log.c: Wrong printk information about namelen
  btrfs: fix race with relocation recovery and fs_root setup
  btrfs: fix memory leak in update_space_info failure path
  btrfs: use correct types for page indices in btrfs_page_exists_in_range
  btrfs: fix incorrect error return ret being passed to mapping_set_error
  btrfs: Make flush bios explicitely sync
  btrfs: fiemap: Cache and merge fiemap extent before submit it to user
parents ac1a14a2 70e7af24
...@@ -2563,7 +2563,7 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes); ...@@ -2563,7 +2563,7 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes);
static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info, static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info,
unsigned num_items) unsigned num_items)
{ {
return fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items; return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items;
} }
/* /*
...@@ -2573,7 +2573,7 @@ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info, ...@@ -2573,7 +2573,7 @@ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info,
static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info, static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info,
unsigned num_items) unsigned num_items)
{ {
return fs_info->nodesize * BTRFS_MAX_LEVEL * num_items; return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items;
} }
int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
......
...@@ -468,7 +468,7 @@ int verify_dir_item(struct btrfs_fs_info *fs_info, ...@@ -468,7 +468,7 @@ int verify_dir_item(struct btrfs_fs_info *fs_info,
if (btrfs_dir_name_len(leaf, dir_item) > namelen) { if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
btrfs_crit(fs_info, "invalid dir item name len: %u", btrfs_crit(fs_info, "invalid dir item name len: %u",
(unsigned)btrfs_dir_data_len(leaf, dir_item)); (unsigned)btrfs_dir_name_len(leaf, dir_item));
return 1; return 1;
} }
......
...@@ -3467,10 +3467,12 @@ static int write_dev_supers(struct btrfs_device *device, ...@@ -3467,10 +3467,12 @@ static int write_dev_supers(struct btrfs_device *device,
* we fua the first super. The others we allow * we fua the first super. The others we allow
* to go down lazy. * to go down lazy.
*/ */
if (i == 0) if (i == 0) {
ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_FUA, bh); ret = btrfsic_submit_bh(REQ_OP_WRITE,
else REQ_SYNC | REQ_FUA, bh);
} else {
ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_SYNC, bh); ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
}
if (ret) if (ret)
errors++; errors++;
} }
...@@ -3535,7 +3537,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait) ...@@ -3535,7 +3537,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
bio->bi_end_io = btrfs_end_empty_barrier; bio->bi_end_io = btrfs_end_empty_barrier;
bio->bi_bdev = device->bdev; bio->bi_bdev = device->bdev;
bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH;
init_completion(&device->flush_wait); init_completion(&device->flush_wait);
bio->bi_private = &device->flush_wait; bio->bi_private = &device->flush_wait;
device->flush_bio = bio; device->flush_bio = bio;
......
...@@ -3993,6 +3993,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, ...@@ -3993,6 +3993,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
info->space_info_kobj, "%s", info->space_info_kobj, "%s",
alloc_name(found->flags)); alloc_name(found->flags));
if (ret) { if (ret) {
percpu_counter_destroy(&found->total_bytes_pinned);
kfree(found); kfree(found);
return ret; return ret;
} }
...@@ -4844,7 +4845,7 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info, ...@@ -4844,7 +4845,7 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info,
spin_unlock(&delayed_rsv->lock); spin_unlock(&delayed_rsv->lock);
commit: commit:
trans = btrfs_join_transaction(fs_info->fs_root); trans = btrfs_join_transaction(fs_info->extent_root);
if (IS_ERR(trans)) if (IS_ERR(trans))
return -ENOSPC; return -ENOSPC;
...@@ -4862,7 +4863,7 @@ static int flush_space(struct btrfs_fs_info *fs_info, ...@@ -4862,7 +4863,7 @@ static int flush_space(struct btrfs_fs_info *fs_info,
struct btrfs_space_info *space_info, u64 num_bytes, struct btrfs_space_info *space_info, u64 num_bytes,
u64 orig_bytes, int state) u64 orig_bytes, int state)
{ {
struct btrfs_root *root = fs_info->fs_root; struct btrfs_root *root = fs_info->extent_root;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
int nr; int nr;
int ret = 0; int ret = 0;
...@@ -5062,7 +5063,7 @@ static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info, ...@@ -5062,7 +5063,7 @@ static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info,
int flush_state = FLUSH_DELAYED_ITEMS_NR; int flush_state = FLUSH_DELAYED_ITEMS_NR;
spin_lock(&space_info->lock); spin_lock(&space_info->lock);
to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->fs_root, to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->extent_root,
space_info); space_info);
if (!to_reclaim) { if (!to_reclaim) {
spin_unlock(&space_info->lock); spin_unlock(&space_info->lock);
......
...@@ -2458,7 +2458,7 @@ void end_extent_writepage(struct page *page, int err, u64 start, u64 end) ...@@ -2458,7 +2458,7 @@ void end_extent_writepage(struct page *page, int err, u64 start, u64 end)
if (!uptodate) { if (!uptodate) {
ClearPageUptodate(page); ClearPageUptodate(page);
SetPageError(page); SetPageError(page);
ret = ret < 0 ? ret : -EIO; ret = err < 0 ? err : -EIO;
mapping_set_error(page->mapping, ret); mapping_set_error(page->mapping, ret);
} }
} }
...@@ -4377,6 +4377,123 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode, ...@@ -4377,6 +4377,123 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
return NULL; return NULL;
} }
/*
* To cache previous fiemap extent
*
* Will be used for merging fiemap extent
*/
struct fiemap_cache {
u64 offset;
u64 phys;
u64 len;
u32 flags;
bool cached;
};
/*
* Helper to submit fiemap extent.
*
* Will try to merge current fiemap extent specified by @offset, @phys,
* @len and @flags with cached one.
* And only when we fails to merge, cached one will be submitted as
* fiemap extent.
*
* Return value is the same as fiemap_fill_next_extent().
*/
static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
struct fiemap_cache *cache,
u64 offset, u64 phys, u64 len, u32 flags)
{
int ret = 0;
if (!cache->cached)
goto assign;
/*
* Sanity check, extent_fiemap() should have ensured that new
* fiemap extent won't overlap with cahced one.
* Not recoverable.
*
* NOTE: Physical address can overlap, due to compression
*/
if (cache->offset + cache->len > offset) {
WARN_ON(1);
return -EINVAL;
}
/*
* Only merges fiemap extents if
* 1) Their logical addresses are continuous
*
* 2) Their physical addresses are continuous
* So truly compressed (physical size smaller than logical size)
* extents won't get merged with each other
*
* 3) Share same flags except FIEMAP_EXTENT_LAST
* So regular extent won't get merged with prealloc extent
*/
if (cache->offset + cache->len == offset &&
cache->phys + cache->len == phys &&
(cache->flags & ~FIEMAP_EXTENT_LAST) ==
(flags & ~FIEMAP_EXTENT_LAST)) {
cache->len += len;
cache->flags |= flags;
goto try_submit_last;
}
/* Not mergeable, need to submit cached one */
ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys,
cache->len, cache->flags);
cache->cached = false;
if (ret)
return ret;
assign:
cache->cached = true;
cache->offset = offset;
cache->phys = phys;
cache->len = len;
cache->flags = flags;
try_submit_last:
if (cache->flags & FIEMAP_EXTENT_LAST) {
ret = fiemap_fill_next_extent(fieinfo, cache->offset,
cache->phys, cache->len, cache->flags);
cache->cached = false;
}
return ret;
}
/*
* Sanity check for fiemap cache
*
* All fiemap cache should be submitted by emit_fiemap_extent()
* Iteration should be terminated either by last fiemap extent or
* fieinfo->fi_extents_max.
* So no cached fiemap should exist.
*/
static int check_fiemap_cache(struct btrfs_fs_info *fs_info,
struct fiemap_extent_info *fieinfo,
struct fiemap_cache *cache)
{
int ret;
if (!cache->cached)
return 0;
/* Small and recoverbale problem, only to info developer */
#ifdef CONFIG_BTRFS_DEBUG
WARN_ON(1);
#endif
btrfs_warn(fs_info,
"unhandled fiemap cache detected: offset=%llu phys=%llu len=%llu flags=0x%x",
cache->offset, cache->phys, cache->len, cache->flags);
ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys,
cache->len, cache->flags);
cache->cached = false;
if (ret > 0)
ret = 0;
return ret;
}
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent) __u64 start, __u64 len, get_extent_t *get_extent)
{ {
...@@ -4394,6 +4511,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -4394,6 +4511,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
struct extent_state *cached_state = NULL; struct extent_state *cached_state = NULL;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct fiemap_cache cache = { 0 };
int end = 0; int end = 0;
u64 em_start = 0; u64 em_start = 0;
u64 em_len = 0; u64 em_len = 0;
...@@ -4573,7 +4691,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -4573,7 +4691,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
flags |= FIEMAP_EXTENT_LAST; flags |= FIEMAP_EXTENT_LAST;
end = 1; end = 1;
} }
ret = fiemap_fill_next_extent(fieinfo, em_start, disko, ret = emit_fiemap_extent(fieinfo, &cache, em_start, disko,
em_len, flags); em_len, flags);
if (ret) { if (ret) {
if (ret == 1) if (ret == 1)
...@@ -4582,6 +4700,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -4582,6 +4700,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
} }
} }
out_free: out_free:
if (!ret)
ret = check_fiemap_cache(root->fs_info, fieinfo, &cache);
free_extent_map(em); free_extent_map(em);
out: out:
btrfs_free_path(path); btrfs_free_path(path);
......
...@@ -2952,7 +2952,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) ...@@ -2952,7 +2952,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
ret = test_range_bit(io_tree, ordered_extent->file_offset, ret = test_range_bit(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1, ordered_extent->file_offset + ordered_extent->len - 1,
EXTENT_DEFRAG, 1, cached_state); EXTENT_DEFRAG, 0, cached_state);
if (ret) { if (ret) {
u64 last_snapshot = btrfs_root_last_snapshot(&root->root_item); u64 last_snapshot = btrfs_root_last_snapshot(&root->root_item);
if (0 && last_snapshot >= BTRFS_I(inode)->generation) if (0 && last_snapshot >= BTRFS_I(inode)->generation)
...@@ -7483,8 +7483,8 @@ bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end) ...@@ -7483,8 +7483,8 @@ bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end)
int found = false; int found = false;
void **pagep = NULL; void **pagep = NULL;
struct page *page = NULL; struct page *page = NULL;
int start_idx; unsigned long start_idx;
int end_idx; unsigned long end_idx;
start_idx = start >> PAGE_SHIFT; start_idx = start >> PAGE_SHIFT;
......
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