| @@ -467,6 +467,15 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, · 466 unmodified lines |
| 467 | 467 | return 0; |
| 468 | 468 | } |
| 469 | 469 | |
| 470 | +/* |
| 471 | + * This allocates memory and gets a tree modification sequence number when |
| 472 | + * needed. |
| 473 | + * |
| 474 | + * Returns 0 when no sequence number is needed, < 0 on error. |
| 475 | + * Returns 1 when a sequence number was added. In this case, |
| 476 | + * fs_info->tree_mod_seq_lock was acquired and must be released by the caller |
| 477 | + * after inserting into the rb tree. |
| 478 | + */ |
| 470 | 479 | static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, |
| 471 | 480 | struct tree_mod_elem **tm_ret) |
| 472 | 481 | { |
| @@ -491,11 +500,11 @@ static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, · 18 unmodified lines |
| 491 | 500 | */ |
| 492 | 501 | kfree(tm); |
| 493 | 502 | seq = 0; |
| 503 | + spin_unlock(&fs_info->tree_mod_seq_lock); |
| 494 | 504 | } else { |
| 495 | 505 | __get_tree_mod_seq(fs_info, &tm->elem); |
| 496 | 506 | seq = tm->elem.seq; |
| 497 | 507 | } |
| 498 | | − spin_unlock(&fs_info->tree_mod_seq_lock); |
| 499 | 508 | |
| 500 | 509 | return seq; |
| 501 | 510 | } |
| @@ -521,7 +530,9 @@ tree_mod_log_insert_key_mask(struct btrfs_fs_info *fs_info, · 19 unmodified lines |
| 521 | 530 | tm->slot = slot; |
| 522 | 531 | tm->generation = btrfs_node_ptr_generation(eb, slot); |
| 523 | 532 | |
| 524 | | − return __tree_mod_log_insert(fs_info, tm); |
| 533 | + ret = __tree_mod_log_insert(fs_info, tm); |
| 534 | + spin_unlock(&fs_info->tree_mod_seq_lock); |
| 535 | + return ret; |
| 525 | 536 | } |
| 526 | 537 | |
| 527 | 538 | static noinline int |
| @@ -559,7 +570,9 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, · 31 unmodified lines |
| 559 | 570 | tm->move.nr_items = nr_items; |
| 560 | 571 | tm->op = MOD_LOG_MOVE_KEYS; |
| 561 | 572 | |
| 562 | | − return __tree_mod_log_insert(fs_info, tm); |
| 573 | + ret = __tree_mod_log_insert(fs_info, tm); |
| 574 | + spin_unlock(&fs_info->tree_mod_seq_lock); |
| 575 | + return ret; |
| 563 | 576 | } |
| 564 | 577 | |
| 565 | 578 | static noinline int |
| @@ -580,7 +593,9 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, · 14 unmodified lines |
| 580 | 593 | tm->generation = btrfs_header_generation(old_root); |
| 581 | 594 | tm->op = MOD_LOG_ROOT_REPLACE; |
| 582 | 595 | |
| 583 | | − return __tree_mod_log_insert(fs_info, tm); |
| 596 | + ret = __tree_mod_log_insert(fs_info, tm); |
| 597 | + spin_unlock(&fs_info->tree_mod_seq_lock); |
| 598 | + return ret; |
| 584 | 599 | } |
| 585 | 600 | |
| 586 | 601 | static struct tree_mod_elem * |
| @@ -1023,6 +1038,10 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, · 436 unmodified lines |
| 1023 | 1038 | looped = 1; |
| 1024 | 1039 | } |
| 1025 | 1040 | |
| 1041 | + /* if there's no old root to return, return what we found instead */ |
| 1042 | + if (!found) |
| 1043 | + found = tm; |
| 1044 | + |
| 1026 | 1045 | return found; |
| 1027 | 1046 | } |
| 1028 | 1047 | |
| @@ -1143,22 +1162,36 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, · 114 unmodified lines |
| 1143 | 1162 | return eb_rewin; |
| 1144 | 1163 | } |
| 1145 | 1164 | |
| 1165 | +/* |
| 1166 | + * get_old_root() rewinds the state of @root's root node to the given @time_seq |
| 1167 | + * value. If there are no changes, the current root->root_node is returned. If |
| 1168 | + * anything changed in between, there's a fresh buffer allocated on which the |
| 1169 | + * rewind operations are done. In any case, the returned buffer is read locked. |
| 1170 | + * Returns NULL on error (with no locks held). |
| 1171 | + */ |
| 1146 | 1172 | static inline struct extent_buffer * |
| 1147 | 1173 | get_old_root(struct btrfs_root *root, u64 time_seq) |
| 1148 | 1174 | { |
| 1149 | 1175 | struct tree_mod_elem *tm; |
| 1150 | 1176 | struct extent_buffer *eb; |
| 1151 | | − struct tree_mod_root *old_root; |
| 1177 | + struct tree_mod_root *old_root = NULL; |
| 1152 | 1178 | u64 old_generation; |
| 1179 | + u64 logical; |
| 1153 | 1180 | |
| 1181 | + eb = btrfs_read_lock_root_node(root); |
| 1154 | 1182 | tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); |
| 1155 | 1183 | if (!tm) |
| 1156 | 1184 | return root->node; |
| 1157 | 1185 | |
| 1158 | | − old_root = &tm->old_root; |
| 1159 | | − old_generation = tm->generation; |
| 1186 | + if (tm->op == MOD_LOG_ROOT_REPLACE) { |
| 1187 | + old_root = &tm->old_root; |
| 1188 | + old_generation = tm->generation; |
| 1189 | + logical = old_root->logical; |
| 1190 | + } else { |
| 1191 | + logical = root->node->start; |
| 1192 | + } |
| 1160 | 1193 | |
| 1161 | | − tm = tree_mod_log_search(root->fs_info, old_root->logical, time_seq); |
| 1194 | + tm = tree_mod_log_search(root->fs_info, logical, time_seq); |
| 1162 | 1195 | /* |
| 1163 | 1196 | * there was an item in the log when __tree_mod_log_oldest_root |
| 1164 | 1197 | * returned. this one must not go away, because the time_seq passed to |
| @@ -1166,22 +1199,25 @@ get_old_root(struct btrfs_root *root, u64 time_seq) · 1 unmodified line |
| 1166 | 1199 | */ |
| 1167 | 1200 | BUG_ON(!tm); |
| 1168 | 1201 | |
| 1169 | | − if (old_root->logical == root->node->start) { |
| 1170 | | − /* there are logged operations for the current root */ |
| 1171 | | − eb = btrfs_clone_extent_buffer(root->node); |
| 1172 | | − } else { |
| 1173 | | − /* there's a root replace operation for the current root */ |
| 1202 | + if (old_root) |
| 1174 | 1203 | eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, |
| 1175 | 1204 | root->nodesize); |
| 1205 | + else |
| 1206 | + eb = btrfs_clone_extent_buffer(root->node); |
| 1207 | + btrfs_tree_read_unlock(root->node); |
| 1208 | + free_extent_buffer(root->node); |
| 1209 | + if (!eb) |
| 1210 | + return NULL; |
| 1211 | + btrfs_tree_read_lock(eb); |
| 1212 | + if (old_root) { |
| 1176 | 1213 | btrfs_set_header_bytenr(eb, eb->start); |
| 1177 | 1214 | btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); |
| 1178 | 1215 | btrfs_set_header_owner(eb, root->root_key.objectid); |
| 1216 | + btrfs_set_header_level(eb, old_root->level); |
| 1217 | + btrfs_set_header_generation(eb, old_generation); |
| 1179 | 1218 | } |
| 1180 | | − if (!eb) |
| 1181 | | − return NULL; |
| 1182 | | − btrfs_set_header_level(eb, old_root->level); |
| 1183 | | − btrfs_set_header_generation(eb, old_generation); |
| 1184 | 1219 | __tree_mod_log_rewind(eb, time_seq, tm); |
| 1220 | + extent_buffer_get(eb); |
| 1185 | 1221 | |
| 1186 | 1222 | return eb; |
| 1187 | 1223 | } |
| @@ -1650,8 +1686,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, · 462 unmodified lines |
| 1650 | 1686 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) |
| 1651 | 1687 | return 0; |
| 1652 | 1688 | |
| 1653 | | − btrfs_header_nritems(mid); |
| 1654 | | − |
| 1655 | 1689 | left = read_node_slot(root, parent, pslot - 1); |
| 1656 | 1690 | if (left) { |
| 1657 | 1691 | btrfs_tree_lock(left); |
| @@ -1681,7 +1715,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, · 23 unmodified lines |
| 1681 | 1715 | wret = push_node_left(trans, root, left, mid, 1); |
| 1682 | 1716 | if (wret < 0) |
| 1683 | 1717 | ret = wret; |
| 1684 | | − btrfs_header_nritems(mid); |
| 1685 | 1718 | } |
| 1686 | 1719 | |
| 1687 | 1720 | /* |
| @@ -2615,9 +2648,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key, · 927 unmodified lines |
| 2615 | 2648 | |
| 2616 | 2649 | again: |
| 2617 | 2650 | b = get_old_root(root, time_seq); |
| 2618 | | − extent_buffer_get(b); |
| 2619 | 2651 | level = btrfs_header_level(b); |
| 2620 | | − btrfs_tree_read_lock(b); |
| 2621 | 2652 | p->locks[level] = BTRFS_READ_LOCK; |
| 2622 | 2653 | |
| 2623 | 2654 | while (b) { |
| @@ -5000,6 +5031,12 @@ next: · 2376 unmodified lines |
| 5000 | 5031 | * returns < 0 on io errors. |
| 5001 | 5032 | */ |
| 5002 | 5033 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) |
| 5034 | +{ |
| 5035 | + return btrfs_next_old_leaf(root, path, 0); |
| 5036 | +} |
| 5037 | + |
| 5038 | +int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, |
| 5039 | + u64 time_seq) |
| 5003 | 5040 | { |
| 5004 | 5041 | int slot; |
| 5005 | 5042 | int level; |
| @@ -5025,7 +5062,10 @@ again: · 19 unmodified lines |
| 5025 | 5062 | path->keep_locks = 1; |
| 5026 | 5063 | path->leave_spinning = 1; |
| 5027 | 5064 | |
| 5028 | | − ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
| 5065 | + if (time_seq) |
| 5066 | + ret = btrfs_search_old_slot(root, &key, path, time_seq); |
| 5067 | + else |
| 5068 | + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
| 5029 | 5069 | path->keep_locks = 0; |
| 5030 | 5070 | |
| 5031 | 5071 | if (ret < 0) |