提交 64887b68 编写于 作者: L Linus Torvalds

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

Pull btrfs fixes from Chris Mason:
 "A few more btrfs fixes.

  These range from corners Filipe found in the new free space cache
  writeback to a grab bag of fixes from the list"

* 'for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: btrfs_release_extent_buffer_page didn't free pages of dummy extent
  Btrfs: fill ->last_trans for delayed inode in btrfs_fill_inode.
  btrfs: unlock i_mutex after attempting to delete subvolume during send
  btrfs: check io_ctl_prepare_pages return in __btrfs_write_out_cache
  btrfs: fix race on ENOMEM in alloc_extent_buffer
  btrfs: handle ENOMEM in btrfs_alloc_tree_block
  Btrfs: fix find_free_dev_extent() malfunction in case device tree has hole
  Btrfs: don't check for delalloc_bytes in cache_save_setup
  Btrfs: fix deadlock when starting writeback of bg caches
  Btrfs: fix race between start dirty bg cache writeout and bg deletion
...@@ -1802,6 +1802,8 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev) ...@@ -1802,6 +1802,8 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
set_nlink(inode, btrfs_stack_inode_nlink(inode_item)); set_nlink(inode, btrfs_stack_inode_nlink(inode_item));
inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item)); inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item));
BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item); BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item);
BTRFS_I(inode)->last_trans = btrfs_stack_inode_transid(inode_item);
inode->i_version = btrfs_stack_inode_sequence(inode_item); inode->i_version = btrfs_stack_inode_sequence(inode_item);
inode->i_rdev = 0; inode->i_rdev = 0;
*rdev = btrfs_stack_inode_rdev(inode_item); *rdev = btrfs_stack_inode_rdev(inode_item);
......
...@@ -3178,8 +3178,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, ...@@ -3178,8 +3178,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
bi = btrfs_item_ptr_offset(leaf, path->slots[0]); bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item)); write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item));
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
fail: fail:
btrfs_release_path(path);
if (ret) if (ret)
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
return ret; return ret;
...@@ -3305,8 +3305,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, ...@@ -3305,8 +3305,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
spin_lock(&block_group->lock); spin_lock(&block_group->lock);
if (block_group->cached != BTRFS_CACHE_FINISHED || if (block_group->cached != BTRFS_CACHE_FINISHED ||
!btrfs_test_opt(root, SPACE_CACHE) || !btrfs_test_opt(root, SPACE_CACHE)) {
block_group->delalloc_bytes) {
/* /*
* don't bother trying to write stuff out _if_ * don't bother trying to write stuff out _if_
* a) we're not cached, * a) we're not cached,
...@@ -3408,17 +3407,14 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, ...@@ -3408,17 +3407,14 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
int loops = 0; int loops = 0;
spin_lock(&cur_trans->dirty_bgs_lock); spin_lock(&cur_trans->dirty_bgs_lock);
if (!list_empty(&cur_trans->dirty_bgs)) { if (list_empty(&cur_trans->dirty_bgs)) {
list_splice_init(&cur_trans->dirty_bgs, &dirty);
}
spin_unlock(&cur_trans->dirty_bgs_lock); spin_unlock(&cur_trans->dirty_bgs_lock);
again:
if (list_empty(&dirty)) {
btrfs_free_path(path);
return 0; return 0;
} }
list_splice_init(&cur_trans->dirty_bgs, &dirty);
spin_unlock(&cur_trans->dirty_bgs_lock);
again:
/* /*
* make sure all the block groups on our dirty list actually * make sure all the block groups on our dirty list actually
* exist * exist
...@@ -3431,18 +3427,16 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, ...@@ -3431,18 +3427,16 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
return -ENOMEM; return -ENOMEM;
} }
/*
* cache_write_mutex is here only to save us from balance or automatic
* removal of empty block groups deleting this block group while we are
* writing out the cache
*/
mutex_lock(&trans->transaction->cache_write_mutex);
while (!list_empty(&dirty)) { while (!list_empty(&dirty)) {
cache = list_first_entry(&dirty, cache = list_first_entry(&dirty,
struct btrfs_block_group_cache, struct btrfs_block_group_cache,
dirty_list); dirty_list);
/*
* cache_write_mutex is here only to save us from balance
* deleting this block group while we are writing out the
* cache
*/
mutex_lock(&trans->transaction->cache_write_mutex);
/* /*
* this can happen if something re-dirties a block * this can happen if something re-dirties a block
* group that is already under IO. Just wait for it to * group that is already under IO. Just wait for it to
...@@ -3495,7 +3489,6 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, ...@@ -3495,7 +3489,6 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
} }
if (!ret) if (!ret)
ret = write_one_cache_group(trans, root, path, cache); ret = write_one_cache_group(trans, root, path, cache);
mutex_unlock(&trans->transaction->cache_write_mutex);
/* if its not on the io list, we need to put the block group */ /* if its not on the io list, we need to put the block group */
if (should_put) if (should_put)
...@@ -3503,7 +3496,16 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, ...@@ -3503,7 +3496,16 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
if (ret) if (ret)
break; break;
/*
* Avoid blocking other tasks for too long. It might even save
* us from writing caches for block groups that are going to be
* removed.
*/
mutex_unlock(&trans->transaction->cache_write_mutex);
mutex_lock(&trans->transaction->cache_write_mutex);
} }
mutex_unlock(&trans->transaction->cache_write_mutex);
/* /*
* go through delayed refs for all the stuff we've just kicked off * go through delayed refs for all the stuff we've just kicked off
...@@ -3514,9 +3516,16 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, ...@@ -3514,9 +3516,16 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
loops++; loops++;
spin_lock(&cur_trans->dirty_bgs_lock); spin_lock(&cur_trans->dirty_bgs_lock);
list_splice_init(&cur_trans->dirty_bgs, &dirty); list_splice_init(&cur_trans->dirty_bgs, &dirty);
/*
* dirty_bgs_lock protects us from concurrent block group
* deletes too (not just cache_write_mutex).
*/
if (!list_empty(&dirty)) {
spin_unlock(&cur_trans->dirty_bgs_lock); spin_unlock(&cur_trans->dirty_bgs_lock);
goto again; goto again;
} }
spin_unlock(&cur_trans->dirty_bgs_lock);
}
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
...@@ -7537,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info, ...@@ -7537,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
* returns the key for the extent through ins, and a tree buffer for * returns the key for the extent through ins, and a tree buffer for
* the first block of the extent through buf. * the first block of the extent through buf.
* *
* returns the tree buffer or NULL. * returns the tree buffer or an ERR_PTR on error.
*/ */
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
...@@ -7548,6 +7557,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, ...@@ -7548,6 +7557,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_key ins; struct btrfs_key ins;
struct btrfs_block_rsv *block_rsv; struct btrfs_block_rsv *block_rsv;
struct extent_buffer *buf; struct extent_buffer *buf;
struct btrfs_delayed_extent_op *extent_op;
u64 flags = 0; u64 flags = 0;
int ret; int ret;
u32 blocksize = root->nodesize; u32 blocksize = root->nodesize;
...@@ -7568,13 +7578,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, ...@@ -7568,13 +7578,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
ret = btrfs_reserve_extent(root, blocksize, blocksize, ret = btrfs_reserve_extent(root, blocksize, blocksize,
empty_size, hint, &ins, 0, 0); empty_size, hint, &ins, 0, 0);
if (ret) { if (ret)
unuse_block_rsv(root->fs_info, block_rsv, blocksize); goto out_unuse;
return ERR_PTR(ret);
}
buf = btrfs_init_new_buffer(trans, root, ins.objectid, level); buf = btrfs_init_new_buffer(trans, root, ins.objectid, level);
BUG_ON(IS_ERR(buf)); /* -ENOMEM */ if (IS_ERR(buf)) {
ret = PTR_ERR(buf);
goto out_free_reserved;
}
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
if (parent == 0) if (parent == 0)
...@@ -7584,9 +7595,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, ...@@ -7584,9 +7595,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
BUG_ON(parent > 0); BUG_ON(parent > 0);
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) { if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
struct btrfs_delayed_extent_op *extent_op;
extent_op = btrfs_alloc_delayed_extent_op(); extent_op = btrfs_alloc_delayed_extent_op();
BUG_ON(!extent_op); /* -ENOMEM */ if (!extent_op) {
ret = -ENOMEM;
goto out_free_buf;
}
if (key) if (key)
memcpy(&extent_op->key, key, sizeof(extent_op->key)); memcpy(&extent_op->key, key, sizeof(extent_op->key));
else else
...@@ -7601,13 +7614,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, ...@@ -7601,13 +7614,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
extent_op->level = level; extent_op->level = level;
ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
ins.objectid, ins.objectid, ins.offset,
ins.offset, parent, root_objectid, parent, root_objectid, level,
level, BTRFS_ADD_DELAYED_EXTENT, BTRFS_ADD_DELAYED_EXTENT,
extent_op, 0); extent_op, 0);
BUG_ON(ret); /* -ENOMEM */ if (ret)
goto out_free_delayed;
} }
return buf; return buf;
out_free_delayed:
btrfs_free_delayed_extent_op(extent_op);
out_free_buf:
free_extent_buffer(buf);
out_free_reserved:
btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0);
out_unuse:
unuse_block_rsv(root->fs_info, block_rsv, blocksize);
return ERR_PTR(ret);
} }
struct walk_control { struct walk_control {
......
...@@ -4560,7 +4560,9 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) ...@@ -4560,7 +4560,9 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb)
do { do {
index--; index--;
page = eb->pages[index]; page = eb->pages[index];
if (page && mapped) { if (!page)
continue;
if (mapped)
spin_lock(&page->mapping->private_lock); spin_lock(&page->mapping->private_lock);
/* /*
* We do this since we'll remove the pages after we've * We do this since we'll remove the pages after we've
...@@ -4583,13 +4585,12 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) ...@@ -4583,13 +4585,12 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb)
/* One for the page private */ /* One for the page private */
page_cache_release(page); page_cache_release(page);
} }
if (mapped)
spin_unlock(&page->mapping->private_lock); spin_unlock(&page->mapping->private_lock);
}
if (page) {
/* One for when we alloced the page */ /* One for when we alloced the page */
page_cache_release(page); page_cache_release(page);
}
} while (index != 0); } while (index != 0);
} }
...@@ -4870,6 +4871,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, ...@@ -4870,6 +4871,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
mark_extent_buffer_accessed(exists, p); mark_extent_buffer_accessed(exists, p);
goto free_eb; goto free_eb;
} }
exists = NULL;
/* /*
* Do this so attach doesn't complain and we need to * Do this so attach doesn't complain and we need to
...@@ -4933,12 +4935,12 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, ...@@ -4933,12 +4935,12 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
return eb; return eb;
free_eb: free_eb:
WARN_ON(!atomic_dec_and_test(&eb->refs));
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
if (eb->pages[i]) if (eb->pages[i])
unlock_page(eb->pages[i]); unlock_page(eb->pages[i]);
} }
WARN_ON(!atomic_dec_and_test(&eb->refs));
btrfs_release_extent_buffer(eb); btrfs_release_extent_buffer(eb);
return exists; return exists;
} }
......
...@@ -1218,7 +1218,7 @@ int btrfs_wait_cache_io(struct btrfs_root *root, ...@@ -1218,7 +1218,7 @@ int btrfs_wait_cache_io(struct btrfs_root *root,
* *
* This function writes out a free space cache struct to disk for quick recovery * This function writes out a free space cache struct to disk for quick recovery
* on mount. This will return 0 if it was successfull in writing the cache out, * on mount. This will return 0 if it was successfull in writing the cache out,
* and -1 if it was not. * or an errno if it was not.
*/ */
static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
struct btrfs_free_space_ctl *ctl, struct btrfs_free_space_ctl *ctl,
...@@ -1235,12 +1235,12 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, ...@@ -1235,12 +1235,12 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
int must_iput = 0; int must_iput = 0;
if (!i_size_read(inode)) if (!i_size_read(inode))
return -1; return -EIO;
WARN_ON(io_ctl->pages); WARN_ON(io_ctl->pages);
ret = io_ctl_init(io_ctl, inode, root, 1); ret = io_ctl_init(io_ctl, inode, root, 1);
if (ret) if (ret)
return -1; return ret;
if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) { if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) {
down_write(&block_group->data_rwsem); down_write(&block_group->data_rwsem);
...@@ -1258,7 +1258,9 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, ...@@ -1258,7 +1258,9 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
} }
/* Lock all pages first so we can lock the extent safely. */ /* Lock all pages first so we can lock the extent safely. */
io_ctl_prepare_pages(io_ctl, inode, 0); ret = io_ctl_prepare_pages(io_ctl, inode, 0);
if (ret)
goto out;
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
0, &cached_state); 0, &cached_state);
......
...@@ -3632,25 +3632,28 @@ static void btrfs_read_locked_inode(struct inode *inode) ...@@ -3632,25 +3632,28 @@ static void btrfs_read_locked_inode(struct inode *inode)
BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item); BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item); BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item);
inode->i_version = btrfs_inode_sequence(leaf, inode_item);
inode->i_generation = BTRFS_I(inode)->generation;
inode->i_rdev = 0;
rdev = btrfs_inode_rdev(leaf, inode_item);
BTRFS_I(inode)->index_cnt = (u64)-1;
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
cache_index:
/* /*
* If we were modified in the current generation and evicted from memory * If we were modified in the current generation and evicted from memory
* and then re-read we need to do a full sync since we don't have any * and then re-read we need to do a full sync since we don't have any
* idea about which extents were modified before we were evicted from * idea about which extents were modified before we were evicted from
* cache. * cache.
*
* This is required for both inode re-read from disk and delayed inode
* in delayed_nodes_tree.
*/ */
if (BTRFS_I(inode)->last_trans == root->fs_info->generation) if (BTRFS_I(inode)->last_trans == root->fs_info->generation)
set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
&BTRFS_I(inode)->runtime_flags); &BTRFS_I(inode)->runtime_flags);
inode->i_version = btrfs_inode_sequence(leaf, inode_item);
inode->i_generation = BTRFS_I(inode)->generation;
inode->i_rdev = 0;
rdev = btrfs_inode_rdev(leaf, inode_item);
BTRFS_I(inode)->index_cnt = (u64)-1;
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
cache_index:
path->slots[0]++; path->slots[0]++;
if (inode->i_nlink != 1 || if (inode->i_nlink != 1 ||
path->slots[0] >= btrfs_header_nritems(leaf)) path->slots[0] >= btrfs_header_nritems(leaf))
......
...@@ -2410,7 +2410,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2410,7 +2410,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
"Attempt to delete subvolume %llu during send", "Attempt to delete subvolume %llu during send",
dest->root_key.objectid); dest->root_key.objectid);
err = -EPERM; err = -EPERM;
goto out_dput; goto out_unlock_inode;
} }
d_invalidate(dentry); d_invalidate(dentry);
...@@ -2505,6 +2505,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2505,6 +2505,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
root_flags & ~BTRFS_ROOT_SUBVOL_DEAD); root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
spin_unlock(&dest->root_item_lock); spin_unlock(&dest->root_item_lock);
} }
out_unlock_inode:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (!err) { if (!err) {
shrink_dcache_sb(root->fs_info->sb); shrink_dcache_sb(root->fs_info->sb);
......
...@@ -1058,6 +1058,7 @@ static int contains_pending_extent(struct btrfs_trans_handle *trans, ...@@ -1058,6 +1058,7 @@ static int contains_pending_extent(struct btrfs_trans_handle *trans,
struct extent_map *em; struct extent_map *em;
struct list_head *search_list = &trans->transaction->pending_chunks; struct list_head *search_list = &trans->transaction->pending_chunks;
int ret = 0; int ret = 0;
u64 physical_start = *start;
again: again:
list_for_each_entry(em, search_list, list) { list_for_each_entry(em, search_list, list) {
...@@ -1068,9 +1069,9 @@ static int contains_pending_extent(struct btrfs_trans_handle *trans, ...@@ -1068,9 +1069,9 @@ static int contains_pending_extent(struct btrfs_trans_handle *trans,
for (i = 0; i < map->num_stripes; i++) { for (i = 0; i < map->num_stripes; i++) {
if (map->stripes[i].dev != device) if (map->stripes[i].dev != device)
continue; continue;
if (map->stripes[i].physical >= *start + len || if (map->stripes[i].physical >= physical_start + len ||
map->stripes[i].physical + em->orig_block_len <= map->stripes[i].physical + em->orig_block_len <=
*start) physical_start)
continue; continue;
*start = map->stripes[i].physical + *start = map->stripes[i].physical +
em->orig_block_len; em->orig_block_len;
...@@ -1193,8 +1194,14 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, ...@@ -1193,8 +1194,14 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
*/ */
if (contains_pending_extent(trans, device, if (contains_pending_extent(trans, device,
&search_start, &search_start,
hole_size)) hole_size)) {
if (key.offset >= search_start) {
hole_size = key.offset - search_start;
} else {
WARN_ON_ONCE(1);
hole_size = 0; hole_size = 0;
}
}
if (hole_size > max_hole_size) { if (hole_size > max_hole_size) {
max_hole_start = search_start; max_hole_start = search_start;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册