kfree(mpb);
}
-static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
+static int multipath_map (multipath_conf_t *conf)
{
- multipath_conf_t *conf = mddev_to_conf(mddev);
int i, disks = conf->raid_disks;
/*
for (i = 0; i < disks; i++) {
mdk_rdev_t *rdev = conf->multipaths[i].rdev;
if (rdev && rdev->in_sync) {
- *rdevp = rdev;
atomic_inc(&rdev->nr_pending);
spin_unlock_irq(&conf->device_lock);
- return 0;
+ return i;
}
}
spin_unlock_irq(&conf->device_lock);
* operation and are ready to return a success/failure code to the buffer
* cache layer.
*/
-static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate)
+static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err)
{
struct bio *bio = mp_bh->master_bio;
multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
- bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
+ bio_endio(bio, bio->bi_size, err);
mempool_free(mp_bh, conf->pool);
}
return 1;
if (uptodate)
- multipath_end_bh_io(mp_bh, uptodate);
- else {
+ multipath_end_bh_io(mp_bh, 0);
+ else if (!bio_rw_ahead(bio)) {
/*
* oops, IO error:
*/
bdevname(rdev->bdev,b),
(unsigned long long)bio->bi_sector);
multipath_reschedule_retry(mp_bh);
- }
- atomic_dec(&rdev->nr_pending);
- return 0;
-}
-
-/*
- * This routine returns the disk from which the requested read should
- * be done.
- */
-
-static int multipath_read_balance (multipath_conf_t *conf)
-{
- int disk;
-
- for (disk = 0; disk < conf->raid_disks; disk++) {
- mdk_rdev_t *rdev = conf->multipaths[disk].rdev;
- if (rdev && rdev->in_sync)
- return disk;
- }
- BUG();
+ } else
+ multipath_end_bh_io(mp_bh, error);
+ rdev_dec_pending(rdev, conf->mddev);
return 0;
}
{
multipath_conf_t *conf = mddev_to_conf(mddev);
int i;
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
for (i=0; i<mddev->raid_disks; i++) {
mdk_rdev_t *rdev = conf->multipaths[i].rdev;
if (rdev && !rdev->faulty) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+ atomic_inc(&rdev->nr_pending);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+
if (r_queue->unplug_fn)
r_queue->unplug_fn(r_queue);
+
+ spin_lock_irqsave(&conf->device_lock, flags);
+ atomic_dec(&rdev->nr_pending);
}
}
+ spin_unlock_irqrestore(&conf->device_lock, flags);
}
static void multipath_unplug(request_queue_t *q)
{
disk_stat_inc(mddev->gendisk, reads);
disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio));
}
- /*
- * read balancing logic:
- */
- spin_lock_irq(&conf->device_lock);
- mp_bh->path = multipath_read_balance(conf);
+
+ mp_bh->path = multipath_map(conf);
+ if (mp_bh->path < 0) {
+ bio_endio(bio, bio->bi_size, -EIO);
+ mempool_free(mp_bh, conf->pool);
+ return 0;
+ }
multipath = conf->multipaths + mp_bh->path;
- atomic_inc(&multipath->rdev->nr_pending);
- spin_unlock_irq(&conf->device_lock);
mp_bh->bio = *bio;
mp_bh->bio.bi_bdev = multipath->rdev->bdev;
seq_printf (seq, "]");
}
+static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
+ sector_t *error_sector)
+{
+ mddev_t *mddev = q->queuedata;
+ multipath_conf_t *conf = mddev_to_conf(mddev);
+ int i, ret = 0;
+
+ for (i=0; i<mddev->raid_disks; i++) {
+ mdk_rdev_t *rdev = conf->multipaths[i].rdev;
+ if (rdev && !rdev->faulty) {
+ struct block_device *bdev = rdev->bdev;
+ request_queue_t *r_queue = bdev_get_queue(bdev);
+
+ if (!r_queue->issue_flush_fn) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+ if (ret)
+ break;
+ }
+ }
+ return ret;
+}
/*
* Careful, this can execute in IRQ contexts as well!
*/
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
mddev->queue->max_sectors > (PAGE_SIZE>>9))
- mddev->queue->max_sectors = (PAGE_SIZE>>9);
+ blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
conf->working_disks++;
rdev->raid_disk = path;
struct multipath_bh *mp_bh;
struct bio *bio;
unsigned long flags;
- mdk_rdev_t *rdev;
+ multipath_conf_t *conf = mddev_to_conf(mddev);
md_check_recovery(mddev);
for (;;) {
bio = &mp_bh->bio;
bio->bi_sector = mp_bh->master_bio->bi_sector;
- rdev = NULL;
- if (multipath_map (mddev, &rdev)<0) {
+ if ((mp_bh->path = multipath_map (conf))<0) {
printk(KERN_ALERT "multipath: %s: unrecoverable IO read"
" error for block %llu\n",
bdevname(bio->bi_bdev,b),
(unsigned long long)bio->bi_sector);
- multipath_end_bh_io(mp_bh, 0);
+ multipath_end_bh_io(mp_bh, -EIO);
} else {
printk(KERN_ERR "multipath: %s: redirecting sector %llu"
" to another IO path\n",
bdevname(bio->bi_bdev,b),
(unsigned long long)bio->bi_sector);
- bio->bi_bdev = rdev->bdev;
+ *bio = *(mp_bh->master_bio);
+ bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev;
+ bio->bi_rw |= (1 << BIO_RW_FAILFAST);
+ bio->bi_end_io = multipath_end_request;
+ bio->bi_private = mp_bh;
generic_make_request(bio);
}
}
mddev->queue->unplug_fn = multipath_unplug;
+ mddev->queue->issue_flush_fn = multipath_issue_flush;
+
conf->working_disks = 0;
ITERATE_RDEV(mddev,rdev,tmp) {
disk_idx = rdev->raid_disk;
* a merge_bvec_fn to be involved in multipath */
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
mddev->queue->max_sectors > (PAGE_SIZE>>9))
- mddev->queue->max_sectors = (PAGE_SIZE>>9);
+ blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
if (!rdev->faulty)
conf->working_disks++;
multipath_conf_t *conf = mddev_to_conf(mddev);
md_unregister_thread(mddev->thread);
+ mddev->thread = NULL;
mempool_destroy(conf->pool);
kfree(conf->multipaths);
kfree(conf);