|
@@ -306,6 +306,28 @@ static void raid1_end_read_request(struct bio *bio, int error)
|
|
|
rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
|
|
|
}
|
|
|
|
|
|
+static void r1_bio_write_done(r1bio_t *r1_bio, int vcnt, struct bio_vec *bv,
|
|
|
+ int behind)
|
|
|
+{
|
|
|
+ if (atomic_dec_and_test(&r1_bio->remaining))
|
|
|
+ {
|
|
|
+ /* it really is the end of this request */
|
|
|
+ if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
|
|
|
+ /* free extra copy of the data pages */
|
|
|
+ int i = vcnt;
|
|
|
+ while (i--)
|
|
|
+ safe_put_page(bv[i].bv_page);
|
|
|
+ }
|
|
|
+ /* clear the bitmap if all writes complete successfully */
|
|
|
+ bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
|
|
|
+ r1_bio->sectors,
|
|
|
+ !test_bit(R1BIO_Degraded, &r1_bio->state),
|
|
|
+ behind);
|
|
|
+ md_write_end(r1_bio->mddev);
|
|
|
+ raid_end_bio_io(r1_bio);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void raid1_end_write_request(struct bio *bio, int error)
|
|
|
{
|
|
|
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
|
|
@@ -373,21 +395,7 @@ static void raid1_end_write_request(struct bio *bio, int error)
|
|
|
* Let's see if all mirrored write operations have finished
|
|
|
* already.
|
|
|
*/
|
|
|
- if (atomic_dec_and_test(&r1_bio->remaining)) {
|
|
|
- if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
|
|
|
- /* free extra copy of the data pages */
|
|
|
- int i = bio->bi_vcnt;
|
|
|
- while (i--)
|
|
|
- safe_put_page(bio->bi_io_vec[i].bv_page);
|
|
|
- }
|
|
|
- /* clear the bitmap if all writes complete successfully */
|
|
|
- bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
|
|
|
- r1_bio->sectors,
|
|
|
- !test_bit(R1BIO_Degraded, &r1_bio->state),
|
|
|
- behind);
|
|
|
- md_write_end(r1_bio->mddev);
|
|
|
- raid_end_bio_io(r1_bio);
|
|
|
- }
|
|
|
+ r1_bio_write_done(r1_bio, bio->bi_vcnt, bio->bi_io_vec, behind);
|
|
|
|
|
|
if (to_put)
|
|
|
bio_put(to_put);
|
|
@@ -735,23 +743,26 @@ static void unfreeze_array(conf_t *conf)
|
|
|
}
|
|
|
|
|
|
|
|
|
-/* duplicate the data pages for behind I/O */
|
|
|
-static struct page **alloc_behind_pages(struct bio *bio)
|
|
|
+/* duplicate the data pages for behind I/O
|
|
|
+ * We return a list of bio_vec rather than just page pointers
|
|
|
+ * as it makes freeing easier
|
|
|
+ */
|
|
|
+static struct bio_vec *alloc_behind_pages(struct bio *bio)
|
|
|
{
|
|
|
int i;
|
|
|
struct bio_vec *bvec;
|
|
|
- struct page **pages = kzalloc(bio->bi_vcnt * sizeof(struct page *),
|
|
|
+ struct bio_vec *pages = kzalloc(bio->bi_vcnt * sizeof(struct bio_vec),
|
|
|
GFP_NOIO);
|
|
|
if (unlikely(!pages))
|
|
|
goto do_sync_io;
|
|
|
|
|
|
bio_for_each_segment(bvec, bio, i) {
|
|
|
- pages[i] = alloc_page(GFP_NOIO);
|
|
|
- if (unlikely(!pages[i]))
|
|
|
+ pages[i].bv_page = alloc_page(GFP_NOIO);
|
|
|
+ if (unlikely(!pages[i].bv_page))
|
|
|
goto do_sync_io;
|
|
|
- memcpy(kmap(pages[i]) + bvec->bv_offset,
|
|
|
+ memcpy(kmap(pages[i].bv_page) + bvec->bv_offset,
|
|
|
kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len);
|
|
|
- kunmap(pages[i]);
|
|
|
+ kunmap(pages[i].bv_page);
|
|
|
kunmap(bvec->bv_page);
|
|
|
}
|
|
|
|
|
@@ -759,8 +770,8 @@ static struct page **alloc_behind_pages(struct bio *bio)
|
|
|
|
|
|
do_sync_io:
|
|
|
if (pages)
|
|
|
- for (i = 0; i < bio->bi_vcnt && pages[i]; i++)
|
|
|
- put_page(pages[i]);
|
|
|
+ for (i = 0; i < bio->bi_vcnt && pages[i].bv_page; i++)
|
|
|
+ put_page(pages[i].bv_page);
|
|
|
kfree(pages);
|
|
|
PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size);
|
|
|
return NULL;
|
|
@@ -775,8 +786,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
|
|
|
int i, targets = 0, disks;
|
|
|
struct bitmap *bitmap;
|
|
|
unsigned long flags;
|
|
|
- struct bio_list bl;
|
|
|
- struct page **behind_pages = NULL;
|
|
|
+ struct bio_vec *behind_pages = NULL;
|
|
|
const int rw = bio_data_dir(bio);
|
|
|
const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
|
|
|
const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
|
|
@@ -873,13 +883,6 @@ static int make_request(mddev_t *mddev, struct bio * bio)
|
|
|
* bios[x] to bio
|
|
|
*/
|
|
|
disks = conf->raid_disks;
|
|
|
-#if 0
|
|
|
- { static int first=1;
|
|
|
- if (first) printk("First Write sector %llu disks %d\n",
|
|
|
- (unsigned long long)r1_bio->sector, disks);
|
|
|
- first = 0;
|
|
|
- }
|
|
|
-#endif
|
|
|
retry_write:
|
|
|
blocked_rdev = NULL;
|
|
|
rcu_read_lock();
|
|
@@ -937,10 +940,11 @@ static int make_request(mddev_t *mddev, struct bio * bio)
|
|
|
(behind_pages = alloc_behind_pages(bio)) != NULL)
|
|
|
set_bit(R1BIO_BehindIO, &r1_bio->state);
|
|
|
|
|
|
- atomic_set(&r1_bio->remaining, 0);
|
|
|
+ atomic_set(&r1_bio->remaining, 1);
|
|
|
atomic_set(&r1_bio->behind_remaining, 0);
|
|
|
|
|
|
- bio_list_init(&bl);
|
|
|
+ bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors,
|
|
|
+ test_bit(R1BIO_BehindIO, &r1_bio->state));
|
|
|
for (i = 0; i < disks; i++) {
|
|
|
struct bio *mbio;
|
|
|
if (!r1_bio->bios[i])
|
|
@@ -967,35 +971,25 @@ static int make_request(mddev_t *mddev, struct bio * bio)
|
|
|
* them all
|
|
|
*/
|
|
|
__bio_for_each_segment(bvec, mbio, j, 0)
|
|
|
- bvec->bv_page = behind_pages[j];
|
|
|
+ bvec->bv_page = behind_pages[j].bv_page;
|
|
|
if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags))
|
|
|
atomic_inc(&r1_bio->behind_remaining);
|
|
|
}
|
|
|
|
|
|
atomic_inc(&r1_bio->remaining);
|
|
|
-
|
|
|
- bio_list_add(&bl, mbio);
|
|
|
+ spin_lock_irqsave(&conf->device_lock, flags);
|
|
|
+ bio_list_add(&conf->pending_bio_list, mbio);
|
|
|
+ blk_plug_device(mddev->queue);
|
|
|
+ spin_unlock_irqrestore(&conf->device_lock, flags);
|
|
|
}
|
|
|
+ r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL);
|
|
|
kfree(behind_pages); /* the behind pages are attached to the bios now */
|
|
|
|
|
|
- bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors,
|
|
|
- test_bit(R1BIO_BehindIO, &r1_bio->state));
|
|
|
- spin_lock_irqsave(&conf->device_lock, flags);
|
|
|
- bio_list_merge(&conf->pending_bio_list, &bl);
|
|
|
- bio_list_init(&bl);
|
|
|
-
|
|
|
- blk_plug_device(mddev->queue);
|
|
|
- spin_unlock_irqrestore(&conf->device_lock, flags);
|
|
|
-
|
|
|
- /* In case raid1d snuck into freeze_array */
|
|
|
+ /* In case raid1d snuck in to freeze_array */
|
|
|
wake_up(&conf->wait_barrier);
|
|
|
|
|
|
if (do_sync)
|
|
|
md_wakeup_thread(mddev->thread);
|
|
|
-#if 0
|
|
|
- while ((bio = bio_list_pop(&bl)) != NULL)
|
|
|
- generic_make_request(bio);
|
|
|
-#endif
|
|
|
|
|
|
return 0;
|
|
|
}
|