diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 150 |
1 files changed, 128 insertions, 22 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 8ba3c9ebff93..c440c89a470a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -2956,7 +2956,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
2956 | struct extent_map_tree *em_tree = &map_tree->map_tree; | 2956 | struct extent_map_tree *em_tree = &map_tree->map_tree; |
2957 | u64 offset; | 2957 | u64 offset; |
2958 | u64 stripe_offset; | 2958 | u64 stripe_offset; |
2959 | u64 stripe_end_offset; | ||
2959 | u64 stripe_nr; | 2960 | u64 stripe_nr; |
2961 | u64 stripe_nr_orig; | ||
2962 | u64 stripe_nr_end; | ||
2960 | int stripes_allocated = 8; | 2963 | int stripes_allocated = 8; |
2961 | int stripes_required = 1; | 2964 | int stripes_required = 1; |
2962 | int stripe_index; | 2965 | int stripe_index; |
@@ -2965,7 +2968,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
2965 | int max_errors = 0; | 2968 | int max_errors = 0; |
2966 | struct btrfs_multi_bio *multi = NULL; | 2969 | struct btrfs_multi_bio *multi = NULL; |
2967 | 2970 | ||
2968 | if (multi_ret && !(rw & REQ_WRITE)) | 2971 | if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) |
2969 | stripes_allocated = 1; | 2972 | stripes_allocated = 1; |
2970 | again: | 2973 | again: |
2971 | if (multi_ret) { | 2974 | if (multi_ret) { |
@@ -3011,7 +3014,15 @@ again: | |||
3011 | max_errors = 1; | 3014 | max_errors = 1; |
3012 | } | 3015 | } |
3013 | } | 3016 | } |
3014 | if (multi_ret && (rw & REQ_WRITE) && | 3017 | if (rw & REQ_DISCARD) { |
3018 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | | ||
3019 | BTRFS_BLOCK_GROUP_RAID1 | | ||
3020 | BTRFS_BLOCK_GROUP_DUP | | ||
3021 | BTRFS_BLOCK_GROUP_RAID10)) { | ||
3022 | stripes_required = map->num_stripes; | ||
3023 | } | ||
3024 | } | ||
3025 | if (multi_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && | ||
3015 | stripes_allocated < stripes_required) { | 3026 | stripes_allocated < stripes_required) { |
3016 | stripes_allocated = map->num_stripes; | 3027 | stripes_allocated = map->num_stripes; |
3017 | free_extent_map(em); | 3028 | free_extent_map(em); |
@@ -3031,12 +3042,15 @@ again: | |||
3031 | /* stripe_offset is the offset of this block in its stripe*/ | 3042 | /* stripe_offset is the offset of this block in its stripe*/ |
3032 | stripe_offset = offset - stripe_offset; | 3043 | stripe_offset = offset - stripe_offset; |
3033 | 3044 | ||
3034 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | | 3045 | if (rw & REQ_DISCARD) |
3035 | BTRFS_BLOCK_GROUP_RAID10 | | 3046 | *length = min_t(u64, em->len - offset, *length); |
3036 | BTRFS_BLOCK_GROUP_DUP)) { | 3047 | else if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | |
3048 | BTRFS_BLOCK_GROUP_RAID1 | | ||
3049 | BTRFS_BLOCK_GROUP_RAID10 | | ||
3050 | BTRFS_BLOCK_GROUP_DUP)) { | ||
3037 | /* we limit the length of each bio to what fits in a stripe */ | 3051 | /* we limit the length of each bio to what fits in a stripe */ |
3038 | *length = min_t(u64, em->len - offset, | 3052 | *length = min_t(u64, em->len - offset, |
3039 | map->stripe_len - stripe_offset); | 3053 | map->stripe_len - stripe_offset); |
3040 | } else { | 3054 | } else { |
3041 | *length = em->len - offset; | 3055 | *length = em->len - offset; |
3042 | } | 3056 | } |
@@ -3046,8 +3060,19 @@ again: | |||
3046 | 3060 | ||
3047 | num_stripes = 1; | 3061 | num_stripes = 1; |
3048 | stripe_index = 0; | 3062 | stripe_index = 0; |
3049 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | 3063 | stripe_nr_orig = stripe_nr; |
3050 | if (unplug_page || (rw & REQ_WRITE)) | 3064 | stripe_nr_end = (offset + *length + map->stripe_len - 1) & |
3065 | (~(map->stripe_len - 1)); | ||
3066 | do_div(stripe_nr_end, map->stripe_len); | ||
3067 | stripe_end_offset = stripe_nr_end * map->stripe_len - | ||
3068 | (offset + *length); | ||
3069 | if (map->type & BTRFS_BLOCK_GROUP_RAID0) { | ||
3070 | if (rw & REQ_DISCARD) | ||
3071 | num_stripes = min_t(u64, map->num_stripes, | ||
3072 | stripe_nr_end - stripe_nr_orig); | ||
3073 | stripe_index = do_div(stripe_nr, map->num_stripes); | ||
3074 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | ||
3075 | if (unplug_page || (rw & (REQ_WRITE | REQ_DISCARD))) | ||
3051 | num_stripes = map->num_stripes; | 3076 | num_stripes = map->num_stripes; |
3052 | else if (mirror_num) | 3077 | else if (mirror_num) |
3053 | stripe_index = mirror_num - 1; | 3078 | stripe_index = mirror_num - 1; |
@@ -3058,7 +3083,7 @@ again: | |||
3058 | } | 3083 | } |
3059 | 3084 | ||
3060 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { | 3085 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { |
3061 | if (rw & REQ_WRITE) | 3086 | if (rw & (REQ_WRITE | REQ_DISCARD)) |
3062 | num_stripes = map->num_stripes; | 3087 | num_stripes = map->num_stripes; |
3063 | else if (mirror_num) | 3088 | else if (mirror_num) |
3064 | stripe_index = mirror_num - 1; | 3089 | stripe_index = mirror_num - 1; |
@@ -3071,6 +3096,10 @@ again: | |||
3071 | 3096 | ||
3072 | if (unplug_page || (rw & REQ_WRITE)) | 3097 | if (unplug_page || (rw & REQ_WRITE)) |
3073 | num_stripes = map->sub_stripes; | 3098 | num_stripes = map->sub_stripes; |
3099 | else if (rw & REQ_DISCARD) | ||
3100 | num_stripes = min_t(u64, map->sub_stripes * | ||
3101 | (stripe_nr_end - stripe_nr_orig), | ||
3102 | map->num_stripes); | ||
3074 | else if (mirror_num) | 3103 | else if (mirror_num) |
3075 | stripe_index += mirror_num - 1; | 3104 | stripe_index += mirror_num - 1; |
3076 | else { | 3105 | else { |
@@ -3088,24 +3117,101 @@ again: | |||
3088 | } | 3117 | } |
3089 | BUG_ON(stripe_index >= map->num_stripes); | 3118 | BUG_ON(stripe_index >= map->num_stripes); |
3090 | 3119 | ||
3091 | for (i = 0; i < num_stripes; i++) { | 3120 | if (rw & REQ_DISCARD) { |
3092 | if (unplug_page) { | 3121 | for (i = 0; i < num_stripes; i++) { |
3093 | struct btrfs_device *device; | ||
3094 | struct backing_dev_info *bdi; | ||
3095 | |||
3096 | device = map->stripes[stripe_index].dev; | ||
3097 | if (device->bdev) { | ||
3098 | bdi = blk_get_backing_dev_info(device->bdev); | ||
3099 | if (bdi->unplug_io_fn) | ||
3100 | bdi->unplug_io_fn(bdi, unplug_page); | ||
3101 | } | ||
3102 | } else { | ||
3103 | multi->stripes[i].physical = | 3122 | multi->stripes[i].physical = |
3104 | map->stripes[stripe_index].physical + | 3123 | map->stripes[stripe_index].physical + |
3105 | stripe_offset + stripe_nr * map->stripe_len; | 3124 | stripe_offset + stripe_nr * map->stripe_len; |
3106 | multi->stripes[i].dev = map->stripes[stripe_index].dev; | 3125 | multi->stripes[i].dev = map->stripes[stripe_index].dev; |
3126 | |||
3127 | if (map->type & BTRFS_BLOCK_GROUP_RAID0) { | ||
3128 | u64 stripes; | ||
3129 | int last_stripe = (stripe_nr_end - 1) % | ||
3130 | map->num_stripes; | ||
3131 | int j; | ||
3132 | |||
3133 | for (j = 0; j < map->num_stripes; j++) { | ||
3134 | if ((stripe_nr_end - 1 - j) % | ||
3135 | map->num_stripes == stripe_index) | ||
3136 | break; | ||
3137 | } | ||
3138 | stripes = stripe_nr_end - 1 - j; | ||
3139 | do_div(stripes, map->num_stripes); | ||
3140 | multi->stripes[i].length = map->stripe_len * | ||
3141 | (stripes - stripe_nr + 1); | ||
3142 | |||
3143 | if (i == 0) { | ||
3144 | multi->stripes[i].length -= | ||
3145 | stripe_offset; | ||
3146 | stripe_offset = 0; | ||
3147 | } | ||
3148 | if (stripe_index == last_stripe) | ||
3149 | multi->stripes[i].length -= | ||
3150 | stripe_end_offset; | ||
3151 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { | ||
3152 | u64 stripes; | ||
3153 | int j; | ||
3154 | int factor = map->num_stripes / | ||
3155 | map->sub_stripes; | ||
3156 | int last_stripe = (stripe_nr_end - 1) % factor; | ||
3157 | last_stripe *= map->sub_stripes; | ||
3158 | |||
3159 | for (j = 0; j < factor; j++) { | ||
3160 | if ((stripe_nr_end - 1 - j) % factor == | ||
3161 | stripe_index / map->sub_stripes) | ||
3162 | break; | ||
3163 | } | ||
3164 | stripes = stripe_nr_end - 1 - j; | ||
3165 | do_div(stripes, factor); | ||
3166 | multi->stripes[i].length = map->stripe_len * | ||
3167 | (stripes - stripe_nr + 1); | ||
3168 | |||
3169 | if (i < map->sub_stripes) { | ||
3170 | multi->stripes[i].length -= | ||
3171 | stripe_offset; | ||
3172 | if (i == map->sub_stripes - 1) | ||
3173 | stripe_offset = 0; | ||
3174 | } | ||
3175 | if (stripe_index >= last_stripe && | ||
3176 | stripe_index <= (last_stripe + | ||
3177 | map->sub_stripes - 1)) { | ||
3178 | multi->stripes[i].length -= | ||
3179 | stripe_end_offset; | ||
3180 | } | ||
3181 | } else | ||
3182 | multi->stripes[i].length = *length; | ||
3183 | |||
3184 | stripe_index++; | ||
3185 | if (stripe_index == map->num_stripes) { | ||
3186 | /* This could only happen for RAID0/10 */ | ||
3187 | stripe_index = 0; | ||
3188 | stripe_nr++; | ||
3189 | } | ||
3190 | } | ||
3191 | } else { | ||
3192 | for (i = 0; i < num_stripes; i++) { | ||
3193 | if (unplug_page) { | ||
3194 | struct btrfs_device *device; | ||
3195 | struct backing_dev_info *bdi; | ||
3196 | |||
3197 | device = map->stripes[stripe_index].dev; | ||
3198 | if (device->bdev) { | ||
3199 | bdi = blk_get_backing_dev_info(device-> | ||
3200 | bdev); | ||
3201 | if (bdi->unplug_io_fn) | ||
3202 | bdi->unplug_io_fn(bdi, | ||
3203 | unplug_page); | ||
3204 | } | ||
3205 | } else { | ||
3206 | multi->stripes[i].physical = | ||
3207 | map->stripes[stripe_index].physical + | ||
3208 | stripe_offset + | ||
3209 | stripe_nr * map->stripe_len; | ||
3210 | multi->stripes[i].dev = | ||
3211 | map->stripes[stripe_index].dev; | ||
3212 | } | ||
3213 | stripe_index++; | ||
3107 | } | 3214 | } |
3108 | stripe_index++; | ||
3109 | } | 3215 | } |
3110 | if (multi_ret) { | 3216 | if (multi_ret) { |
3111 | *multi_ret = multi; | 3217 | *multi_ret = multi; |