diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-30 15:44:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-30 15:44:29 -0400 |
commit | 9613bebb223dea3179c265dc31e1bb41ae39f321 (patch) | |
tree | 39bf883573d23775a53be3172323c0237fef5630 /fs/btrfs/backref.c | |
parent | 40380f1c7841a5dcbf0b20f0b6da11969211ef77 (diff) | |
parent | bc3f116fec194f1d7329b160c266fe16b9266a1e (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs fixes and features from Chris Mason:
"We've merged in the error handling patches from SuSE. These are
already shipping in the sles kernel, and they give btrfs the ability
to abort transactions and go readonly on errors. It involves a lot of
churn as they clarify BUG_ONs, and remove the ones we now properly
deal with.
Josef reworked the way our metadata interacts with the page cache.
page->private now points to the btrfs extent_buffer object, which
makes everything faster. He changed it so we write an whole extent
buffer at a time instead of allowing individual pages to go down,,
which will be important for the raid5/6 code (for the 3.5 merge
window ;)
Josef also made us more aggressive about dropping pages for metadata
blocks that were freed due to COW. Overall, our metadata caching is
much faster now.
We've integrated my patch for metadata bigger than the page size.
This allows metadata blocks up to 64KB in size. In practice 16K and
32K seem to work best. For workloads with lots of metadata, this cuts
down the size of the extent allocation tree dramatically and fragments
much less.
Scrub was updated to support the larger block sizes, which ended up
being a fairly large change (thanks Stefan Behrens).
We also have an assortment of fixes and updates, especially to the
balancing code (Ilya Dryomov), the back ref walker (Jan Schmidt) and
the defragging code (Liu Bo)."
Fixed up trivial conflicts in fs/btrfs/scrub.c that were just due to
removal of the second argument to k[un]map_atomic() in commit
7ac687d9e047.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (75 commits)
Btrfs: update the checks for mixed block groups with big metadata blocks
Btrfs: update to the right index of defragment
Btrfs: do not bother to defrag an extent if it is a big real extent
Btrfs: add a check to decide if we should defrag the range
Btrfs: fix recursive defragment with autodefrag option
Btrfs: fix the mismatch of page->mapping
Btrfs: fix race between direct io and autodefrag
Btrfs: fix deadlock during allocating chunks
Btrfs: show useful info in space reservation tracepoint
Btrfs: don't use crc items bigger than 4KB
Btrfs: flush out and clean up any block device pages during mount
btrfs: disallow unequal data/metadata blocksize for mixed block groups
Btrfs: enhance superblock sanity checks
Btrfs: change scrub to support big blocks
Btrfs: minor cleanup in scrub
Btrfs: introduce common define for max number of mirrors
Btrfs: fix infinite loop in btrfs_shrink_device()
Btrfs: fix memory leak in resolver code
Btrfs: allow dup for data chunks in mixed mode
Btrfs: validate target profiles only if we are going to use them
...
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 122 |
1 files changed, 67 insertions, 55 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 0436c12da8c2..f4e90748940a 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -116,6 +116,7 @@ add_parent: | |||
116 | * to a logical address | 116 | * to a logical address |
117 | */ | 117 | */ |
118 | static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | 118 | static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, |
119 | int search_commit_root, | ||
119 | struct __prelim_ref *ref, | 120 | struct __prelim_ref *ref, |
120 | struct ulist *parents) | 121 | struct ulist *parents) |
121 | { | 122 | { |
@@ -131,6 +132,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
131 | path = btrfs_alloc_path(); | 132 | path = btrfs_alloc_path(); |
132 | if (!path) | 133 | if (!path) |
133 | return -ENOMEM; | 134 | return -ENOMEM; |
135 | path->search_commit_root = !!search_commit_root; | ||
134 | 136 | ||
135 | root_key.objectid = ref->root_id; | 137 | root_key.objectid = ref->root_id; |
136 | root_key.type = BTRFS_ROOT_ITEM_KEY; | 138 | root_key.type = BTRFS_ROOT_ITEM_KEY; |
@@ -188,6 +190,7 @@ out: | |||
188 | * resolve all indirect backrefs from the list | 190 | * resolve all indirect backrefs from the list |
189 | */ | 191 | */ |
190 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | 192 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, |
193 | int search_commit_root, | ||
191 | struct list_head *head) | 194 | struct list_head *head) |
192 | { | 195 | { |
193 | int err; | 196 | int err; |
@@ -212,7 +215,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | |||
212 | continue; | 215 | continue; |
213 | if (ref->count == 0) | 216 | if (ref->count == 0) |
214 | continue; | 217 | continue; |
215 | err = __resolve_indirect_ref(fs_info, ref, parents); | 218 | err = __resolve_indirect_ref(fs_info, search_commit_root, |
219 | ref, parents); | ||
216 | if (err) { | 220 | if (err) { |
217 | if (ret == 0) | 221 | if (ret == 0) |
218 | ret = err; | 222 | ret = err; |
@@ -586,6 +590,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, | |||
586 | struct btrfs_delayed_ref_head *head; | 590 | struct btrfs_delayed_ref_head *head; |
587 | int info_level = 0; | 591 | int info_level = 0; |
588 | int ret; | 592 | int ret; |
593 | int search_commit_root = (trans == BTRFS_BACKREF_SEARCH_COMMIT_ROOT); | ||
589 | struct list_head prefs_delayed; | 594 | struct list_head prefs_delayed; |
590 | struct list_head prefs; | 595 | struct list_head prefs; |
591 | struct __prelim_ref *ref; | 596 | struct __prelim_ref *ref; |
@@ -600,6 +605,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, | |||
600 | path = btrfs_alloc_path(); | 605 | path = btrfs_alloc_path(); |
601 | if (!path) | 606 | if (!path) |
602 | return -ENOMEM; | 607 | return -ENOMEM; |
608 | path->search_commit_root = !!search_commit_root; | ||
603 | 609 | ||
604 | /* | 610 | /* |
605 | * grab both a lock on the path and a lock on the delayed ref head. | 611 | * grab both a lock on the path and a lock on the delayed ref head. |
@@ -614,35 +620,39 @@ again: | |||
614 | goto out; | 620 | goto out; |
615 | BUG_ON(ret == 0); | 621 | BUG_ON(ret == 0); |
616 | 622 | ||
617 | /* | 623 | if (trans != BTRFS_BACKREF_SEARCH_COMMIT_ROOT) { |
618 | * look if there are updates for this ref queued and lock the head | 624 | /* |
619 | */ | 625 | * look if there are updates for this ref queued and lock the |
620 | delayed_refs = &trans->transaction->delayed_refs; | 626 | * head |
621 | spin_lock(&delayed_refs->lock); | 627 | */ |
622 | head = btrfs_find_delayed_ref_head(trans, bytenr); | 628 | delayed_refs = &trans->transaction->delayed_refs; |
623 | if (head) { | 629 | spin_lock(&delayed_refs->lock); |
624 | if (!mutex_trylock(&head->mutex)) { | 630 | head = btrfs_find_delayed_ref_head(trans, bytenr); |
625 | atomic_inc(&head->node.refs); | 631 | if (head) { |
626 | spin_unlock(&delayed_refs->lock); | 632 | if (!mutex_trylock(&head->mutex)) { |
627 | 633 | atomic_inc(&head->node.refs); | |
628 | btrfs_release_path(path); | 634 | spin_unlock(&delayed_refs->lock); |
629 | 635 | ||
630 | /* | 636 | btrfs_release_path(path); |
631 | * Mutex was contended, block until it's | 637 | |
632 | * released and try again | 638 | /* |
633 | */ | 639 | * Mutex was contended, block until it's |
634 | mutex_lock(&head->mutex); | 640 | * released and try again |
635 | mutex_unlock(&head->mutex); | 641 | */ |
636 | btrfs_put_delayed_ref(&head->node); | 642 | mutex_lock(&head->mutex); |
637 | goto again; | 643 | mutex_unlock(&head->mutex); |
638 | } | 644 | btrfs_put_delayed_ref(&head->node); |
639 | ret = __add_delayed_refs(head, seq, &info_key, &prefs_delayed); | 645 | goto again; |
640 | if (ret) { | 646 | } |
641 | spin_unlock(&delayed_refs->lock); | 647 | ret = __add_delayed_refs(head, seq, &info_key, |
642 | goto out; | 648 | &prefs_delayed); |
649 | if (ret) { | ||
650 | spin_unlock(&delayed_refs->lock); | ||
651 | goto out; | ||
652 | } | ||
643 | } | 653 | } |
654 | spin_unlock(&delayed_refs->lock); | ||
644 | } | 655 | } |
645 | spin_unlock(&delayed_refs->lock); | ||
646 | 656 | ||
647 | if (path->slots[0]) { | 657 | if (path->slots[0]) { |
648 | struct extent_buffer *leaf; | 658 | struct extent_buffer *leaf; |
@@ -679,7 +689,7 @@ again: | |||
679 | if (ret) | 689 | if (ret) |
680 | goto out; | 690 | goto out; |
681 | 691 | ||
682 | ret = __resolve_indirect_refs(fs_info, &prefs); | 692 | ret = __resolve_indirect_refs(fs_info, search_commit_root, &prefs); |
683 | if (ret) | 693 | if (ret) |
684 | goto out; | 694 | goto out; |
685 | 695 | ||
@@ -1074,8 +1084,7 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, | |||
1074 | return 0; | 1084 | return 0; |
1075 | } | 1085 | } |
1076 | 1086 | ||
1077 | static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, | 1087 | static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, u64 logical, |
1078 | struct btrfs_path *path, u64 logical, | ||
1079 | u64 orig_extent_item_objectid, | 1088 | u64 orig_extent_item_objectid, |
1080 | u64 extent_item_pos, u64 root, | 1089 | u64 extent_item_pos, u64 root, |
1081 | iterate_extent_inodes_t *iterate, void *ctx) | 1090 | iterate_extent_inodes_t *iterate, void *ctx) |
@@ -1143,35 +1152,38 @@ static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, | |||
1143 | * calls iterate() for every inode that references the extent identified by | 1152 | * calls iterate() for every inode that references the extent identified by |
1144 | * the given parameters. | 1153 | * the given parameters. |
1145 | * when the iterator function returns a non-zero value, iteration stops. | 1154 | * when the iterator function returns a non-zero value, iteration stops. |
1146 | * path is guaranteed to be in released state when iterate() is called. | ||
1147 | */ | 1155 | */ |
1148 | int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | 1156 | int iterate_extent_inodes(struct btrfs_fs_info *fs_info, |
1149 | struct btrfs_path *path, | ||
1150 | u64 extent_item_objectid, u64 extent_item_pos, | 1157 | u64 extent_item_objectid, u64 extent_item_pos, |
1158 | int search_commit_root, | ||
1151 | iterate_extent_inodes_t *iterate, void *ctx) | 1159 | iterate_extent_inodes_t *iterate, void *ctx) |
1152 | { | 1160 | { |
1153 | int ret; | 1161 | int ret; |
1154 | struct list_head data_refs = LIST_HEAD_INIT(data_refs); | 1162 | struct list_head data_refs = LIST_HEAD_INIT(data_refs); |
1155 | struct list_head shared_refs = LIST_HEAD_INIT(shared_refs); | 1163 | struct list_head shared_refs = LIST_HEAD_INIT(shared_refs); |
1156 | struct btrfs_trans_handle *trans; | 1164 | struct btrfs_trans_handle *trans; |
1157 | struct ulist *refs; | 1165 | struct ulist *refs = NULL; |
1158 | struct ulist *roots; | 1166 | struct ulist *roots = NULL; |
1159 | struct ulist_node *ref_node = NULL; | 1167 | struct ulist_node *ref_node = NULL; |
1160 | struct ulist_node *root_node = NULL; | 1168 | struct ulist_node *root_node = NULL; |
1161 | struct seq_list seq_elem; | 1169 | struct seq_list seq_elem; |
1162 | struct btrfs_delayed_ref_root *delayed_refs; | 1170 | struct btrfs_delayed_ref_root *delayed_refs = NULL; |
1163 | |||
1164 | trans = btrfs_join_transaction(fs_info->extent_root); | ||
1165 | if (IS_ERR(trans)) | ||
1166 | return PTR_ERR(trans); | ||
1167 | 1171 | ||
1168 | pr_debug("resolving all inodes for extent %llu\n", | 1172 | pr_debug("resolving all inodes for extent %llu\n", |
1169 | extent_item_objectid); | 1173 | extent_item_objectid); |
1170 | 1174 | ||
1171 | delayed_refs = &trans->transaction->delayed_refs; | 1175 | if (search_commit_root) { |
1172 | spin_lock(&delayed_refs->lock); | 1176 | trans = BTRFS_BACKREF_SEARCH_COMMIT_ROOT; |
1173 | btrfs_get_delayed_seq(delayed_refs, &seq_elem); | 1177 | } else { |
1174 | spin_unlock(&delayed_refs->lock); | 1178 | trans = btrfs_join_transaction(fs_info->extent_root); |
1179 | if (IS_ERR(trans)) | ||
1180 | return PTR_ERR(trans); | ||
1181 | |||
1182 | delayed_refs = &trans->transaction->delayed_refs; | ||
1183 | spin_lock(&delayed_refs->lock); | ||
1184 | btrfs_get_delayed_seq(delayed_refs, &seq_elem); | ||
1185 | spin_unlock(&delayed_refs->lock); | ||
1186 | } | ||
1175 | 1187 | ||
1176 | ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, | 1188 | ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, |
1177 | extent_item_pos, seq_elem.seq, | 1189 | extent_item_pos, seq_elem.seq, |
@@ -1188,7 +1200,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
1188 | while (!ret && (root_node = ulist_next(roots, root_node))) { | 1200 | while (!ret && (root_node = ulist_next(roots, root_node))) { |
1189 | pr_debug("root %llu references leaf %llu\n", | 1201 | pr_debug("root %llu references leaf %llu\n", |
1190 | root_node->val, ref_node->val); | 1202 | root_node->val, ref_node->val); |
1191 | ret = iterate_leaf_refs(fs_info, path, ref_node->val, | 1203 | ret = iterate_leaf_refs(fs_info, ref_node->val, |
1192 | extent_item_objectid, | 1204 | extent_item_objectid, |
1193 | extent_item_pos, root_node->val, | 1205 | extent_item_pos, root_node->val, |
1194 | iterate, ctx); | 1206 | iterate, ctx); |
@@ -1198,8 +1210,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
1198 | ulist_free(refs); | 1210 | ulist_free(refs); |
1199 | ulist_free(roots); | 1211 | ulist_free(roots); |
1200 | out: | 1212 | out: |
1201 | btrfs_put_delayed_seq(delayed_refs, &seq_elem); | 1213 | if (!search_commit_root) { |
1202 | btrfs_end_transaction(trans, fs_info->extent_root); | 1214 | btrfs_put_delayed_seq(delayed_refs, &seq_elem); |
1215 | btrfs_end_transaction(trans, fs_info->extent_root); | ||
1216 | } | ||
1217 | |||
1203 | return ret; | 1218 | return ret; |
1204 | } | 1219 | } |
1205 | 1220 | ||
@@ -1210,6 +1225,7 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, | |||
1210 | int ret; | 1225 | int ret; |
1211 | u64 extent_item_pos; | 1226 | u64 extent_item_pos; |
1212 | struct btrfs_key found_key; | 1227 | struct btrfs_key found_key; |
1228 | int search_commit_root = path->search_commit_root; | ||
1213 | 1229 | ||
1214 | ret = extent_from_logical(fs_info, logical, path, | 1230 | ret = extent_from_logical(fs_info, logical, path, |
1215 | &found_key); | 1231 | &found_key); |
@@ -1220,8 +1236,9 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, | |||
1220 | return ret; | 1236 | return ret; |
1221 | 1237 | ||
1222 | extent_item_pos = logical - found_key.objectid; | 1238 | extent_item_pos = logical - found_key.objectid; |
1223 | ret = iterate_extent_inodes(fs_info, path, found_key.objectid, | 1239 | ret = iterate_extent_inodes(fs_info, found_key.objectid, |
1224 | extent_item_pos, iterate, ctx); | 1240 | extent_item_pos, search_commit_root, |
1241 | iterate, ctx); | ||
1225 | 1242 | ||
1226 | return ret; | 1243 | return ret; |
1227 | } | 1244 | } |
@@ -1342,12 +1359,6 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) | |||
1342 | inode_to_path, ipath); | 1359 | inode_to_path, ipath); |
1343 | } | 1360 | } |
1344 | 1361 | ||
1345 | /* | ||
1346 | * allocates space to return multiple file system paths for an inode. | ||
1347 | * total_bytes to allocate are passed, note that space usable for actual path | ||
1348 | * information will be total_bytes - sizeof(struct inode_fs_paths). | ||
1349 | * the returned pointer must be freed with free_ipath() in the end. | ||
1350 | */ | ||
1351 | struct btrfs_data_container *init_data_container(u32 total_bytes) | 1362 | struct btrfs_data_container *init_data_container(u32 total_bytes) |
1352 | { | 1363 | { |
1353 | struct btrfs_data_container *data; | 1364 | struct btrfs_data_container *data; |
@@ -1403,5 +1414,6 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, | |||
1403 | 1414 | ||
1404 | void free_ipath(struct inode_fs_paths *ipath) | 1415 | void free_ipath(struct inode_fs_paths *ipath) |
1405 | { | 1416 | { |
1417 | kfree(ipath->fspath); | ||
1406 | kfree(ipath); | 1418 | kfree(ipath); |
1407 | } | 1419 | } |