Commit fce3bb9a1bd492793170e117c60d5718b7896af4

Authored by Li Dongyang
Committed by root
1 parent b4d00d569a

Btrfs: make btrfs_map_block() return entire free extent for each device of RAID0/1/10/DUP

btrfs_map_block() will only return a single stripe length, but we want the
full extent be mapped to each disk when we are trimming the extent,
so we add length to btrfs_bio_stripe and fill it if we are mapping for REQ_DISCARD.

Signed-off-by: Li Dongyang <lidongyang@novell.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>

Showing 2 changed files with 129 additions and 22 deletions Side-by-side Diff

... ... @@ -2956,7 +2956,10 @@
2956 2956 struct extent_map_tree *em_tree = &map_tree->map_tree;
2957 2957 u64 offset;
2958 2958 u64 stripe_offset;
  2959 + u64 stripe_end_offset;
2959 2960 u64 stripe_nr;
  2961 + u64 stripe_nr_orig;
  2962 + u64 stripe_nr_end;
2960 2963 int stripes_allocated = 8;
2961 2964 int stripes_required = 1;
2962 2965 int stripe_index;
... ... @@ -2965,7 +2968,7 @@
2965 2968 int max_errors = 0;
2966 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 2972 stripes_allocated = 1;
2970 2973 again:
2971 2974 if (multi_ret) {
... ... @@ -3011,7 +3014,15 @@
3011 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 3026 stripes_allocated < stripes_required) {
3016 3027 stripes_allocated = map->num_stripes;
3017 3028 free_extent_map(em);
3018 3029  
... ... @@ -3031,12 +3042,15 @@
3031 3042 /* stripe_offset is the offset of this block in its stripe*/
3032 3043 stripe_offset = offset - stripe_offset;
3033 3044  
3034   - if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
3035   - BTRFS_BLOCK_GROUP_RAID10 |
3036   - BTRFS_BLOCK_GROUP_DUP)) {
  3045 + if (rw & REQ_DISCARD)
  3046 + *length = min_t(u64, em->len - offset, *length);
  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 3051 /* we limit the length of each bio to what fits in a stripe */
3038 3052 *length = min_t(u64, em->len - offset,
3039   - map->stripe_len - stripe_offset);
  3053 + map->stripe_len - stripe_offset);
3040 3054 } else {
3041 3055 *length = em->len - offset;
3042 3056 }
... ... @@ -3046,8 +3060,19 @@
3046 3060  
3047 3061 num_stripes = 1;
3048 3062 stripe_index = 0;
3049   - if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
3050   - if (unplug_page || (rw & REQ_WRITE))
  3063 + stripe_nr_orig = stripe_nr;
  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 3076 num_stripes = map->num_stripes;
3052 3077 else if (mirror_num)
3053 3078 stripe_index = mirror_num - 1;
... ... @@ -3058,7 +3083,7 @@
3058 3083 }
3059 3084  
3060 3085 } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
3061   - if (rw & REQ_WRITE)
  3086 + if (rw & (REQ_WRITE | REQ_DISCARD))
3062 3087 num_stripes = map->num_stripes;
3063 3088 else if (mirror_num)
3064 3089 stripe_index = mirror_num - 1;
... ... @@ -3071,6 +3096,10 @@
3071 3096  
3072 3097 if (unplug_page || (rw & REQ_WRITE))
3073 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 3103 else if (mirror_num)
3075 3104 stripe_index += mirror_num - 1;
3076 3105 else {
3077 3106  
3078 3107  
... ... @@ -3088,24 +3117,101 @@
3088 3117 }
3089 3118 BUG_ON(stripe_index >= map->num_stripes);
3090 3119  
3091   - for (i = 0; i < num_stripes; i++) {
3092   - if (unplug_page) {
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 {
  3120 + if (rw & REQ_DISCARD) {
  3121 + for (i = 0; i < num_stripes; i++) {
3103 3122 multi->stripes[i].physical =
3104 3123 map->stripes[stripe_index].physical +
3105 3124 stripe_offset + stripe_nr * map->stripe_len;
3106 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 + }
3107 3190 }
3108   - stripe_index++;
  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++;
  3214 + }
3109 3215 }
3110 3216 if (multi_ret) {
3111 3217 *multi_ret = multi;
... ... @@ -126,6 +126,7 @@
126 126 struct btrfs_bio_stripe {
127 127 struct btrfs_device *dev;
128 128 u64 physical;
  129 + u64 length; /* only used for discard mappings */
129 130 };
130 131  
131 132 struct btrfs_multi_bio {