diff options
| -rw-r--r-- | fs/btrfs/volumes.c | 150 | ||||
| -rw-r--r-- | fs/btrfs/volumes.h | 1 |
2 files changed, 129 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; |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 7b38d0668b51..cc2eadaf7a27 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
| @@ -126,6 +126,7 @@ struct btrfs_fs_devices { | |||
| 126 | struct btrfs_bio_stripe { | 126 | struct btrfs_bio_stripe { |
| 127 | struct btrfs_device *dev; | 127 | struct btrfs_device *dev; |
| 128 | u64 physical; | 128 | u64 physical; |
| 129 | u64 length; /* only used for discard mappings */ | ||
| 129 | }; | 130 | }; |
| 130 | 131 | ||
| 131 | struct btrfs_multi_bio { | 132 | struct btrfs_multi_bio { |
