diff options
-rw-r--r-- | fs/btrfs/tree-log.c | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ed1f7ce7219a..e0ef92f91d66 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2833,6 +2833,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
2833 | struct btrfs_file_extent_item *fi; | 2833 | struct btrfs_file_extent_item *fi; |
2834 | struct btrfs_key key; | 2834 | struct btrfs_key key; |
2835 | u64 start = em->mod_start; | 2835 | u64 start = em->mod_start; |
2836 | u64 search_start = start; | ||
2836 | u64 len = em->mod_len; | 2837 | u64 len = em->mod_len; |
2837 | u64 num_bytes; | 2838 | u64 num_bytes; |
2838 | int nritems; | 2839 | int nritems; |
@@ -2848,23 +2849,55 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
2848 | while (len) { | 2849 | while (len) { |
2849 | if (args->nr) | 2850 | if (args->nr) |
2850 | goto next_slot; | 2851 | goto next_slot; |
2852 | again: | ||
2851 | key.objectid = btrfs_ino(inode); | 2853 | key.objectid = btrfs_ino(inode); |
2852 | key.type = BTRFS_EXTENT_DATA_KEY; | 2854 | key.type = BTRFS_EXTENT_DATA_KEY; |
2853 | key.offset = start; | 2855 | key.offset = search_start; |
2854 | 2856 | ||
2855 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 2857 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
2856 | if (ret < 0) | 2858 | if (ret < 0) |
2857 | return ret; | 2859 | return ret; |
2860 | |||
2858 | if (ret) { | 2861 | if (ret) { |
2859 | /* | 2862 | /* |
2860 | * This shouldn't happen, but it might so warn and | 2863 | * A rare case were we can have an em for a section of a |
2861 | * return an error. | 2864 | * larger extent so we need to make sure that this em |
2865 | * falls within the extent we've found. If not we just | ||
2866 | * bail and go back to ye-olde way of doing things but | ||
2867 | * it happens often enough in testing that we need to do | ||
2868 | * this dance to make sure. | ||
2862 | */ | 2869 | */ |
2863 | WARN_ON(1); | 2870 | do { |
2864 | return -ENOENT; | 2871 | if (path->slots[0] == 0) { |
2872 | btrfs_release_path(path); | ||
2873 | if (search_start == 0) | ||
2874 | return -ENOENT; | ||
2875 | search_start--; | ||
2876 | goto again; | ||
2877 | } | ||
2878 | |||
2879 | path->slots[0]--; | ||
2880 | btrfs_item_key_to_cpu(path->nodes[0], &key, | ||
2881 | path->slots[0]); | ||
2882 | if (key.objectid != btrfs_ino(inode) || | ||
2883 | key.type != BTRFS_EXTENT_DATA_KEY) { | ||
2884 | btrfs_release_path(path); | ||
2885 | return -ENOENT; | ||
2886 | } | ||
2887 | } while (key.offset > start); | ||
2888 | |||
2889 | fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
2890 | struct btrfs_file_extent_item); | ||
2891 | num_bytes = btrfs_file_extent_num_bytes(path->nodes[0], | ||
2892 | fi); | ||
2893 | if (key.offset + num_bytes <= start) { | ||
2894 | btrfs_release_path(path); | ||
2895 | return -ENOENT; | ||
2896 | } | ||
2865 | } | 2897 | } |
2866 | args->src = path->nodes[0]; | 2898 | args->src = path->nodes[0]; |
2867 | next_slot: | 2899 | next_slot: |
2900 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
2868 | fi = btrfs_item_ptr(args->src, path->slots[0], | 2901 | fi = btrfs_item_ptr(args->src, path->slots[0], |
2869 | struct btrfs_file_extent_item); | 2902 | struct btrfs_file_extent_item); |
2870 | if (args->nr && | 2903 | if (args->nr && |
@@ -2898,8 +2931,9 @@ next_slot: | |||
2898 | } else { | 2931 | } else { |
2899 | len -= num_bytes; | 2932 | len -= num_bytes; |
2900 | } | 2933 | } |
2901 | start += btrfs_file_extent_num_bytes(args->src, fi); | 2934 | start = key.offset + num_bytes; |
2902 | args->next_offset = start; | 2935 | args->next_offset = start; |
2936 | search_start = start; | ||
2903 | 2937 | ||
2904 | if (path->slots[0] < nritems) { | 2938 | if (path->slots[0] < nritems) { |
2905 | if (len) | 2939 | if (len) |