diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 57 |
1 files changed, 27 insertions, 30 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a4bbb854dfd2..c50271ad3157 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -799,12 +799,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
799 | struct inode *dir; | 799 | struct inode *dir; |
800 | int ret; | 800 | int ret; |
801 | struct btrfs_inode_ref *ref; | 801 | struct btrfs_inode_ref *ref; |
802 | struct btrfs_dir_item *di; | ||
803 | struct inode *inode; | 802 | struct inode *inode; |
804 | char *name; | 803 | char *name; |
805 | int namelen; | 804 | int namelen; |
806 | unsigned long ref_ptr; | 805 | unsigned long ref_ptr; |
807 | unsigned long ref_end; | 806 | unsigned long ref_end; |
807 | int search_done = 0; | ||
808 | 808 | ||
809 | /* | 809 | /* |
810 | * it is possible that we didn't log all the parent directories | 810 | * it is possible that we didn't log all the parent directories |
@@ -845,7 +845,10 @@ again: | |||
845 | * existing back reference, and we don't want to create | 845 | * existing back reference, and we don't want to create |
846 | * dangling pointers in the directory. | 846 | * dangling pointers in the directory. |
847 | */ | 847 | */ |
848 | conflict_again: | 848 | |
849 | if (search_done) | ||
850 | goto insert; | ||
851 | |||
849 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | 852 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); |
850 | if (ret == 0) { | 853 | if (ret == 0) { |
851 | char *victim_name; | 854 | char *victim_name; |
@@ -886,37 +889,21 @@ conflict_again: | |||
886 | ret = btrfs_unlink_inode(trans, root, dir, | 889 | ret = btrfs_unlink_inode(trans, root, dir, |
887 | inode, victim_name, | 890 | inode, victim_name, |
888 | victim_name_len); | 891 | victim_name_len); |
889 | kfree(victim_name); | ||
890 | btrfs_release_path(root, path); | ||
891 | goto conflict_again; | ||
892 | } | 892 | } |
893 | kfree(victim_name); | 893 | kfree(victim_name); |
894 | ptr = (unsigned long)(victim_ref + 1) + victim_name_len; | 894 | ptr = (unsigned long)(victim_ref + 1) + victim_name_len; |
895 | } | 895 | } |
896 | BUG_ON(ret); | 896 | BUG_ON(ret); |
897 | } | ||
898 | btrfs_release_path(root, path); | ||
899 | |||
900 | /* look for a conflicting sequence number */ | ||
901 | di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino, | ||
902 | btrfs_inode_ref_index(eb, ref), | ||
903 | name, namelen, 0); | ||
904 | if (di && !IS_ERR(di)) { | ||
905 | ret = drop_one_dir_item(trans, root, path, dir, di); | ||
906 | BUG_ON(ret); | ||
907 | } | ||
908 | btrfs_release_path(root, path); | ||
909 | 897 | ||
910 | 898 | /* | |
911 | /* look for a conflicting name */ | 899 | * NOTE: we have searched root tree and checked the |
912 | di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino, | 900 | * coresponding ref, it does not need to check again. |
913 | name, namelen, 0); | 901 | */ |
914 | if (di && !IS_ERR(di)) { | 902 | search_done = 1; |
915 | ret = drop_one_dir_item(trans, root, path, dir, di); | ||
916 | BUG_ON(ret); | ||
917 | } | 903 | } |
918 | btrfs_release_path(root, path); | 904 | btrfs_release_path(root, path); |
919 | 905 | ||
906 | insert: | ||
920 | /* insert our name */ | 907 | /* insert our name */ |
921 | ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, | 908 | ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, |
922 | btrfs_inode_ref_index(eb, ref)); | 909 | btrfs_inode_ref_index(eb, ref)); |
@@ -1286,6 +1273,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, | |||
1286 | ptr_end = ptr + item_size; | 1273 | ptr_end = ptr + item_size; |
1287 | while (ptr < ptr_end) { | 1274 | while (ptr < ptr_end) { |
1288 | di = (struct btrfs_dir_item *)ptr; | 1275 | di = (struct btrfs_dir_item *)ptr; |
1276 | if (verify_dir_item(root, eb, di)) | ||
1277 | return -EIO; | ||
1289 | name_len = btrfs_dir_name_len(eb, di); | 1278 | name_len = btrfs_dir_name_len(eb, di); |
1290 | ret = replay_one_name(trans, root, path, eb, di, key); | 1279 | ret = replay_one_name(trans, root, path, eb, di, key); |
1291 | BUG_ON(ret); | 1280 | BUG_ON(ret); |
@@ -1412,6 +1401,11 @@ again: | |||
1412 | ptr_end = ptr + item_size; | 1401 | ptr_end = ptr + item_size; |
1413 | while (ptr < ptr_end) { | 1402 | while (ptr < ptr_end) { |
1414 | di = (struct btrfs_dir_item *)ptr; | 1403 | di = (struct btrfs_dir_item *)ptr; |
1404 | if (verify_dir_item(root, eb, di)) { | ||
1405 | ret = -EIO; | ||
1406 | goto out; | ||
1407 | } | ||
1408 | |||
1415 | name_len = btrfs_dir_name_len(eb, di); | 1409 | name_len = btrfs_dir_name_len(eb, di); |
1416 | name = kmalloc(name_len, GFP_NOFS); | 1410 | name = kmalloc(name_len, GFP_NOFS); |
1417 | if (!name) { | 1411 | if (!name) { |
@@ -1821,7 +1815,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, | |||
1821 | int orig_level; | 1815 | int orig_level; |
1822 | 1816 | ||
1823 | path = btrfs_alloc_path(); | 1817 | path = btrfs_alloc_path(); |
1824 | BUG_ON(!path); | 1818 | if (!path) |
1819 | return -ENOMEM; | ||
1825 | 1820 | ||
1826 | level = btrfs_header_level(log->node); | 1821 | level = btrfs_header_level(log->node); |
1827 | orig_level = level; | 1822 | orig_level = level; |
@@ -3107,9 +3102,11 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
3107 | .stage = 0, | 3102 | .stage = 0, |
3108 | }; | 3103 | }; |
3109 | 3104 | ||
3110 | fs_info->log_root_recovering = 1; | ||
3111 | path = btrfs_alloc_path(); | 3105 | path = btrfs_alloc_path(); |
3112 | BUG_ON(!path); | 3106 | if (!path) |
3107 | return -ENOMEM; | ||
3108 | |||
3109 | fs_info->log_root_recovering = 1; | ||
3113 | 3110 | ||
3114 | trans = btrfs_start_transaction(fs_info->tree_root, 0); | 3111 | trans = btrfs_start_transaction(fs_info->tree_root, 0); |
3115 | BUG_ON(IS_ERR(trans)); | 3112 | BUG_ON(IS_ERR(trans)); |
@@ -3117,7 +3114,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
3117 | wc.trans = trans; | 3114 | wc.trans = trans; |
3118 | wc.pin = 1; | 3115 | wc.pin = 1; |
3119 | 3116 | ||
3120 | walk_log_tree(trans, log_root_tree, &wc); | 3117 | ret = walk_log_tree(trans, log_root_tree, &wc); |
3118 | BUG_ON(ret); | ||
3121 | 3119 | ||
3122 | again: | 3120 | again: |
3123 | key.objectid = BTRFS_TREE_LOG_OBJECTID; | 3121 | key.objectid = BTRFS_TREE_LOG_OBJECTID; |
@@ -3141,8 +3139,7 @@ again: | |||
3141 | 3139 | ||
3142 | log = btrfs_read_fs_root_no_radix(log_root_tree, | 3140 | log = btrfs_read_fs_root_no_radix(log_root_tree, |
3143 | &found_key); | 3141 | &found_key); |
3144 | BUG_ON(!log); | 3142 | BUG_ON(IS_ERR(log)); |
3145 | |||
3146 | 3143 | ||
3147 | tmp_key.objectid = found_key.offset; | 3144 | tmp_key.objectid = found_key.offset; |
3148 | tmp_key.type = BTRFS_ROOT_ITEM_KEY; | 3145 | tmp_key.type = BTRFS_ROOT_ITEM_KEY; |