]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/md/raid5.c
Fail safely when trying to grow an array with a write-intent bitmap.
[karo-tx-linux.git] / drivers / md / raid5.c
index 46132fca3469172b32320adde338afcc867ac93f..17e0953c3c06b1d004cc608d8cfd4621f886b76e 100644 (file)
@@ -2507,7 +2507,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
  *
  */
 
-static void handle_stripe5(struct stripe_head *sh)
+static bool handle_stripe5(struct stripe_head *sh)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks, i;
@@ -2755,9 +2755,11 @@ static void handle_stripe5(struct stripe_head *sh)
        ops_run_io(sh, &s);
 
        return_io(return_bi);
+
+       return blocked_rdev == NULL;
 }
 
-static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
+static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
 {
        raid6_conf_t *conf = sh->raid_conf;
        int disks = sh->disks;
@@ -2968,14 +2970,17 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
        ops_run_io(sh, &s);
 
        return_io(return_bi);
+
+       return blocked_rdev == NULL;
 }
 
-static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
+/* returns true if the stripe was handled */
+static bool handle_stripe(struct stripe_head *sh, struct page *tmp_page)
 {
        if (sh->raid_conf->level == 6)
-               handle_stripe6(sh, tmp_page);
+               return handle_stripe6(sh, tmp_page);
        else
-               handle_stripe5(sh);
+               return handle_stripe5(sh);
 }
 
 
@@ -3074,15 +3079,17 @@ static int raid5_congested(void *data, int bits)
 /* We want read requests to align with chunks where possible,
  * but write requests don't need to.
  */
-static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
+static int raid5_mergeable_bvec(struct request_queue *q,
+                               struct bvec_merge_data *bvm,
+                               struct bio_vec *biovec)
 {
        mddev_t *mddev = q->queuedata;
-       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
        int max;
        unsigned int chunk_sectors = mddev->chunk_size >> 9;
-       unsigned int bio_sectors = bio->bi_size >> 9;
+       unsigned int bio_sectors = bvm->bi_size >> 9;
 
-       if (bio_data_dir(bio) == WRITE)
+       if ((bvm->bi_rw & 1) == WRITE)
                return biovec->bv_len; /* always allow writes to be mergeable */
 
        max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
@@ -3691,7 +3698,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        clear_bit(STRIPE_INSYNC, &sh->state);
        spin_unlock(&sh->lock);
 
-       handle_stripe(sh, NULL);
+       /* wait for any blocked device to be handled */
+       while(unlikely(!handle_stripe(sh, NULL)))
+               ;
        release_stripe(sh);
 
        return STRIPE_SECTORS;
@@ -4437,6 +4446,9 @@ static int raid5_check_reshape(mddev_t *mddev)
                return -EINVAL; /* Cannot shrink array or change level yet */
        if (mddev->delta_disks == 0)
                return 0; /* nothing to do */
+       if (mddev->bitmap)
+               /* Cannot grow a bitmap yet */
+               return -EBUSY;
 
        /* Can only proceed if there are plenty of stripe_heads.
         * We need a minimum of one full stripe,, and for sensible progress