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/btrfs-unstable

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: avoid delayed metadata items during commits
  btrfs: fix uninitialized return value
  btrfs: fix wrong reservation when doing delayed inode operations
  btrfs: Remove unused sysfs code
  btrfs: fix dereference of ERR_PTR value
  Btrfs: fix relocation races
  Btrfs: set no_trans_join after trying to expand the transaction
  Btrfs: protect the pending_snapshots list with trans_lock
  Btrfs: fix path leakage on subvol deletion
  Btrfs: drop the delalloc_bytes check in shrink_delalloc
  Btrfs: check the return value from set_anon_super
  • Loading branch information
torvalds committed Jun 20, 2011
2 parents 10e18e6 + e999376 commit 90a800d
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 189 deletions.
15 changes: 14 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,12 @@ struct btrfs_fs_info {
struct srcu_struct subvol_srcu;

spinlock_t trans_lock;
/*
* the reloc mutex goes with the trans lock, it is taken
* during commit to protect us from the relocation code
*/
struct mutex reloc_mutex;

struct list_head trans_list;
struct list_head hashers;
struct list_head dead_roots;
Expand Down Expand Up @@ -1172,6 +1178,14 @@ struct btrfs_root {
u32 type;

u64 highest_objectid;

/* btrfs_record_root_in_trans is a multi-step process,
* and it can race with the balancing code. But the
* race is very small, and only the first time the root
* is added to each transaction. So in_trans_setup
* is used to tell us when more checks are required
*/
unsigned long in_trans_setup;
int ref_cows;
int track_dirty;
int in_radix;
Expand All @@ -1181,7 +1195,6 @@ struct btrfs_root {
struct btrfs_key defrag_max;
int defrag_running;
char *name;
int in_sysfs;

/* the dirty list is only used by non-reference counted roots */
struct list_head dirty_list;
Expand Down
32 changes: 27 additions & 5 deletions fs/btrfs/delayed-inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ struct btrfs_delayed_item *btrfs_alloc_delayed_item(u32 data_len)
item->data_len = data_len;
item->ins_or_del = 0;
item->bytes_reserved = 0;
item->block_rsv = NULL;
item->delayed_node = NULL;
atomic_set(&item->refs, 1);
}
Expand Down Expand Up @@ -593,21 +592,22 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,

num_bytes = btrfs_calc_trans_metadata_size(root, 1);
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
if (!ret) {
if (!ret)
item->bytes_reserved = num_bytes;
item->block_rsv = dst_rsv;
}

return ret;
}

static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
struct btrfs_delayed_item *item)
{
struct btrfs_block_rsv *rsv;

if (!item->bytes_reserved)
return;

btrfs_block_rsv_release(root, item->block_rsv,
rsv = &root->fs_info->global_block_rsv;
btrfs_block_rsv_release(root, rsv,
item->bytes_reserved);
}

Expand Down Expand Up @@ -1014,13 +1014,17 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
struct btrfs_delayed_root *delayed_root;
struct btrfs_delayed_node *curr_node, *prev_node;
struct btrfs_path *path;
struct btrfs_block_rsv *block_rsv;
int ret = 0;

path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
path->leave_spinning = 1;

block_rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->global_block_rsv;

delayed_root = btrfs_get_delayed_root(root);

curr_node = btrfs_first_delayed_node(delayed_root);
Expand All @@ -1045,27 +1049,33 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
}

btrfs_free_path(path);
trans->block_rsv = block_rsv;
return ret;
}

static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
struct btrfs_delayed_node *node)
{
struct btrfs_path *path;
struct btrfs_block_rsv *block_rsv;
int ret;

path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
path->leave_spinning = 1;

block_rsv = trans->block_rsv;
trans->block_rsv = &node->root->fs_info->global_block_rsv;

ret = btrfs_insert_delayed_items(trans, path, node->root, node);
if (!ret)
ret = btrfs_delete_delayed_items(trans, path, node->root, node);
if (!ret)
ret = btrfs_update_delayed_inode(trans, node->root, path, node);
btrfs_free_path(path);

trans->block_rsv = block_rsv;
return ret;
}

Expand Down Expand Up @@ -1116,6 +1126,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
struct btrfs_path *path;
struct btrfs_delayed_node *delayed_node = NULL;
struct btrfs_root *root;
struct btrfs_block_rsv *block_rsv;
unsigned long nr = 0;
int need_requeue = 0;
int ret;
Expand All @@ -1134,6 +1145,9 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
if (IS_ERR(trans))
goto free_path;

block_rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->global_block_rsv;

ret = btrfs_insert_delayed_items(trans, path, root, delayed_node);
if (!ret)
ret = btrfs_delete_delayed_items(trans, path, root,
Expand Down Expand Up @@ -1176,6 +1190,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)

nr = trans->blocks_used;

trans->block_rsv = block_rsv;
btrfs_end_transaction_dmeta(trans, root);
__btrfs_btree_balance_dirty(root, nr);
free_path:
Expand Down Expand Up @@ -1222,6 +1237,13 @@ static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root,
return 0;
}

void btrfs_assert_delayed_root_empty(struct btrfs_root *root)
{
struct btrfs_delayed_root *delayed_root;
delayed_root = btrfs_get_delayed_root(root);
WARN_ON(btrfs_first_delayed_node(delayed_root));
}

void btrfs_balance_delayed_items(struct btrfs_root *root)
{
struct btrfs_delayed_root *delayed_root;
Expand Down
5 changes: 4 additions & 1 deletion fs/btrfs/delayed-inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ struct btrfs_delayed_item {
struct list_head tree_list; /* used for batch insert/delete items */
struct list_head readdir_list; /* used for readdir items */
u64 bytes_reserved;
struct btrfs_block_rsv *block_rsv;
struct btrfs_delayed_node *delayed_node;
atomic_t refs;
int ins_or_del;
Expand Down Expand Up @@ -138,4 +137,8 @@ int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
/* for init */
int __init btrfs_delayed_inode_init(void);
void btrfs_delayed_inode_exit(void);

/* for debugging */
void btrfs_assert_delayed_root_empty(struct btrfs_root *root);

#endif
12 changes: 7 additions & 5 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->last_trans = 0;
root->highest_objectid = 0;
root->name = NULL;
root->in_sysfs = 0;
root->inode_tree = RB_ROOT;
INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
root->block_rsv = NULL;
Expand Down Expand Up @@ -1300,19 +1299,21 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
return root;

root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS);
if (!root->free_ino_ctl)
goto fail;
root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned),
GFP_NOFS);
if (!root->free_ino_pinned)
if (!root->free_ino_pinned || !root->free_ino_ctl) {
ret = -ENOMEM;
goto fail;
}

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

set_anon_super(&root->anon_super, NULL);
ret = set_anon_super(&root->anon_super, NULL);
if (ret)
goto fail;

if (btrfs_root_refs(&root->root_item) == 0) {
ret = -ENOENT;
Expand Down Expand Up @@ -1618,6 +1619,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
spin_lock_init(&fs_info->fs_roots_radix_lock);
spin_lock_init(&fs_info->delayed_iput_lock);
spin_lock_init(&fs_info->defrag_inodes_lock);
mutex_init(&fs_info->reloc_mutex);

init_completion(&fs_info->kobj_unregister);
fs_info->tree_root = tree_root;
Expand Down
4 changes: 0 additions & 4 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -3314,10 +3314,6 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
if (reserved == 0)
return 0;

/* nothing to shrink - nothing to reclaim */
if (root->fs_info->delalloc_bytes == 0)
return 0;

max_reclaim = min(reserved, to_reclaim);

while (loops < 1024) {
Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3076,6 +3076,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
ret = btrfs_update_inode(trans, root, dir);
BUG_ON(ret);

btrfs_free_path(path);
return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
ret = btrfs_snap_reserve_metadata(trans, pending_snapshot);
BUG_ON(ret);

spin_lock(&root->fs_info->trans_lock);
list_add(&pending_snapshot->list,
&trans->transaction->pending_snapshots);
spin_unlock(&root->fs_info->trans_lock);
if (async_transid) {
*async_transid = trans->transid;
ret = btrfs_commit_transaction_async(trans,
Expand Down
30 changes: 21 additions & 9 deletions fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -1368,7 +1368,7 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
int ret;

if (!root->reloc_root)
return 0;
goto out;

reloc_root = root->reloc_root;
root_item = &reloc_root->root_item;
Expand All @@ -1390,6 +1390,8 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
ret = btrfs_update_root(trans, root->fs_info->tree_root,
&reloc_root->root_key, root_item);
BUG_ON(ret);

out:
return 0;
}

Expand Down Expand Up @@ -2142,10 +2144,11 @@ int prepare_to_merge(struct reloc_control *rc, int err)
u64 num_bytes = 0;
int ret;

spin_lock(&root->fs_info->trans_lock);
mutex_lock(&root->fs_info->reloc_mutex);
rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2;
rc->merging_rsv_size += rc->nodes_relocated * 2;
spin_unlock(&root->fs_info->trans_lock);
mutex_unlock(&root->fs_info->reloc_mutex);

again:
if (!err) {
num_bytes = rc->merging_rsv_size;
Expand Down Expand Up @@ -2214,9 +2217,16 @@ int merge_reloc_roots(struct reloc_control *rc)
int ret;
again:
root = rc->extent_root;
spin_lock(&root->fs_info->trans_lock);

/*
* this serializes us with btrfs_record_root_in_transaction,
* we have to make sure nobody is in the middle of
* adding their roots to the list while we are
* doing this splice
*/
mutex_lock(&root->fs_info->reloc_mutex);
list_splice_init(&rc->reloc_roots, &reloc_roots);
spin_unlock(&root->fs_info->trans_lock);
mutex_unlock(&root->fs_info->reloc_mutex);

while (!list_empty(&reloc_roots)) {
found = 1;
Expand Down Expand Up @@ -3590,17 +3600,19 @@ int find_next_extent(struct btrfs_trans_handle *trans,
static void set_reloc_control(struct reloc_control *rc)
{
struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
spin_lock(&fs_info->trans_lock);

mutex_lock(&fs_info->reloc_mutex);
fs_info->reloc_ctl = rc;
spin_unlock(&fs_info->trans_lock);
mutex_unlock(&fs_info->reloc_mutex);
}

static void unset_reloc_control(struct reloc_control *rc)
{
struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
spin_lock(&fs_info->trans_lock);

mutex_lock(&fs_info->reloc_mutex);
fs_info->reloc_ctl = NULL;
spin_unlock(&fs_info->trans_lock);
mutex_unlock(&fs_info->reloc_mutex);
}

static int check_extent_flags(u64 flags)
Expand Down
Loading

0 comments on commit 90a800d

Please sign in to comment.