diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/bitmap.c | 9 | ||||
-rw-r--r-- | drivers/md/dm-mpath.c | 68 | ||||
-rw-r--r-- | drivers/md/dm-raid1.c | 1 | ||||
-rw-r--r-- | drivers/md/dm-snap.c | 6 | ||||
-rw-r--r-- | drivers/md/dm-table.c | 1 | ||||
-rw-r--r-- | drivers/md/dm.c | 27 | ||||
-rw-r--r-- | drivers/md/md.c | 1 | ||||
-rw-r--r-- | drivers/md/raid0.c | 8 | ||||
-rw-r--r-- | drivers/md/raid1.c | 37 |
9 files changed, 92 insertions, 66 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 95980ad6b27..0c2ed99a383 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1345,7 +1345,8 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto } } -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks) +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, + int degraded) { bitmap_counter_t *bmc; int rv; @@ -1362,8 +1363,10 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks) rv = 1; else if (NEEDED(*bmc)) { rv = 1; - *bmc |= RESYNC_MASK; - *bmc &= ~NEEDED_MASK; + if (!degraded) { /* don't set/clear bits if degraded */ + *bmc |= RESYNC_MASK; + *bmc &= ~NEEDED_MASK; + } } } spin_unlock_irq(&bitmap->lock); diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 0c1b8520ef8..785806bdb24 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -63,6 +63,7 @@ struct multipath { unsigned nr_priority_groups; struct list_head priority_groups; unsigned pg_init_required; /* pg_init needs calling? */ + unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ unsigned nr_valid_paths; /* Total number of usable paths */ struct pgpath *current_pgpath; @@ -72,7 +73,7 @@ struct multipath { unsigned queue_io; /* Must we queue all I/O? */ unsigned queue_if_no_path; /* Queue I/O if last path fails? */ - unsigned suspended; /* Has dm core suspended our I/O? */ + unsigned saved_queue_if_no_path;/* Saved state during suspension */ struct work_struct process_queued_ios; struct bio_list queued_ios; @@ -304,11 +305,12 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, m->queue_size--; if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path && !m->suspended)) { + (!pgpath && m->queue_if_no_path)) { /* Queue for the daemon to resubmit */ bio_list_add(&m->queued_ios, bio); m->queue_size++; - if (m->pg_init_required || !m->queue_io) + if ((m->pg_init_required && !m->pg_init_in_progress) || + !m->queue_io) queue_work(kmultipathd, &m->process_queued_ios); pgpath = NULL; r = 0; @@ -333,8 +335,9 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) spin_lock_irqsave(&m->lock, flags); + m->saved_queue_if_no_path = m->queue_if_no_path; m->queue_if_no_path = queue_if_no_path; - if (!m->queue_if_no_path) + if (!m->queue_if_no_path && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); @@ -379,25 +382,31 @@ static void process_queued_ios(void *data) { struct multipath *m = (struct multipath *) data; struct hw_handler *hwh = &m->hw_handler; - struct pgpath *pgpath; - unsigned init_required, must_queue = 0; + struct pgpath *pgpath = NULL; + unsigned init_required = 0, must_queue = 1; unsigned long flags; spin_lock_irqsave(&m->lock, flags); + if (!m->queue_size) + goto out; + if (!m->current_pgpath) __choose_pgpath(m); pgpath = m->current_pgpath; - if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path && !m->suspended)) - must_queue = 1; + if ((pgpath && !m->queue_io) || + (!pgpath && !m->queue_if_no_path)) + must_queue = 0; - init_required = m->pg_init_required; - if (init_required) + if (m->pg_init_required && !m->pg_init_in_progress) { m->pg_init_required = 0; + m->pg_init_in_progress = 1; + init_required = 1; + } +out: spin_unlock_irqrestore(&m->lock, flags); if (init_required) @@ -752,6 +761,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, static void multipath_dtr(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; + + flush_workqueue(kmultipathd); free_multipath(m); } @@ -765,6 +776,9 @@ static int multipath_map(struct dm_target *ti, struct bio *bio, struct mpath_io *mpio; struct multipath *m = (struct multipath *) ti->private; + if (bio_barrier(bio)) + return -EOPNOTSUPP; + mpio = mempool_alloc(m->mpio_pool, GFP_NOIO); dm_bio_record(&mpio->details, bio); @@ -837,7 +851,7 @@ static int reinstate_path(struct pgpath *pgpath) pgpath->path.is_active = 1; m->current_pgpath = NULL; - if (!m->nr_valid_paths++) + if (!m->nr_valid_paths++ && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); queue_work(kmultipathd, &m->trigger_event); @@ -963,12 +977,13 @@ void dm_pg_init_complete(struct path *path, unsigned err_flags) bypass_pg(m, pg, 1); spin_lock_irqsave(&m->lock, flags); - if (!err_flags) - m->queue_io = 0; - else { + if (err_flags) { m->current_pgpath = NULL; m->current_pg = NULL; - } + } else if (!m->pg_init_required) + m->queue_io = 0; + + m->pg_init_in_progress = 0; queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); } @@ -988,9 +1003,12 @@ static int do_end_io(struct multipath *m, struct bio *bio, if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) return error; + if (error == -EOPNOTSUPP) + return error; + spin_lock(&m->lock); if (!m->nr_valid_paths) { - if (!m->queue_if_no_path || m->suspended) { + if (!m->queue_if_no_path) { spin_unlock(&m->lock); return -EIO; } else { @@ -1051,27 +1069,27 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio, /* * Suspend can't complete until all the I/O is processed so if - * the last path failed we will now error any queued I/O. + * the last path fails we must error any remaining I/O. + * Note that if the freeze_bdev fails while suspending, the + * queue_if_no_path state is lost - userspace should reset it. */ static void multipath_presuspend(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; - unsigned long flags; - spin_lock_irqsave(&m->lock, flags); - m->suspended = 1; - if (m->queue_if_no_path) - queue_work(kmultipathd, &m->process_queued_ios); - spin_unlock_irqrestore(&m->lock, flags); + queue_if_no_path(m, 0); } +/* + * Restore the queue_if_no_path setting. + */ static void multipath_resume(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; unsigned long flags; spin_lock_irqsave(&m->lock, flags); - m->suspended = 0; + m->queue_if_no_path = m->saved_queue_if_no_path; spin_unlock_irqrestore(&m->lock, flags); } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 6e3cf7e1345..12031c9d3f1 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1060,6 +1060,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ti->private = ms; + ti->split_io = ms->rh.region_size; r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); if (r) { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7e691ab9a74..ab54f99b7c3 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -777,7 +777,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, /* Full snapshots are not usable */ if (!s->valid) - return -1; + return -EIO; /* * Write to snapshot - higher level takes care of RW/RO @@ -931,6 +931,10 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) if (!snap->valid) continue; + /* Nothing to do if writing beyond end of snapshot */ + if (bio->bi_sector >= dm_table_get_size(snap->table)) + continue; + down_write(&snap->lock); /* diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 18e9b9953fc..a5a4c0ed8a1 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -943,6 +943,7 @@ EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); EXPORT_SYMBOL(dm_table_event); +EXPORT_SYMBOL(dm_table_get_size); EXPORT_SYMBOL(dm_table_get_mode); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f6b03957efc..54fabbf0667 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -384,7 +384,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, /* error the io and bail out */ struct dm_io *io = tio->io; free_tio(tio->io->md, tio); - dec_pending(io, -EIO); + dec_pending(io, r); bio_put(clone); } } @@ -966,23 +966,20 @@ static void __flush_deferred_io(struct mapped_device *md, struct bio *c) */ int dm_swap_table(struct mapped_device *md, struct dm_table *table) { - int r; + int r = -EINVAL; down_write(&md->lock); /* device must be suspended */ - if (!test_bit(DMF_SUSPENDED, &md->flags)) { - up_write(&md->lock); - return -EPERM; - } + if (!test_bit(DMF_SUSPENDED, &md->flags)) + goto out; __unbind(md); r = __bind(md, table); - if (r) - return r; +out: up_write(&md->lock); - return 0; + return r; } /* @@ -1055,14 +1052,17 @@ int dm_suspend(struct mapped_device *md) if (test_bit(DMF_BLOCK_IO, &md->flags)) goto out_read_unlock; - error = __lock_fs(md); - if (error) - goto out_read_unlock; - map = dm_get_table(md); if (map) + /* This does not get reverted if there's an error later. */ dm_table_presuspend_targets(map); + error = __lock_fs(md); + if (error) { + dm_table_put(map); + goto out_read_unlock; + } + up_read(&md->lock); /* @@ -1121,7 +1121,6 @@ int dm_suspend(struct mapped_device *md) return 0; out_unfreeze: - /* FIXME Undo dm_table_presuspend_targets */ __unlock_fs(md); clear_bit(DMF_BLOCK_IO, &md->flags); out_write_unlock: diff --git a/drivers/md/md.c b/drivers/md/md.c index 3802f7a17f1..4a0c57db2b6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -338,6 +338,7 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&rdev->mddev->pending_writes)) wake_up(&rdev->mddev->sb_wait); + bio_put(bio); return 0; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index e11dd14d0b4..2120710172c 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -314,16 +314,16 @@ static int raid0_run (mddev_t *mddev) sector_t space = conf->hash_spacing; int round; conf->preshift = 0; - if (sizeof(sector_t) > sizeof(unsigned long)) { + if (sizeof(sector_t) > sizeof(u32)) { /*shift down space and s so that sector_div will work */ - while (space > (sector_t) (~(unsigned long)0)) { + while (space > (sector_t) (~(u32)0)) { s >>= 1; space >>= 1; s += 1; /* force round-up */ conf->preshift++; } } - round = sector_div(s, (unsigned long)space) ? 1 : 0; + round = sector_div(s, (u32)space) ? 1 : 0; nb_zone = s + round; } printk("raid0 : nb_zone is %d.\n", nb_zone); @@ -443,7 +443,7 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) volatile #endif sector_t x = block >> conf->preshift; - sector_div(x, (unsigned long)conf->hash_spacing); + sector_div(x, (u32)conf->hash_spacing); zone = conf->hash_table[x]; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ff1dbec864a..5f253ee536b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1126,21 +1126,19 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i * only be one in raid1 resync. * We can find the current addess in mddev->curr_resync */ - if (!conf->fullsync) { - if (mddev->curr_resync < max_sector) - bitmap_end_sync(mddev->bitmap, - mddev->curr_resync, + if (mddev->curr_resync < max_sector) /* aborted */ + bitmap_end_sync(mddev->bitmap, mddev->curr_resync, &sync_blocks, 1); - bitmap_close_sync(mddev->bitmap); - } - if (mddev->curr_resync >= max_sector) + else /* completed sync */ conf->fullsync = 0; + + bitmap_close_sync(mddev->bitmap); close_sync(conf); return 0; } - if (!conf->fullsync && - !bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks)) { + if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, mddev->degraded) && + !conf->fullsync) { /* We can skip this block, and probably several more */ *skipped = 1; return sync_blocks; @@ -1243,15 +1241,15 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i len = (max_sector - sector_nr) << 9; if (len == 0) break; - if (!conf->fullsync) { - if (sync_blocks == 0) { - if (!bitmap_start_sync(mddev->bitmap, - sector_nr, &sync_blocks)) - break; - if (sync_blocks < (PAGE_SIZE>>9)) - BUG(); - if (len > (sync_blocks<<9)) len = sync_blocks<<9; - } + if (sync_blocks == 0) { + if (!bitmap_start_sync(mddev->bitmap, sector_nr, + &sync_blocks, mddev->degraded) && + !conf->fullsync) + break; + if (sync_blocks < (PAGE_SIZE>>9)) + BUG(); + if (len > (sync_blocks<<9)) + len = sync_blocks<<9; } for (i=0 ; i < conf->raid_disks; i++) { @@ -1264,7 +1262,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i while (i > 0) { i--; bio = r1_bio->bios[i]; - if (bio->bi_end_io==NULL) continue; + if (bio->bi_end_io==NULL) + continue; /* remove last page from this bio */ bio->bi_vcnt--; bio->bi_size -= len; |