aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/tree-log.c46
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;
2852again:
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];
2867next_slot: 2899next_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)