Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mason/linux-btrfs

Pull second set of btrfs updates from Chris Mason:
 "The most important changes here are from Josef, fixing a btrfs
  regression in 3.14 that can cause corruptions in the extent allocation
  tree when snapshots are in use.

  Josef also fixed some deadlocks in send/recv and other assorted races
  when balance is running"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (23 commits)
  Btrfs: fix compile warnings on on avr32 platform
  btrfs: allow mounting btrfs subvolumes with different ro/rw options
  btrfs: export global block reserve size as space_info
  btrfs: fix crash in remount(thread_pool=) case
  Btrfs: abort the transaction when we don't find our extent ref
  Btrfs: fix EINVAL checks in btrfs_clone
  Btrfs: fix unlock in __start_delalloc_inodes()
  Btrfs: scrub raid56 stripes in the right way
  Btrfs: don't compress for a small write
  Btrfs: more efficient io tree navigation on wait_extent_bit
  Btrfs: send, build path string only once in send_hole
  btrfs: filter invalid arg for btrfs resize
  Btrfs: send, fix data corruption due to incorrect hole detection
  Btrfs: kmalloc() doesn't return an ERR_PTR
  Btrfs: fix snapshot vs nocow writting
  btrfs: Change the expanding write sequence to fix snapshot related bug.
  btrfs: make device scan less noisy
  btrfs: fix lockdep warning with reclaim lock inversion
  Btrfs: hold the commit_root_sem when getting the commit root during send
  Btrfs: remove transaction from send
  ...
  • Loading branch information
Linus Torvalds committed Apr 11, 2014
2 parents 582076a + e4fbaee commit 3123bca
Show file tree
Hide file tree
Showing 19 changed files with 374 additions and 279 deletions.
2 changes: 2 additions & 0 deletions fs/btrfs/async-thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ void btrfs_destroy_workqueue(struct btrfs_workqueue *wq)

void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max)
{
if (!wq)
return;
wq->normal->max_active = max;
if (wq->high)
wq->high->max_active = max;
Expand Down
33 changes: 27 additions & 6 deletions fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,10 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
goto out;
}

root_level = btrfs_old_root_level(root, time_seq);
if (path->search_commit_root)
root_level = btrfs_header_level(root->commit_root);
else
root_level = btrfs_old_root_level(root, time_seq);

if (root_level + 1 == level) {
srcu_read_unlock(&fs_info->subvol_srcu, index);
Expand Down Expand Up @@ -1099,9 +1102,9 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
*
* returns 0 on success, < 0 on error.
*/
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist **roots)
static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist **roots)
{
struct ulist *tmp;
struct ulist_node *node = NULL;
Expand Down Expand Up @@ -1137,6 +1140,20 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
return 0;
}

int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist **roots)
{
int ret;

if (!trans)
down_read(&fs_info->commit_root_sem);
ret = __btrfs_find_all_roots(trans, fs_info, bytenr, time_seq, roots);
if (!trans)
up_read(&fs_info->commit_root_sem);
return ret;
}

/*
* this makes the path point to (inum INODE_ITEM ioff)
*/
Expand Down Expand Up @@ -1516,6 +1533,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
if (IS_ERR(trans))
return PTR_ERR(trans);
btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
} else {
down_read(&fs_info->commit_root_sem);
}

ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
Expand All @@ -1526,8 +1545,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,

ULIST_ITER_INIT(&ref_uiter);
while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
ret = btrfs_find_all_roots(trans, fs_info, ref_node->val,
tree_mod_seq_elem.seq, &roots);
ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val,
tree_mod_seq_elem.seq, &roots);
if (ret)
break;
ULIST_ITER_INIT(&root_uiter);
Expand All @@ -1549,6 +1568,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
if (!search_commit_root) {
btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
btrfs_end_transaction(trans, fs_info->extent_root);
} else {
up_read(&fs_info->commit_root_sem);
}

return ret;
Expand Down
94 changes: 6 additions & 88 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2769,9 +2769,13 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
* the commit roots are read only
* so we always do read locks
*/
if (p->need_commit_sem)
down_read(&root->fs_info->commit_root_sem);
b = root->commit_root;
extent_buffer_get(b);
level = btrfs_header_level(b);
if (p->need_commit_sem)
up_read(&root->fs_info->commit_root_sem);
if (!p->skip_locking)
btrfs_tree_read_lock(b);
} else {
Expand Down Expand Up @@ -5360,7 +5364,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
{
int ret;
int cmp;
struct btrfs_trans_handle *trans = NULL;
struct btrfs_path *left_path = NULL;
struct btrfs_path *right_path = NULL;
struct btrfs_key left_key;
Expand All @@ -5378,9 +5381,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
u64 right_blockptr;
u64 left_gen;
u64 right_gen;
u64 left_start_ctransid;
u64 right_start_ctransid;
u64 ctransid;

left_path = btrfs_alloc_path();
if (!left_path) {
Expand All @@ -5404,21 +5404,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
right_path->search_commit_root = 1;
right_path->skip_locking = 1;

spin_lock(&left_root->root_item_lock);
left_start_ctransid = btrfs_root_ctransid(&left_root->root_item);
spin_unlock(&left_root->root_item_lock);

spin_lock(&right_root->root_item_lock);
right_start_ctransid = btrfs_root_ctransid(&right_root->root_item);
spin_unlock(&right_root->root_item_lock);

trans = btrfs_join_transaction(left_root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
trans = NULL;
goto out;
}

/*
* Strategy: Go to the first items of both trees. Then do
*
Expand Down Expand Up @@ -5455,6 +5440,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
* the right if possible or go up and right.
*/

down_read(&left_root->fs_info->commit_root_sem);
left_level = btrfs_header_level(left_root->commit_root);
left_root_level = left_level;
left_path->nodes[left_level] = left_root->commit_root;
Expand All @@ -5464,6 +5450,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
right_root_level = right_level;
right_path->nodes[right_level] = right_root->commit_root;
extent_buffer_get(right_path->nodes[right_level]);
up_read(&left_root->fs_info->commit_root_sem);

if (left_level == 0)
btrfs_item_key_to_cpu(left_path->nodes[left_level],
Expand All @@ -5482,67 +5469,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
advance_left = advance_right = 0;

while (1) {
/*
* We need to make sure the transaction does not get committed
* while we do anything on commit roots. This means, we need to
* join and leave transactions for every item that we process.
*/
if (trans && btrfs_should_end_transaction(trans, left_root)) {
btrfs_release_path(left_path);
btrfs_release_path(right_path);

ret = btrfs_end_transaction(trans, left_root);
trans = NULL;
if (ret < 0)
goto out;
}
/* now rejoin the transaction */
if (!trans) {
trans = btrfs_join_transaction(left_root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
trans = NULL;
goto out;
}

spin_lock(&left_root->root_item_lock);
ctransid = btrfs_root_ctransid(&left_root->root_item);
spin_unlock(&left_root->root_item_lock);
if (ctransid != left_start_ctransid)
left_start_ctransid = 0;

spin_lock(&right_root->root_item_lock);
ctransid = btrfs_root_ctransid(&right_root->root_item);
spin_unlock(&right_root->root_item_lock);
if (ctransid != right_start_ctransid)
right_start_ctransid = 0;

if (!left_start_ctransid || !right_start_ctransid) {
WARN(1, KERN_WARNING
"BTRFS: btrfs_compare_tree detected "
"a change in one of the trees while "
"iterating. This is probably a "
"bug.\n");
ret = -EIO;
goto out;
}

/*
* the commit root may have changed, so start again
* where we stopped
*/
left_path->lowest_level = left_level;
right_path->lowest_level = right_level;
ret = btrfs_search_slot(NULL, left_root,
&left_key, left_path, 0, 0);
if (ret < 0)
goto out;
ret = btrfs_search_slot(NULL, right_root,
&right_key, right_path, 0, 0);
if (ret < 0)
goto out;
}

if (advance_left && !left_end_reached) {
ret = tree_advance(left_root, left_path, &left_level,
left_root_level,
Expand Down Expand Up @@ -5672,14 +5598,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
btrfs_free_path(left_path);
btrfs_free_path(right_path);
kfree(tmp_buf);

if (trans) {
if (!ret)
ret = btrfs_end_transaction(trans, left_root);
else
btrfs_end_transaction(trans, left_root);
}

return ret;
}

Expand Down
13 changes: 10 additions & 3 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ struct btrfs_path {
unsigned int skip_locking:1;
unsigned int leave_spinning:1;
unsigned int search_commit_root:1;
unsigned int need_commit_sem:1;
};

/*
Expand Down Expand Up @@ -986,7 +987,8 @@ struct btrfs_dev_replace_item {
#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6)
#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7)
#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8)
#define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE
#define BTRFS_BLOCK_GROUP_RESERVED (BTRFS_AVAIL_ALLOC_BIT_SINGLE | \
BTRFS_SPACE_INFO_GLOBAL_RSV)

enum btrfs_raid_types {
BTRFS_RAID_RAID10,
Expand Down Expand Up @@ -1018,6 +1020,12 @@ enum btrfs_raid_types {
*/
#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48)

/*
* A fake block group type that is used to communicate global block reserve
* size to userspace via the SPACE_INFO ioctl.
*/
#define BTRFS_SPACE_INFO_GLOBAL_RSV (1ULL << 49)

#define BTRFS_EXTENDED_PROFILE_MASK (BTRFS_BLOCK_GROUP_PROFILE_MASK | \
BTRFS_AVAIL_ALLOC_BIT_SINGLE)

Expand Down Expand Up @@ -1440,7 +1448,7 @@ struct btrfs_fs_info {
*/
struct mutex ordered_extent_flush_mutex;

struct rw_semaphore extent_commit_sem;
struct rw_semaphore commit_root_sem;

struct rw_semaphore cleanup_work_sem;

Expand Down Expand Up @@ -1711,7 +1719,6 @@ struct btrfs_root {
struct btrfs_block_rsv *block_rsv;

/* free ino cache stuff */
struct mutex fs_commit_mutex;
struct btrfs_free_space_ctl *free_ino_ctl;
enum btrfs_caching_type cached;
spinlock_t cache_lock;
Expand Down
23 changes: 20 additions & 3 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,20 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
{
struct extent_state *cached_state = NULL;
int ret;
bool need_lock = (current->journal_info ==
(void *)BTRFS_SEND_TRANS_STUB);

if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
return 0;

if (atomic)
return -EAGAIN;

if (need_lock) {
btrfs_tree_read_lock(eb);
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
}

lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
0, &cached_state);
if (extent_buffer_uptodate(eb) &&
Expand All @@ -347,10 +354,21 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
"found %llu\n",
eb->start, parent_transid, btrfs_header_generation(eb));
ret = 1;
clear_extent_buffer_uptodate(eb);

/*
* Things reading via commit roots that don't have normal protection,
* like send, can have a really old block in cache that may point at a
* block that has been free'd and re-allocated. So don't clear uptodate
* if we find an eb that is under IO (dirty/writeback) because we could
* end up reading in the stale data and then writing it back out and
* making everybody very sad.
*/
if (!extent_buffer_under_io(eb))
clear_extent_buffer_uptodate(eb);
out:
unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
&cached_state, GFP_NOFS);
btrfs_tree_read_unlock_blocking(eb);
return ret;
}

Expand Down Expand Up @@ -1546,7 +1564,6 @@ int btrfs_init_fs_root(struct btrfs_root *root)
root->subv_writers = writers;

btrfs_init_free_ino_ctl(root);
mutex_init(&root->fs_commit_mutex);
spin_lock_init(&root->cache_lock);
init_waitqueue_head(&root->cache_wait);

Expand Down Expand Up @@ -2324,7 +2341,7 @@ int open_ctree(struct super_block *sb,
mutex_init(&fs_info->transaction_kthread_mutex);
mutex_init(&fs_info->cleaner_mutex);
mutex_init(&fs_info->volume_mutex);
init_rwsem(&fs_info->extent_commit_sem);
init_rwsem(&fs_info->commit_root_sem);
init_rwsem(&fs_info->cleanup_work_sem);
init_rwsem(&fs_info->subvol_sem);
sema_init(&fs_info->uuid_tree_rescan_sem, 1);
Expand Down
Loading

0 comments on commit 3123bca

Please sign in to comment.