Commit b478b2ba authored by Chris Mason's avatar Chris Mason

Merge branch 'qgroup' of git://git.jan-o-sch.net/btrfs-unstable into for-linus

Conflicts:
	fs/btrfs/ioctl.c
	fs/btrfs/ioctl.h
	fs/btrfs/transaction.c
	fs/btrfs/transaction.h
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parents 67c9684f 6f72c7e2
...@@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ ...@@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
export.o tree-log.o free-space-cache.o zlib.o lzo.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
reada.o backref.o ulist.o reada.o backref.o ulist.o qgroup.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
...@@ -773,9 +773,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info, ...@@ -773,9 +773,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
*/ */
static int find_parent_nodes(struct btrfs_trans_handle *trans, static int find_parent_nodes(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr, struct btrfs_fs_info *fs_info, u64 bytenr,
u64 delayed_ref_seq, u64 time_seq, u64 time_seq, struct ulist *refs,
struct ulist *refs, struct ulist *roots, struct ulist *roots, const u64 *extent_item_pos)
const u64 *extent_item_pos)
{ {
struct btrfs_key key; struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
...@@ -837,7 +836,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -837,7 +836,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
btrfs_put_delayed_ref(&head->node); btrfs_put_delayed_ref(&head->node);
goto again; goto again;
} }
ret = __add_delayed_refs(head, delayed_ref_seq, ret = __add_delayed_refs(head, time_seq,
&prefs_delayed); &prefs_delayed);
mutex_unlock(&head->mutex); mutex_unlock(&head->mutex);
if (ret) { if (ret) {
...@@ -981,8 +980,7 @@ static void free_leaf_list(struct ulist *blocks) ...@@ -981,8 +980,7 @@ static void free_leaf_list(struct ulist *blocks)
*/ */
static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr, struct btrfs_fs_info *fs_info, u64 bytenr,
u64 delayed_ref_seq, u64 time_seq, u64 time_seq, struct ulist **leafs,
struct ulist **leafs,
const u64 *extent_item_pos) const u64 *extent_item_pos)
{ {
struct ulist *tmp; struct ulist *tmp;
...@@ -997,7 +995,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, ...@@ -997,7 +995,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
return -ENOMEM; return -ENOMEM;
} }
ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq, ret = find_parent_nodes(trans, fs_info, bytenr,
time_seq, *leafs, tmp, extent_item_pos); time_seq, *leafs, tmp, extent_item_pos);
ulist_free(tmp); ulist_free(tmp);
...@@ -1024,8 +1022,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, ...@@ -1024,8 +1022,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
*/ */
int btrfs_find_all_roots(struct btrfs_trans_handle *trans, int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr, struct btrfs_fs_info *fs_info, u64 bytenr,
u64 delayed_ref_seq, u64 time_seq, u64 time_seq, struct ulist **roots)
struct ulist **roots)
{ {
struct ulist *tmp; struct ulist *tmp;
struct ulist_node *node = NULL; struct ulist_node *node = NULL;
...@@ -1043,7 +1040,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, ...@@ -1043,7 +1040,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
ULIST_ITER_INIT(&uiter); ULIST_ITER_INIT(&uiter);
while (1) { while (1) {
ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq, ret = find_parent_nodes(trans, fs_info, bytenr,
time_seq, tmp, *roots, NULL); time_seq, tmp, *roots, NULL);
if (ret < 0 && ret != -ENOENT) { if (ret < 0 && ret != -ENOENT) {
ulist_free(tmp); ulist_free(tmp);
...@@ -1376,11 +1373,9 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, ...@@ -1376,11 +1373,9 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
struct ulist *roots = NULL; struct ulist *roots = NULL;
struct ulist_node *ref_node = NULL; struct ulist_node *ref_node = NULL;
struct ulist_node *root_node = NULL; struct ulist_node *root_node = NULL;
struct seq_list seq_elem = {};
struct seq_list tree_mod_seq_elem = {}; struct seq_list tree_mod_seq_elem = {};
struct ulist_iterator ref_uiter; struct ulist_iterator ref_uiter;
struct ulist_iterator root_uiter; struct ulist_iterator root_uiter;
struct btrfs_delayed_ref_root *delayed_refs = NULL;
pr_debug("resolving all inodes for extent %llu\n", pr_debug("resolving all inodes for extent %llu\n",
extent_item_objectid); extent_item_objectid);
...@@ -1391,16 +1386,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, ...@@ -1391,16 +1386,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
trans = btrfs_join_transaction(fs_info->extent_root); trans = btrfs_join_transaction(fs_info->extent_root);
if (IS_ERR(trans)) if (IS_ERR(trans))
return PTR_ERR(trans); return PTR_ERR(trans);
delayed_refs = &trans->transaction->delayed_refs;
spin_lock(&delayed_refs->lock);
btrfs_get_delayed_seq(delayed_refs, &seq_elem);
spin_unlock(&delayed_refs->lock);
btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
} }
ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
seq_elem.seq, tree_mod_seq_elem.seq, &refs, tree_mod_seq_elem.seq, &refs,
&extent_item_pos); &extent_item_pos);
if (ret) if (ret)
goto out; goto out;
...@@ -1408,8 +1398,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, ...@@ -1408,8 +1398,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
ULIST_ITER_INIT(&ref_uiter); ULIST_ITER_INIT(&ref_uiter);
while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, ret = btrfs_find_all_roots(trans, fs_info, ref_node->val,
seq_elem.seq, tree_mod_seq_elem.seq, &roots);
tree_mod_seq_elem.seq, &roots);
if (ret) if (ret)
break; break;
ULIST_ITER_INIT(&root_uiter); ULIST_ITER_INIT(&root_uiter);
...@@ -1431,7 +1420,6 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, ...@@ -1431,7 +1420,6 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
out: out:
if (!search_commit_root) { if (!search_commit_root) {
btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
btrfs_put_delayed_seq(delayed_refs, &seq_elem);
btrfs_end_transaction(trans, fs_info->extent_root); btrfs_end_transaction(trans, fs_info->extent_root);
} }
......
...@@ -58,8 +58,7 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath); ...@@ -58,8 +58,7 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
int btrfs_find_all_roots(struct btrfs_trans_handle *trans, int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr, struct btrfs_fs_info *fs_info, u64 bytenr,
u64 delayed_ref_seq, u64 time_seq, u64 time_seq, struct ulist **roots);
struct ulist **roots);
struct btrfs_data_container *init_data_container(u32 total_bytes); struct btrfs_data_container *init_data_container(u32 total_bytes);
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
......
This diff is collapsed.
This diff is collapsed.
...@@ -233,22 +233,26 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, ...@@ -233,22 +233,26 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs,
u64 seq) u64 seq)
{ {
struct seq_list *elem; struct seq_list *elem;
int ret = 0;
assert_spin_locked(&delayed_refs->lock);
if (list_empty(&delayed_refs->seq_head)) spin_lock(&fs_info->tree_mod_seq_lock);
return 0; if (!list_empty(&fs_info->tree_mod_seq_list)) {
elem = list_first_entry(&fs_info->tree_mod_seq_list,
elem = list_first_entry(&delayed_refs->seq_head, struct seq_list, list); struct seq_list, list);
if (seq >= elem->seq) { if (seq >= elem->seq) {
pr_debug("holding back delayed_ref %llu, lowest is %llu (%p)\n", pr_debug("holding back delayed_ref %llu, lowest is "
seq, elem->seq, delayed_refs); "%llu (%p)\n", seq, elem->seq, delayed_refs);
return 1; ret = 1;
}
} }
return 0;
spin_unlock(&fs_info->tree_mod_seq_lock);
return ret;
} }
int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
...@@ -525,8 +529,8 @@ static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -525,8 +529,8 @@ static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
ref->is_head = 0; ref->is_head = 0;
ref->in_tree = 1; ref->in_tree = 1;
if (is_fstree(ref_root)) if (need_ref_seq(for_cow, ref_root))
seq = inc_delayed_seq(delayed_refs); seq = btrfs_get_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
ref->seq = seq; ref->seq = seq;
full_ref = btrfs_delayed_node_to_tree_ref(ref); full_ref = btrfs_delayed_node_to_tree_ref(ref);
...@@ -584,8 +588,8 @@ static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -584,8 +588,8 @@ static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
ref->is_head = 0; ref->is_head = 0;
ref->in_tree = 1; ref->in_tree = 1;
if (is_fstree(ref_root)) if (need_ref_seq(for_cow, ref_root))
seq = inc_delayed_seq(delayed_refs); seq = btrfs_get_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
ref->seq = seq; ref->seq = seq;
full_ref = btrfs_delayed_node_to_data_ref(ref); full_ref = btrfs_delayed_node_to_data_ref(ref);
...@@ -658,10 +662,12 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -658,10 +662,12 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr, add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
num_bytes, parent, ref_root, level, action, num_bytes, parent, ref_root, level, action,
for_cow); for_cow);
if (!is_fstree(ref_root) && if (!need_ref_seq(for_cow, ref_root) &&
waitqueue_active(&delayed_refs->seq_wait)) waitqueue_active(&fs_info->tree_mod_seq_wait))
wake_up(&delayed_refs->seq_wait); wake_up(&fs_info->tree_mod_seq_wait);
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
if (need_ref_seq(for_cow, ref_root))
btrfs_qgroup_record_ref(trans, &ref->node, extent_op);
return 0; return 0;
} }
...@@ -707,10 +713,12 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -707,10 +713,12 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
add_delayed_data_ref(fs_info, trans, &ref->node, bytenr, add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
num_bytes, parent, ref_root, owner, offset, num_bytes, parent, ref_root, owner, offset,
action, for_cow); action, for_cow);
if (!is_fstree(ref_root) && if (!need_ref_seq(for_cow, ref_root) &&
waitqueue_active(&delayed_refs->seq_wait)) waitqueue_active(&fs_info->tree_mod_seq_wait))
wake_up(&delayed_refs->seq_wait); wake_up(&fs_info->tree_mod_seq_wait);
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
if (need_ref_seq(for_cow, ref_root))
btrfs_qgroup_record_ref(trans, &ref->node, extent_op);
return 0; return 0;
} }
...@@ -736,8 +744,8 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, ...@@ -736,8 +744,8 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
num_bytes, BTRFS_UPDATE_DELAYED_HEAD, num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
extent_op->is_data); extent_op->is_data);
if (waitqueue_active(&delayed_refs->seq_wait)) if (waitqueue_active(&fs_info->tree_mod_seq_wait))
wake_up(&delayed_refs->seq_wait); wake_up(&fs_info->tree_mod_seq_wait);
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
return 0; return 0;
} }
......
...@@ -139,26 +139,6 @@ struct btrfs_delayed_ref_root { ...@@ -139,26 +139,6 @@ struct btrfs_delayed_ref_root {
int flushing; int flushing;
u64 run_delayed_start; u64 run_delayed_start;
/*
* seq number of delayed refs. We need to know if a backref was being
* added before the currently processed ref or afterwards.
*/
u64 seq;
/*
* seq_list holds a list of all seq numbers that are currently being
* added to the list. While walking backrefs (btrfs_find_all_roots,
* qgroups), which might take some time, no newer ref must be processed,
* as it might influence the outcome of the walk.
*/
struct list_head seq_head;
/*
* when the only refs we have in the list must not be processed, we want
* to wait for more refs to show up or for the end of backref walking.
*/
wait_queue_head_t seq_wait;
}; };
static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
...@@ -195,34 +175,28 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, ...@@ -195,34 +175,28 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
struct list_head *cluster, u64 search_start); struct list_head *cluster, u64 search_start);
static inline u64 inc_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs) int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
{ struct btrfs_delayed_ref_root *delayed_refs,
assert_spin_locked(&delayed_refs->lock); u64 seq);
++delayed_refs->seq;
return delayed_refs->seq;
}
static inline void /*
btrfs_get_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, * delayed refs with a ref_seq > 0 must be held back during backref walking.
struct seq_list *elem) * this only applies to items in one of the fs-trees. for_cow items never need
* to be held back, so they won't get a ref_seq number.
*/
static inline int need_ref_seq(int for_cow, u64 rootid)
{ {
assert_spin_locked(&delayed_refs->lock); if (for_cow)
elem->seq = delayed_refs->seq; return 0;
list_add_tail(&elem->list, &delayed_refs->seq_head);
}
static inline void if (rootid == BTRFS_FS_TREE_OBJECTID)
btrfs_put_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, return 1;
struct seq_list *elem)
{
spin_lock(&delayed_refs->lock);
list_del(&elem->list);
wake_up(&delayed_refs->seq_wait);
spin_unlock(&delayed_refs->lock);
}
int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, if ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID)
u64 seq); return 1;
return 0;
}
/* /*
* a node might live in a head or a regular ref, this lets you * a node might live in a head or a regular ref, this lets you
......
...@@ -1225,6 +1225,82 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info) ...@@ -1225,6 +1225,82 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
return root; return root;
} }
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
u64 objectid)
{
struct extent_buffer *leaf;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *root;
struct btrfs_key key;
int ret = 0;
u64 bytenr;
root = btrfs_alloc_root(fs_info);
if (!root)
return ERR_PTR(-ENOMEM);
__setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
root, fs_info, objectid);
root->root_key.objectid = objectid;
root->root_key.type = BTRFS_ROOT_ITEM_KEY;
root->root_key.offset = 0;
leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
0, objectid, NULL, 0, 0, 0);
if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf);
goto fail;
}
bytenr = leaf->start;
memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_bytenr(leaf, leaf->start);
btrfs_set_header_generation(leaf, trans->transid);
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(leaf, objectid);
root->node = leaf;
write_extent_buffer(leaf, fs_info->fsid,
(unsigned long)btrfs_header_fsid(leaf),
BTRFS_FSID_SIZE);
write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
(unsigned long)btrfs_header_chunk_tree_uuid(leaf),
BTRFS_UUID_SIZE);
btrfs_mark_buffer_dirty(leaf);
root->commit_root = btrfs_root_node(root);
root->track_dirty = 1;
root->root_item.flags = 0;
root->root_item.byte_limit = 0;
btrfs_set_root_bytenr(&root->root_item, leaf->start);
btrfs_set_root_generation(&root->root_item, trans->transid);
btrfs_set_root_level(&root->root_item, 0);
btrfs_set_root_refs(&root->root_item, 1);
btrfs_set_root_used(&root->root_item, leaf->len);
btrfs_set_root_last_snapshot(&root->root_item, 0);
btrfs_set_root_dirid(&root->root_item, 0);
root->root_item.drop_level = 0;
key.objectid = objectid;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = 0;
ret = btrfs_insert_root(trans, tree_root, &key, &root->root_item);
if (ret)
goto fail;
btrfs_tree_unlock(leaf);
fail:
if (ret)
return ERR_PTR(ret);
return root;
}
static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info) struct btrfs_fs_info *fs_info)
{ {
...@@ -1396,6 +1472,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1396,6 +1472,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
return fs_info->dev_root; return fs_info->dev_root;
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
return fs_info->csum_root; return fs_info->csum_root;
if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
return fs_info->quota_root ? fs_info->quota_root :
ERR_PTR(-ENOENT);
again: again:
spin_lock(&fs_info->fs_roots_radix_lock); spin_lock(&fs_info->fs_roots_radix_lock);
root = radix_tree_lookup(&fs_info->fs_roots_radix, root = radix_tree_lookup(&fs_info->fs_roots_radix,
...@@ -1823,6 +1902,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) ...@@ -1823,6 +1902,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
free_extent_buffer(info->extent_root->commit_root); free_extent_buffer(info->extent_root->commit_root);
free_extent_buffer(info->csum_root->node); free_extent_buffer(info->csum_root->node);
free_extent_buffer(info->csum_root->commit_root); free_extent_buffer(info->csum_root->commit_root);
if (info->quota_root) {
free_extent_buffer(info->quota_root->node);
free_extent_buffer(info->quota_root->commit_root);
}
info->tree_root->node = NULL; info->tree_root->node = NULL;
info->tree_root->commit_root = NULL; info->tree_root->commit_root = NULL;
...@@ -1832,6 +1915,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) ...@@ -1832,6 +1915,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
info->extent_root->commit_root = NULL; info->extent_root->commit_root = NULL;
info->csum_root->node = NULL; info->csum_root->node = NULL;
info->csum_root->commit_root = NULL; info->csum_root->commit_root = NULL;
if (info->quota_root) {
info->quota_root->node = NULL;
info->quota_root->commit_root = NULL;
}
if (chunk_root) { if (chunk_root) {
free_extent_buffer(info->chunk_root->node); free_extent_buffer(info->chunk_root->node);
...@@ -1862,6 +1949,7 @@ int open_ctree(struct super_block *sb, ...@@ -1862,6 +1949,7 @@ int open_ctree(struct super_block *sb,
struct btrfs_root *csum_root; struct btrfs_root *csum_root;
struct btrfs_root *chunk_root; struct btrfs_root *chunk_root;
struct btrfs_root *dev_root; struct btrfs_root *dev_root;
struct btrfs_root *quota_root;
struct btrfs_root *log_tree_root; struct btrfs_root *log_tree_root;
int ret; int ret;
int err = -EINVAL; int err = -EINVAL;
...@@ -1873,9 +1961,10 @@ int open_ctree(struct super_block *sb, ...@@ -1873,9 +1961,10 @@ int open_ctree(struct super_block *sb,
csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info); csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info);
chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info); chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info); dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info);
quota_root = fs_info->quota_root = btrfs_alloc_root(fs_info);
if (!tree_root || !extent_root || !csum_root || if (!tree_root || !extent_root || !csum_root ||
!chunk_root || !dev_root) { !chunk_root || !dev_root || !quota_root) {
err = -ENOMEM; err = -ENOMEM;
goto fail; goto fail;
} }
...@@ -1944,6 +2033,8 @@ int open_ctree(struct super_block *sb, ...@@ -1944,6 +2033,8 @@ int open_ctree(struct super_block *sb,
fs_info->free_chunk_space = 0; fs_info->free_chunk_space = 0;
fs_info->tree_mod_log = RB_ROOT; fs_info->tree_mod_log = RB_ROOT;
init_waitqueue_head(&fs_info->tree_mod_seq_wait);
/* readahead state */ /* readahead state */
INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT); INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
spin_lock_init(&fs_info->reada_lock); spin_lock_init(&fs_info->reada_lock);
...@@ -2032,6 +2123,13 @@ int open_ctree(struct super_block *sb, ...@@ -2032,6 +2123,13 @@ int open_ctree(struct super_block *sb,
init_rwsem(&fs_info->cleanup_work_sem); init_rwsem(&fs_info->cleanup_work_sem);
init_rwsem(&fs_info->subvol_sem); init_rwsem(&fs_info->subvol_sem);
spin_lock_init(&fs_info->qgroup_lock);
fs_info->qgroup_tree = RB_ROOT;
INIT_LIST_HEAD(&fs_info->dirty_qgroups);
fs_info->qgroup_seq = 1;
fs_info->quota_enabled = 0;
fs_info->pending_quota_state = 0;
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
btrfs_init_free_cluster(&fs_info->data_alloc_cluster); btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
...@@ -2356,6 +2454,17 @@ int open_ctree(struct super_block *sb, ...@@ -2356,6 +2454,17 @@ int open_ctree(struct super_block *sb,
goto recovery_tree_root; goto recovery_tree_root;
csum_root->track_dirty = 1; csum_root->track_dirty = 1;
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_QUOTA_TREE_OBJECTID, quota_root);
if (ret) {
kfree(quota_root);
quota_root = fs_info->quota_root = NULL;
} else {
quota_root->track_dirty = 1;
fs_info->quota_enabled = 1;
fs_info->pending_quota_state = 1;
}
fs_info->generation = generation; fs_info->generation = generation;
fs_info->last_trans_committed = generation; fs_info->last_trans_committed = generation;
...@@ -2415,6 +2524,9 @@ int open_ctree(struct super_block *sb, ...@@ -2415,6 +2524,9 @@ int open_ctree(struct super_block *sb,
" integrity check module %s\n", sb->s_id); " integrity check module %s\n", sb->s_id);
} }
#endif #endif
ret = btrfs_read_qgroup_config(fs_info);
if (ret)
goto fail_trans_kthread;
/* do not make disk changes in broken FS */ /* do not make disk changes in broken FS */
if (btrfs_super_log_root(disk_super) != 0 && if (btrfs_super_log_root(disk_super) != 0 &&
...@@ -2425,7 +2537,7 @@ int open_ctree(struct super_block *sb, ...@@ -2425,7 +2537,7 @@ int open_ctree(struct super_block *sb,
printk(KERN_WARNING "Btrfs log replay required " printk(KERN_WARNING "Btrfs log replay required "
"on RO media\n"); "on RO media\n");
err = -EIO; err = -EIO;
goto fail_trans_kthread; goto fail_qgroup;
} }
blocksize = blocksize =
btrfs_level_size(tree_root, btrfs_level_size(tree_root,
...@@ -2434,7 +2546,7 @@ int open_ctree(struct super_block *sb, ...@@ -2434,7 +2546,7 @@ int open_ctree(struct super_block *sb,
log_tree_root = btrfs_alloc_root(fs_info); log_tree_root = btrfs_alloc_root(fs_info);
if (!log_tree_root) { if (!log_tree_root) {
err = -ENOMEM; err = -ENOMEM;
goto fail_trans_kthread; goto fail_qgroup;
} }
__setup_root(nodesize, leafsize, sectorsize, stripesize, __setup_root(nodesize, leafsize, sectorsize, stripesize,
...@@ -2474,7 +2586,7 @@ int open_ctree(struct super_block *sb, ...@@ -2474,7 +2586,7 @@ int open_ctree(struct super_block *sb,
printk(KERN_WARNING printk(KERN_WARNING
"btrfs: failed to recover relocation\n"); "btrfs: failed to recover relocation\n");
err = -EINVAL; err = -EINVAL;
goto fail_trans_kthread; goto fail_qgroup;
} }
} }
...@@ -2484,10 +2596,10 @@ int open_ctree(struct super_block *sb, ...@@ -2484,10 +2596,10 @@ int open_ctree(struct super_block *sb,
fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location); fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location);
if (!fs_info->fs_root) if (!fs_info->fs_root)
goto fail_trans_kthread; goto fail_qgroup;
if (IS_ERR(fs_info->fs_root)) { if (IS_ERR(fs_info->fs_root)) {
err = PTR_ERR(fs_info->fs_root); err = PTR_ERR(fs_info->fs_root);
goto fail_trans_kthread; goto fail_qgroup;
} }
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
...@@ -2511,6 +2623,8 @@ int open_ctree(struct super_block *sb, ...@@ -2511,6 +2623,8 @@ int open_ctree(struct super_block *sb,
return 0; return 0;
fail_qgroup:
btrfs_free_qgroup_config(fs_info);
fail_trans_kthread: fail_trans_kthread:
kthread_stop(fs_info->transaction_kthread); kthread_stop(fs_info->transaction_kthread);
fail_cleaner: fail_cleaner:
...@@ -3109,6 +3223,8 @@ int close_ctree(struct btrfs_root *root) ...@@ -3109,6 +3223,8 @@ int close_ctree(struct btrfs_root *root)
fs_info->closing = 2; fs_info->closing = 2;
smp_mb(); smp_mb();
btrfs_free_qgroup_config(root->fs_info);
if (fs_info->delalloc_bytes) { if (fs_info->delalloc_bytes) {
printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n", printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n",
(unsigned long long)fs_info->delalloc_bytes); (unsigned long long)fs_info->delalloc_bytes);
...@@ -3128,6 +3244,10 @@ int close_ctree(struct btrfs_root *root) ...@@ -3128,6 +3244,10 @@ int close_ctree(struct btrfs_root *root)
free_extent_buffer(fs_info->dev_root->commit_root); free_extent_buffer(fs_info->dev_root->commit_root);
free_extent_buffer(fs_info->csum_root->node); free_extent_buffer(fs_info->csum_root->node);
free_extent_buffer(fs_info->csum_root->commit_root); free_extent_buffer(fs_info->csum_root->commit_root);
if (fs_info->quota_root) {
free_extent_buffer(fs_info->quota_root->node);
free_extent_buffer(fs_info->quota_root->commit_root);
}
btrfs_free_block_groups(fs_info); btrfs_free_block_groups(fs_info);
...@@ -3258,7 +3378,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) ...@@ -3258,7 +3378,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
return btree_read_extent_buffer_pages(root, buf, 0, parent_transid); return btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
} }
static int btree_lock_page_hook(struct page *page, void *data, int btree_lock_page_hook(struct page *page, void *data,
void (*flush_fn)(void *)) void (*flush_fn)(void *))
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
......
...@@ -89,6 +89,12 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans, ...@@ -89,6 +89,12 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
int btrfs_cleanup_transaction(struct btrfs_root *root); int btrfs_cleanup_transaction(struct btrfs_root *root);
void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans, void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans,
struct btrfs_root *root); struct btrfs_root *root);
void btrfs_abort_devices(struct btrfs_root *root);
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
u64 objectid);
int btree_lock_page_hook(struct page *page, void *data,
void (*flush_fn)(void *));
#ifdef CONFIG_DEBUG_LOCK_ALLOC #ifdef CONFIG_DEBUG_LOCK_ALLOC
void btrfs_init_lockdep(void); void btrfs_init_lockdep(void);
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include "locking.h" #include "locking.h"
#include "free-space-cache.h" #include "free-space-cache.h"
#undef SCRAMBLE_DELAYED_REFS
/* /*
* control flags for do_chunk_alloc's force field * control flags for do_chunk_alloc's force field
* CHUNK_ALLOC_NO_FORCE means to only allocate a chunk * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk
...@@ -2217,6 +2219,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, ...@@ -2217,6 +2219,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_node *ref; struct btrfs_delayed_ref_node *ref;
struct btrfs_delayed_ref_head *locked_ref = NULL; struct btrfs_delayed_ref_head *locked_ref = NULL;
struct btrfs_delayed_extent_op *extent_op; struct btrfs_delayed_extent_op *extent_op;
struct btrfs_fs_info *fs_info = root->fs_info;
int ret; int ret;
int count = 0; int count = 0;
int must_insert_reserved = 0; int must_insert_reserved = 0;
...@@ -2255,7 +2258,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, ...@@ -2255,7 +2258,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
ref = select_delayed_ref(locked_ref); ref = select_delayed_ref(locked_ref);
if (ref && ref->seq && if (ref && ref->seq &&
btrfs_check_delayed_seq(delayed_refs, ref->seq)) { btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) {
/* /*
* there are still refs with lower seq numbers in the * there are still refs with lower seq numbers in the
* process of being added. Don't run this ref yet. * process of being added. Don't run this ref yet.
...@@ -2337,7 +2340,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, ...@@ -2337,7 +2340,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
} }
next: next:
do_chunk_alloc(trans, root->fs_info->extent_root, do_chunk_alloc(trans, fs_info->extent_root,
2 * 1024 * 1024, 2 * 1024 * 1024,
btrfs_get_alloc_profile(root, 0), btrfs_get_alloc_profile(root, 0),
CHUNK_ALLOC_NO_FORCE); CHUNK_ALLOC_NO_FORCE);
...@@ -2347,21 +2350,99 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, ...@@ -2347,21 +2350,99 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
return count; return count;
} }
static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs, static void wait_for_more_refs(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs,
unsigned long num_refs, unsigned long num_refs,
struct list_head *first_seq) struct list_head *first_seq)
{ {
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
pr_debug("waiting for more refs (num %ld, first %p)\n", pr_debug("waiting for more refs (num %ld, first %p)\n",
num_refs, first_seq); num_refs, first_seq);
wait_event(delayed_refs->seq_wait, wait_event(fs_info->tree_mod_seq_wait,
num_refs != delayed_refs->num_entries || num_refs != delayed_refs->num_entries ||
delayed_refs->seq_head.next != first_seq); fs_info->tree_mod_seq_list.next != first_seq);
pr_debug("done waiting for more refs (num %ld, first %p)\n", pr_debug("done waiting for more refs (num %ld, first %p)\n",
delayed_refs->num_entries, delayed_refs->seq_head.next); delayed_refs->num_entries, fs_info->tree_mod_seq_list.next);
spin_lock(&delayed_refs->lock); spin_lock(&delayed_refs->lock);
} }
#ifdef SCRAMBLE_DELAYED_REFS
/*
* Normally delayed refs get processed in ascending bytenr order. This
* correlates in most cases to the order added. To expose dependencies on this
* order, we start to process the tree in the middle instead of the beginning
*/
static u64 find_middle(struct rb_root *root)
{
struct rb_node *n = root->rb_node;
struct btrfs_delayed_ref_node *entry;
int alt = 1;
u64 middle;
u64 first = 0, last = 0;
n = rb_first(root);
if (n) {
entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
first = entry->bytenr;
}
n = rb_last(root);
if (n) {
entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
last = entry->bytenr;
}
n = root->rb_node;
while (n) {
entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
WARN_ON(!entry->in_tree);
middle = entry->bytenr;
if (alt)
n = n->rb_left;
else
n = n->rb_right;
alt = 1 - alt;
}
return middle;
}
#endif
int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info)
{
struct qgroup_update *qgroup_update;
int ret = 0;
if (list_empty(&trans->qgroup_ref_list) !=
!trans->delayed_ref_elem.seq) {
/* list without seq or seq without list */
printk(KERN_ERR "btrfs: qgroup accounting update error, list is%s empty, seq is %llu\n",
list_empty(&trans->qgroup_ref_list) ? "" : " not",
trans->delayed_ref_elem.seq);
BUG();
}
if (!trans->delayed_ref_elem.seq)
return 0;
while (!list_empty(&trans->qgroup_ref_list)) {
qgroup_update = list_first_entry(&trans->qgroup_ref_list,
struct qgroup_update, list);
list_del(&qgroup_update->list);
if (!ret)
ret = btrfs_qgroup_account_ref(
trans, fs_info, qgroup_update->node,
qgroup_update->extent_op);
kfree(qgroup_update);
}
btrfs_put_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
return ret;
}
/* /*
* this starts processing the delayed reference count updates and * this starts processing the delayed reference count updates and
* extent insertions we have queued up so far. count can be * extent insertions we have queued up so far. count can be
...@@ -2398,11 +2479,18 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2398,11 +2479,18 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
2 * 1024 * 1024, btrfs_get_alloc_profile(root, 0), 2 * 1024 * 1024, btrfs_get_alloc_profile(root, 0),
CHUNK_ALLOC_NO_FORCE); CHUNK_ALLOC_NO_FORCE);
btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
delayed_refs = &trans->transaction->delayed_refs; delayed_refs = &trans->transaction->delayed_refs;
INIT_LIST_HEAD(&cluster); INIT_LIST_HEAD(&cluster);
again: again:
consider_waiting = 0; consider_waiting = 0;
spin_lock(&delayed_refs->lock); spin_lock(&delayed_refs->lock);
#ifdef SCRAMBLE_DELAYED_REFS
delayed_refs->run_delayed_start = find_middle(&delayed_refs->root);
#endif
if (count == 0) { if (count == 0) {
count = delayed_refs->num_entries * 2; count = delayed_refs->num_entries * 2;
run_most = 1; run_most = 1;
...@@ -2437,7 +2525,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2437,7 +2525,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
num_refs = delayed_refs->num_entries; num_refs = delayed_refs->num_entries;
first_seq = root->fs_info->tree_mod_seq_list.next; first_seq = root->fs_info->tree_mod_seq_list.next;
} else { } else {
wait_for_more_refs(delayed_refs, wait_for_more_refs(root->fs_info, delayed_refs,
num_refs, first_seq); num_refs, first_seq);
/* /*
* after waiting, things have changed. we * after waiting, things have changed. we
...@@ -2502,6 +2590,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2502,6 +2590,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
} }
out: out:
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
assert_qgroups_uptodate(trans);
return 0; return 0;
} }
...@@ -4479,6 +4568,13 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) ...@@ -4479,6 +4568,13 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
csum_bytes = BTRFS_I(inode)->csum_bytes; csum_bytes = BTRFS_I(inode)->csum_bytes;
spin_unlock(&BTRFS_I(inode)->lock); spin_unlock(&BTRFS_I(inode)->lock);
if (root->fs_info->quota_enabled) {
ret = btrfs_qgroup_reserve(root, num_bytes +
nr_extents * root->leafsize);
if (ret)
return ret;
}
ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush); ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
if (ret) { if (ret) {
u64 to_free = 0; u64 to_free = 0;
...@@ -4557,6 +4653,11 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes) ...@@ -4557,6 +4653,11 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
trace_btrfs_space_reservation(root->fs_info, "delalloc", trace_btrfs_space_reservation(root->fs_info, "delalloc",
btrfs_ino(inode), to_free, 0); btrfs_ino(inode), to_free, 0);
if (root->fs_info->quota_enabled) {
btrfs_qgroup_free(root, num_bytes +
dropped * root->leafsize);
}
btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv, btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
to_free); to_free);
} }
...@@ -5193,8 +5294,8 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, ...@@ -5193,8 +5294,8 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
rb_erase(&head->node.rb_node, &delayed_refs->root); rb_erase(&head->node.rb_node, &delayed_refs->root);
delayed_refs->num_entries--; delayed_refs->num_entries--;
if (waitqueue_active(&delayed_refs->seq_wait)) if (waitqueue_active(&root->fs_info->tree_mod_seq_wait))
wake_up(&delayed_refs->seq_wait); wake_up(&root->fs_info->tree_mod_seq_wait);
/* /*
* we don't take a ref on the node because we're removing it from the * we don't take a ref on the node because we're removing it from the
......
...@@ -336,7 +336,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) ...@@ -336,7 +336,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
static noinline int create_subvol(struct btrfs_root *root, static noinline int create_subvol(struct btrfs_root *root,
struct dentry *dentry, struct dentry *dentry,
char *name, int namelen, char *name, int namelen,
u64 *async_transid) u64 *async_transid,
struct btrfs_qgroup_inherit **inherit)
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_key key; struct btrfs_key key;
...@@ -368,6 +369,11 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -368,6 +369,11 @@ static noinline int create_subvol(struct btrfs_root *root,
if (IS_ERR(trans)) if (IS_ERR(trans))
return PTR_ERR(trans); return PTR_ERR(trans);
ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid,
inherit ? *inherit : NULL);
if (ret)
goto fail;
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
0, objectid, NULL, 0, 0, 0); 0, objectid, NULL, 0, 0, 0);
if (IS_ERR(leaf)) { if (IS_ERR(leaf)) {
...@@ -484,7 +490,7 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -484,7 +490,7 @@ static noinline int create_subvol(struct btrfs_root *root,
static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
char *name, int namelen, u64 *async_transid, char *name, int namelen, u64 *async_transid,
bool readonly) bool readonly, struct btrfs_qgroup_inherit **inherit)
{ {
struct inode *inode; struct inode *inode;
struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_pending_snapshot *pending_snapshot;
...@@ -502,6 +508,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -502,6 +508,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
pending_snapshot->dentry = dentry; pending_snapshot->dentry = dentry;
pending_snapshot->root = root; pending_snapshot->root = root;
pending_snapshot->readonly = readonly; pending_snapshot->readonly = readonly;
if (inherit) {
pending_snapshot->inherit = *inherit;
*inherit = NULL; /* take responsibility to free it */
}
trans = btrfs_start_transaction(root->fs_info->extent_root, 5); trans = btrfs_start_transaction(root->fs_info->extent_root, 5);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
...@@ -635,7 +645,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) ...@@ -635,7 +645,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
static noinline int btrfs_mksubvol(struct path *parent, static noinline int btrfs_mksubvol(struct path *parent,
char *name, int namelen, char *name, int namelen,
struct btrfs_root *snap_src, struct btrfs_root *snap_src,
u64 *async_transid, bool readonly) u64 *async_transid, bool readonly,
struct btrfs_qgroup_inherit **inherit)
{ {
struct inode *dir = parent->dentry->d_inode; struct inode *dir = parent->dentry->d_inode;
struct dentry *dentry; struct dentry *dentry;
...@@ -662,11 +673,11 @@ static noinline int btrfs_mksubvol(struct path *parent, ...@@ -662,11 +673,11 @@ static noinline int btrfs_mksubvol(struct path *parent,
goto out_up_read; goto out_up_read;
if (snap_src) { if (snap_src) {
error = create_snapshot(snap_src, dentry, error = create_snapshot(snap_src, dentry, name, namelen,
name, namelen, async_transid, readonly); async_transid, readonly, inherit);
} else { } else {
error = create_subvol(BTRFS_I(dir)->root, dentry, error = create_subvol(BTRFS_I(dir)->root, dentry,
name, namelen, async_transid); name, namelen, async_transid, inherit);
} }
if (!error) if (!error)
fsnotify_mkdir(dir, dentry); fsnotify_mkdir(dir, dentry);
...@@ -1375,11 +1386,9 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, ...@@ -1375,11 +1386,9 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
} }
static noinline int btrfs_ioctl_snap_create_transid(struct file *file, static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
char *name, char *name, unsigned long fd, int subvol,
unsigned long fd, u64 *transid, bool readonly,
int subvol, struct btrfs_qgroup_inherit **inherit)
u64 *transid,
bool readonly)
{ {
struct file *src_file; struct file *src_file;
int namelen; int namelen;
...@@ -1403,7 +1412,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, ...@@ -1403,7 +1412,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
if (subvol) { if (subvol) {
ret = btrfs_mksubvol(&file->f_path, name, namelen, ret = btrfs_mksubvol(&file->f_path, name, namelen,
NULL, transid, readonly); NULL, transid, readonly, inherit);
} else { } else {
struct inode *src_inode; struct inode *src_inode;
src_file = fget(fd); src_file = fget(fd);
...@@ -1422,7 +1431,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, ...@@ -1422,7 +1431,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
} }
ret = btrfs_mksubvol(&file->f_path, name, namelen, ret = btrfs_mksubvol(&file->f_path, name, namelen,
BTRFS_I(src_inode)->root, BTRFS_I(src_inode)->root,
transid, readonly); transid, readonly, inherit);
fput(src_file); fput(src_file);
} }
out_drop_write: out_drop_write:
...@@ -1444,7 +1453,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, ...@@ -1444,7 +1453,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,
vol_args->fd, subvol, vol_args->fd, subvol,
NULL, false); NULL, false, NULL);
kfree(vol_args); kfree(vol_args);
return ret; return ret;
...@@ -1458,6 +1467,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, ...@@ -1458,6 +1467,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
u64 transid = 0; u64 transid = 0;
u64 *ptr = NULL; u64 *ptr = NULL;
bool readonly = false; bool readonly = false;
struct btrfs_qgroup_inherit *inherit = NULL;
vol_args = memdup_user(arg, sizeof(*vol_args)); vol_args = memdup_user(arg, sizeof(*vol_args));
if (IS_ERR(vol_args)) if (IS_ERR(vol_args))
...@@ -1465,7 +1475,8 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, ...@@ -1465,7 +1475,8 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
if (vol_args->flags & if (vol_args->flags &
~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY |
BTRFS_SUBVOL_QGROUP_INHERIT)) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out; goto out;
} }
...@@ -1474,10 +1485,21 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, ...@@ -1474,10 +1485,21 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
ptr = &transid; ptr = &transid;
if (vol_args->flags & BTRFS_SUBVOL_RDONLY) if (vol_args->flags & BTRFS_SUBVOL_RDONLY)
readonly = true; readonly = true;
if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
if (vol_args->size > PAGE_CACHE_SIZE) {
ret = -EINVAL;
goto out;
}
inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size);
if (IS_ERR(inherit)) {
ret = PTR_ERR(inherit);
goto out;
}
}
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,
vol_args->fd, subvol, vol_args->fd, subvol, ptr,
ptr, readonly); readonly, &inherit);
if (ret == 0 && ptr && if (ret == 0 && ptr &&
copy_to_user(arg + copy_to_user(arg +
...@@ -1486,6 +1508,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, ...@@ -1486,6 +1508,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
ret = -EFAULT; ret = -EFAULT;
out: out:
kfree(vol_args); kfree(vol_args);
kfree(inherit);
return ret; return ret;
} }
...@@ -3401,6 +3424,183 @@ static long btrfs_ioctl_balance_progress(struct btrfs_root *root, ...@@ -3401,6 +3424,183 @@ static long btrfs_ioctl_balance_progress(struct btrfs_root *root,
return ret; return ret;
} }
static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
{
struct btrfs_ioctl_quota_ctl_args *sa;
struct btrfs_trans_handle *trans = NULL;
int ret;
int err;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa))
return PTR_ERR(sa);
if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) {
trans = btrfs_start_transaction(root, 2);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
}
switch (sa->cmd) {
case BTRFS_QUOTA_CTL_ENABLE:
ret = btrfs_quota_enable(trans, root->fs_info);
break;
case BTRFS_QUOTA_CTL_DISABLE:
ret = btrfs_quota_disable(trans, root->fs_info);
break;
case BTRFS_QUOTA_CTL_RESCAN:
ret = btrfs_quota_rescan(root->fs_info);
break;
default:
ret = -EINVAL;
break;
}
if (copy_to_user(arg, sa, sizeof(*sa)))
ret = -EFAULT;
if (trans) {
err = btrfs_commit_transaction(trans, root);
if (err && !ret)
ret = err;
}
out:
kfree(sa);
return ret;
}
static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
{
struct btrfs_ioctl_qgroup_assign_args *sa;
struct btrfs_trans_handle *trans;
int ret;
int err;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa))
return PTR_ERR(sa);
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
/* FIXME: check if the IDs really exist */
if (sa->assign) {
ret = btrfs_add_qgroup_relation(trans, root->fs_info,
sa->src, sa->dst);
} else {
ret = btrfs_del_qgroup_relation(trans, root->fs_info,
sa->src, sa->dst);
}
err = btrfs_end_transaction(trans, root);
if (err && !ret)
ret = err;
out:
kfree(sa);
return ret;
}
static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
{
struct btrfs_ioctl_qgroup_create_args *sa;
struct btrfs_trans_handle *trans;
int ret;
int err;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa))
return PTR_ERR(sa);
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
/* FIXME: check if the IDs really exist */
if (sa->create) {
ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid,
NULL);
} else {
ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid);
}
err = btrfs_end_transaction(trans, root);
if (err && !ret)
ret = err;
out:
kfree(sa);
return ret;
}
static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
{
struct btrfs_ioctl_qgroup_limit_args *sa;
struct btrfs_trans_handle *trans;
int ret;
int err;
u64 qgroupid;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa))
return PTR_ERR(sa);
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
qgroupid = sa->qgroupid;
if (!qgroupid) {
/* take the current subvol as qgroup */
qgroupid = root->root_key.objectid;
}
/* FIXME: check if the IDs really exist */
ret = btrfs_limit_qgroup(trans, root->fs_info, qgroupid, &sa->lim);
err = btrfs_end_transaction(trans, root);
if (err && !ret)
ret = err;
out:
kfree(sa);
return ret;
}
long btrfs_ioctl(struct file *file, unsigned int long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg) cmd, unsigned long arg)
{ {
...@@ -3422,6 +3622,8 @@ long btrfs_ioctl(struct file *file, unsigned int ...@@ -3422,6 +3622,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_snap_create_v2(file, argp, 0); return btrfs_ioctl_snap_create_v2(file, argp, 0);
case BTRFS_IOC_SUBVOL_CREATE: case BTRFS_IOC_SUBVOL_CREATE:
return btrfs_ioctl_snap_create(file, argp, 1); return btrfs_ioctl_snap_create(file, argp, 1);
case BTRFS_IOC_SUBVOL_CREATE_V2:
return btrfs_ioctl_snap_create_v2(file, argp, 1);
case BTRFS_IOC_SNAP_DESTROY: case BTRFS_IOC_SNAP_DESTROY:
return btrfs_ioctl_snap_destroy(file, argp); return btrfs_ioctl_snap_destroy(file, argp);
case BTRFS_IOC_SUBVOL_GETFLAGS: case BTRFS_IOC_SUBVOL_GETFLAGS:
...@@ -3485,6 +3687,14 @@ long btrfs_ioctl(struct file *file, unsigned int ...@@ -3485,6 +3687,14 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_balance_progress(root, argp); return btrfs_ioctl_balance_progress(root, argp);
case BTRFS_IOC_GET_DEV_STATS: case BTRFS_IOC_GET_DEV_STATS:
return btrfs_ioctl_get_dev_stats(root, argp); return btrfs_ioctl_get_dev_stats(root, argp);
case BTRFS_IOC_QUOTA_CTL:
return btrfs_ioctl_quota_ctl(root, argp);
case BTRFS_IOC_QGROUP_ASSIGN:
return btrfs_ioctl_qgroup_assign(root, argp);
case BTRFS_IOC_QGROUP_CREATE:
return btrfs_ioctl_qgroup_create(root, argp);
case BTRFS_IOC_QGROUP_LIMIT:
return btrfs_ioctl_qgroup_limit(root, argp);
} }
return -ENOTTY; return -ENOTTY;
......
...@@ -32,15 +32,46 @@ struct btrfs_ioctl_vol_args { ...@@ -32,15 +32,46 @@ struct btrfs_ioctl_vol_args {
#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
#define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_RDONLY (1ULL << 1)
#define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2)
#define BTRFS_FSID_SIZE 16 #define BTRFS_FSID_SIZE 16
#define BTRFS_UUID_SIZE 16 #define BTRFS_UUID_SIZE 16
#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0)
struct btrfs_qgroup_limit {
__u64 flags;
__u64 max_rfer;
__u64 max_excl;
__u64 rsv_rfer;
__u64 rsv_excl;
};
struct btrfs_qgroup_inherit {
__u64 flags;
__u64 num_qgroups;
__u64 num_ref_copies;
__u64 num_excl_copies;
struct btrfs_qgroup_limit lim;
__u64 qgroups[0];
};
struct btrfs_ioctl_qgroup_limit_args {
__u64 qgroupid;
struct btrfs_qgroup_limit lim;
};
#define BTRFS_SUBVOL_NAME_MAX 4039 #define BTRFS_SUBVOL_NAME_MAX 4039
struct btrfs_ioctl_vol_args_v2 { struct btrfs_ioctl_vol_args_v2 {
__s64 fd; __s64 fd;
__u64 transid; __u64 transid;
__u64 flags; __u64 flags;
__u64 unused[4]; union {
struct {
__u64 size;
struct btrfs_qgroup_inherit __user *qgroup_inherit;
};
__u64 unused[4];
};
char name[BTRFS_SUBVOL_NAME_MAX + 1]; char name[BTRFS_SUBVOL_NAME_MAX + 1];
}; };
...@@ -299,6 +330,25 @@ struct btrfs_ioctl_get_dev_stats { ...@@ -299,6 +330,25 @@ struct btrfs_ioctl_get_dev_stats {
__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
}; };
#define BTRFS_QUOTA_CTL_ENABLE 1
#define BTRFS_QUOTA_CTL_DISABLE 2
#define BTRFS_QUOTA_CTL_RESCAN 3
struct btrfs_ioctl_quota_ctl_args {
__u64 cmd;
__u64 status;
};
struct btrfs_ioctl_qgroup_assign_args {
__u64 assign;
__u64 src;
__u64 dst;
};
struct btrfs_ioctl_qgroup_create_args {
__u64 create;
__u64 qgroupid;
};
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args) struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
...@@ -343,6 +393,8 @@ struct btrfs_ioctl_get_dev_stats { ...@@ -343,6 +393,8 @@ struct btrfs_ioctl_get_dev_stats {
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
struct btrfs_ioctl_vol_args_v2) struct btrfs_ioctl_vol_args_v2)
#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \
struct btrfs_ioctl_vol_args_v2)
#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64) #define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
#define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \ #define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \
...@@ -365,6 +417,14 @@ struct btrfs_ioctl_get_dev_stats { ...@@ -365,6 +417,14 @@ struct btrfs_ioctl_get_dev_stats {
struct btrfs_ioctl_ino_path_args) struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \ #define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \
struct btrfs_ioctl_vol_args) struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \
struct btrfs_ioctl_quota_ctl_args)
#define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \
struct btrfs_ioctl_qgroup_assign_args)
#define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \
struct btrfs_ioctl_qgroup_create_args)
#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \
struct btrfs_ioctl_qgroup_limit_args)
#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
struct btrfs_ioctl_get_dev_stats) struct btrfs_ioctl_get_dev_stats)
#endif #endif
This diff is collapsed.
...@@ -38,7 +38,6 @@ void put_transaction(struct btrfs_transaction *transaction) ...@@ -38,7 +38,6 @@ void put_transaction(struct btrfs_transaction *transaction)
if (atomic_dec_and_test(&transaction->use_count)) { if (atomic_dec_and_test(&transaction->use_count)) {
BUG_ON(!list_empty(&transaction->list)); BUG_ON(!list_empty(&transaction->list));
WARN_ON(transaction->delayed_refs.root.rb_node); WARN_ON(transaction->delayed_refs.root.rb_node);
WARN_ON(!list_empty(&transaction->delayed_refs.seq_head));
memset(transaction, 0, sizeof(*transaction)); memset(transaction, 0, sizeof(*transaction));
kmem_cache_free(btrfs_transaction_cachep, transaction); kmem_cache_free(btrfs_transaction_cachep, transaction);
} }
...@@ -126,7 +125,6 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) ...@@ -126,7 +125,6 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail)
cur_trans->delayed_refs.num_heads = 0; cur_trans->delayed_refs.num_heads = 0;
cur_trans->delayed_refs.flushing = 0; cur_trans->delayed_refs.flushing = 0;
cur_trans->delayed_refs.run_delayed_start = 0; cur_trans->delayed_refs.run_delayed_start = 0;
cur_trans->delayed_refs.seq = 1;
/* /*
* although the tree mod log is per file system and not per transaction, * although the tree mod log is per file system and not per transaction,
...@@ -145,10 +143,8 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) ...@@ -145,10 +143,8 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail)
} }
atomic_set(&fs_info->tree_mod_seq, 0); atomic_set(&fs_info->tree_mod_seq, 0);
init_waitqueue_head(&cur_trans->delayed_refs.seq_wait);
spin_lock_init(&cur_trans->commit_lock); spin_lock_init(&cur_trans->commit_lock);
spin_lock_init(&cur_trans->delayed_refs.lock); spin_lock_init(&cur_trans->delayed_refs.lock);
INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head);
INIT_LIST_HEAD(&cur_trans->pending_snapshots); INIT_LIST_HEAD(&cur_trans->pending_snapshots);
list_add_tail(&cur_trans->list, &fs_info->trans_list); list_add_tail(&cur_trans->list, &fs_info->trans_list);
...@@ -299,6 +295,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -299,6 +295,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
struct btrfs_transaction *cur_trans; struct btrfs_transaction *cur_trans;
u64 num_bytes = 0; u64 num_bytes = 0;
int ret; int ret;
u64 qgroup_reserved = 0;
if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
return ERR_PTR(-EROFS); return ERR_PTR(-EROFS);
...@@ -317,6 +314,14 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -317,6 +314,14 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
* the appropriate flushing if need be. * the appropriate flushing if need be.
*/ */
if (num_items > 0 && root != root->fs_info->chunk_root) { if (num_items > 0 && root != root->fs_info->chunk_root) {
if (root->fs_info->quota_enabled &&
is_fstree(root->root_key.objectid)) {
qgroup_reserved = num_items * root->leafsize;
ret = btrfs_qgroup_reserve(root, qgroup_reserved);
if (ret)
return ERR_PTR(ret);
}
num_bytes = btrfs_calc_trans_metadata_size(root, num_items); num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
ret = btrfs_block_rsv_add(root, ret = btrfs_block_rsv_add(root,
&root->fs_info->trans_block_rsv, &root->fs_info->trans_block_rsv,
...@@ -349,12 +354,16 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -349,12 +354,16 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
h->transaction = cur_trans; h->transaction = cur_trans;
h->blocks_used = 0; h->blocks_used = 0;
h->bytes_reserved = 0; h->bytes_reserved = 0;
h->root = root;
h->delayed_ref_updates = 0; h->delayed_ref_updates = 0;
h->use_count = 1; h->use_count = 1;
h->adding_csums = 0; h->adding_csums = 0;
h->block_rsv = NULL; h->block_rsv = NULL;
h->orig_rsv = NULL; h->orig_rsv = NULL;
h->aborted = 0; h->aborted = 0;
h->qgroup_reserved = qgroup_reserved;
h->delayed_ref_elem.seq = 0;
INIT_LIST_HEAD(&h->qgroup_ref_list);
smp_mb(); smp_mb();
if (cur_trans->blocked && may_wait_transaction(root, type)) { if (cur_trans->blocked && may_wait_transaction(root, type)) {
...@@ -505,6 +514,24 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -505,6 +514,24 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
/*
* do the qgroup accounting as early as possible
*/
err = btrfs_delayed_refs_qgroup_accounting(trans, info);
btrfs_trans_release_metadata(trans, root);
trans->block_rsv = NULL;
/*
* the same root has to be passed to start_transaction and
* end_transaction. Subvolume quota depends on this.
*/
WARN_ON(trans->root != root);
if (trans->qgroup_reserved) {
btrfs_qgroup_free(root, trans->qgroup_reserved);
trans->qgroup_reserved = 0;
}
while (count < 2) { while (count < 2) {
unsigned long cur = trans->delayed_ref_updates; unsigned long cur = trans->delayed_ref_updates;
trans->delayed_ref_updates = 0; trans->delayed_ref_updates = 0;
...@@ -559,6 +586,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -559,6 +586,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
err = -EIO; err = -EIO;
} }
assert_qgroups_uptodate(trans);
memset(trans, 0, sizeof(*trans)); memset(trans, 0, sizeof(*trans));
kmem_cache_free(btrfs_trans_handle_cachep, trans); kmem_cache_free(btrfs_trans_handle_cachep, trans);
...@@ -777,6 +805,13 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, ...@@ -777,6 +805,13 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
ret = btrfs_run_dev_stats(trans, root->fs_info); ret = btrfs_run_dev_stats(trans, root->fs_info);
BUG_ON(ret); BUG_ON(ret);
ret = btrfs_run_qgroups(trans, root->fs_info);
BUG_ON(ret);
/* run_qgroups might have added some more refs */
ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
BUG_ON(ret);
while (!list_empty(&fs_info->dirty_cowonly_roots)) { while (!list_empty(&fs_info->dirty_cowonly_roots)) {
next = fs_info->dirty_cowonly_roots.next; next = fs_info->dirty_cowonly_roots.next;
list_del_init(next); list_del_init(next);
...@@ -949,6 +984,14 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -949,6 +984,14 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
} }
} }
ret = btrfs_qgroup_inherit(trans, fs_info, root->root_key.objectid,
objectid, pending->inherit);
kfree(pending->inherit);
if (ret) {
pending->error = ret;
goto fail;
}
key.objectid = objectid; key.objectid = objectid;
key.offset = (u64)-1; key.offset = (u64)-1;
key.type = BTRFS_ROOT_ITEM_KEY; key.type = BTRFS_ROOT_ITEM_KEY;
...@@ -1344,6 +1387,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1344,6 +1387,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
if (ret) if (ret)
goto cleanup_transaction; goto cleanup_transaction;
/*
* running the delayed items may have added new refs. account
* them now so that they hinder processing of more delayed refs
* as little as possible.
*/
btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
/* /*
* rename don't use btrfs_join_transaction, so, once we * rename don't use btrfs_join_transaction, so, once we
* set the transaction to blocked above, we aren't going * set the transaction to blocked above, we aren't going
...@@ -1456,6 +1506,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1456,6 +1506,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
root->fs_info->chunk_root->node); root->fs_info->chunk_root->node);
switch_commit_root(root->fs_info->chunk_root); switch_commit_root(root->fs_info->chunk_root);
assert_qgroups_uptodate(trans);
update_super_roots(root); update_super_roots(root);
if (!root->fs_info->log_root_recovering) { if (!root->fs_info->log_root_recovering) {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define __BTRFS_TRANSACTION__ #define __BTRFS_TRANSACTION__
#include "btrfs_inode.h" #include "btrfs_inode.h"
#include "delayed-ref.h" #include "delayed-ref.h"
#include "ctree.h"
struct btrfs_transaction { struct btrfs_transaction {
u64 transid; u64 transid;
...@@ -49,6 +50,7 @@ struct btrfs_transaction { ...@@ -49,6 +50,7 @@ struct btrfs_transaction {
struct btrfs_trans_handle { struct btrfs_trans_handle {
u64 transid; u64 transid;
u64 bytes_reserved; u64 bytes_reserved;
u64 qgroup_reserved;
unsigned long use_count; unsigned long use_count;
unsigned long blocks_reserved; unsigned long blocks_reserved;
unsigned long blocks_used; unsigned long blocks_used;
...@@ -58,12 +60,21 @@ struct btrfs_trans_handle { ...@@ -58,12 +60,21 @@ struct btrfs_trans_handle {
struct btrfs_block_rsv *orig_rsv; struct btrfs_block_rsv *orig_rsv;
int aborted; int aborted;
int adding_csums; int adding_csums;
/*
* this root is only needed to validate that the root passed to
* start_transaction is the same as the one passed to end_transaction.
* Subvolume quota depends on this
*/
struct btrfs_root *root;
struct seq_list delayed_ref_elem;
struct list_head qgroup_ref_list;
}; };
struct btrfs_pending_snapshot { struct btrfs_pending_snapshot {
struct dentry *dentry; struct dentry *dentry;
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_root *snap; struct btrfs_root *snap;
struct btrfs_qgroup_inherit *inherit;
/* block reservation for the operation */ /* block reservation for the operation */
struct btrfs_block_rsv block_rsv; struct btrfs_block_rsv block_rsv;
/* extra metadata reseration for relocation */ /* extra metadata reseration for relocation */
......
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