X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmd%2Fdm-raid1.c;h=d12cf3e5e0763cfd9f3d8acb3771f8ee4197f283;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=abab265164731febe7abcb966f20d75548f2e272;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index abab26516..d12cf3e5e 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -67,7 +67,7 @@ static inline void wake(void) struct mirror_set; struct region_hash { struct mirror_set *ms; - sector_t region_size; + uint32_t region_size; unsigned region_shift; /* holds persistent region state */ @@ -122,20 +122,10 @@ static inline sector_t region_to_sector(struct region_hash *rh, region_t region) /* FIXME move this */ static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw); -static void *region_alloc(int gfp_mask, void *pool_data) -{ - return kmalloc(sizeof(struct region), gfp_mask); -} - -static void region_free(void *element, void *pool_data) -{ - kfree(element); -} - #define MIN_REGIONS 64 #define MAX_RECOVERY 1 static int rh_init(struct region_hash *rh, struct mirror_set *ms, - struct dirty_log *log, sector_t region_size, + struct dirty_log *log, uint32_t region_size, region_t nr_regions) { unsigned int nr_buckets, max_buckets; @@ -173,8 +163,8 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms, INIT_LIST_HEAD(&rh->quiesced_regions); INIT_LIST_HEAD(&rh->recovered_regions); - rh->region_pool = mempool_create(MIN_REGIONS, region_alloc, - region_free, NULL); + rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, + sizeof(struct region)); if (!rh->region_pool) { vfree(rh->buckets); rh->buckets = NULL; @@ -253,9 +243,9 @@ static struct region *__rh_alloc(struct region_hash *rh, region_t region) else { __rh_insert(rh, nreg); if (nreg->state == RH_CLEAN) { - spin_lock_irq(&rh->region_lock); + spin_lock(&rh->region_lock); list_add(&nreg->list, &rh->clean_regions); - spin_unlock_irq(&rh->region_lock); + spin_unlock(&rh->region_lock); } reg = nreg; } @@ -375,16 +365,20 @@ static void rh_inc(struct region_hash *rh, region_t region) read_lock(&rh->hash_lock); reg = __rh_find(rh, region); - if (reg->state == RH_CLEAN) { - rh->log->type->mark_region(rh->log, reg->key); - spin_lock_irq(&rh->region_lock); + spin_lock_irq(&rh->region_lock); + atomic_inc(®->pending); + + if (reg->state == RH_CLEAN) { reg->state = RH_DIRTY; list_del_init(®->list); /* take off the clean list */ spin_unlock_irq(&rh->region_lock); - } - atomic_inc(®->pending); + rh->log->type->mark_region(rh->log, reg->key); + } else + spin_unlock_irq(&rh->region_lock); + + read_unlock(&rh->hash_lock); } @@ -406,17 +400,29 @@ static void rh_dec(struct region_hash *rh, region_t region) reg = __rh_lookup(rh, region); read_unlock(&rh->hash_lock); + spin_lock_irqsave(&rh->region_lock, flags); if (atomic_dec_and_test(®->pending)) { - spin_lock_irqsave(&rh->region_lock, flags); + /* + * There is no pending I/O for this region. + * We can move the region to corresponding list for next action. + * At this point, the region is not yet connected to any list. + * + * If the state is RH_NOSYNC, the region should be kept off + * from clean list. + * The hash entry for RH_NOSYNC will remain in memory + * until the region is recovered or the map is reloaded. + */ + + /* do nothing for RH_NOSYNC */ if (reg->state == RH_RECOVERING) { list_add_tail(®->list, &rh->quiesced_regions); - } else { + } else if (reg->state == RH_DIRTY) { reg->state = RH_CLEAN; list_add(®->list, &rh->clean_regions); } - spin_unlock_irqrestore(&rh->region_lock, flags); should_wake = 1; } + spin_unlock_irqrestore(&rh->region_lock, flags); if (should_wake) wake(); @@ -558,6 +564,8 @@ struct mirror_set { region_t nr_regions; int in_sync; + struct mirror *default_mirror; /* Default mirror */ + unsigned int nr_mirrors; struct mirror mirror[0]; }; @@ -607,7 +615,7 @@ static int recover(struct mirror_set *ms, struct region *reg) unsigned long flags = 0; /* fill in the source */ - m = ms->mirror + DEFAULT_MIRROR; + m = ms->default_mirror; from.bdev = m->dev->bdev; from.sector = m->offset + region_to_sector(reg->rh, reg->key); if (reg->key == (ms->nr_regions - 1)) { @@ -623,7 +631,7 @@ static int recover(struct mirror_set *ms, struct region *reg) /* fill in the destinations */ for (i = 0, dest = to; i < ms->nr_mirrors; i++) { - if (i == DEFAULT_MIRROR) + if (&ms->mirror[i] == ms->default_mirror) continue; m = ms->mirror + i; @@ -678,7 +686,7 @@ static void do_recovery(struct mirror_set *ms) static struct mirror *choose_mirror(struct mirror_set *ms, sector_t sector) { /* FIXME: add read balancing */ - return ms->mirror + DEFAULT_MIRROR; + return ms->default_mirror; } /* @@ -705,7 +713,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) if (rh_in_sync(&ms->rh, region, 0)) m = choose_mirror(ms, bio->bi_sector); else - m = ms->mirror + DEFAULT_MIRROR; + m = ms->default_mirror; map_bio(ms, m, bio); generic_make_request(bio); @@ -829,7 +837,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) rh_delay(&ms->rh, bio); while ((bio = bio_list_pop(&nosync))) { - map_bio(ms, ms->mirror + DEFAULT_MIRROR, bio); + map_bio(ms, ms->default_mirror, bio); generic_make_request(bio); } } @@ -871,7 +879,7 @@ static void do_work(void *ignored) * Target functions *---------------------------------------------------------------*/ static struct mirror_set *alloc_context(unsigned int nr_mirrors, - sector_t region_size, + uint32_t region_size, struct dm_target *ti, struct dirty_log *dl) { @@ -894,8 +902,9 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, ms->ti = ti; ms->nr_mirrors = nr_mirrors; - ms->nr_regions = dm_div_up(ti->len, region_size); + ms->nr_regions = dm_sector_div_up(ti->len, region_size); ms->in_sync = 0; + ms->default_mirror = &ms->mirror[DEFAULT_MIRROR]; if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { ti->error = "dm-mirror: Error creating dirty region hash"; @@ -916,7 +925,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti, kfree(ms); } -static inline int _check_region_size(struct dm_target *ti, sector_t size) +static inline int _check_region_size(struct dm_target *ti, uint32_t size) { return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) || size > ti->len); @@ -925,9 +934,9 @@ static inline int _check_region_size(struct dm_target *ti, sector_t size) static int get_mirror(struct mirror_set *ms, struct dm_target *ti, unsigned int mirror, char **argv) { - sector_t offset; + unsigned long long offset; - if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) { + if (sscanf(argv[1], "%llu", &offset) != 1) { ti->error = "dm-mirror: Invalid offset"; return -EINVAL; } @@ -1060,6 +1069,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) { @@ -1158,10 +1168,11 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, return 0; } -static void mirror_suspend(struct dm_target *ti) +static void mirror_postsuspend(struct dm_target *ti) { struct mirror_set *ms = (struct mirror_set *) ti->private; struct dirty_log *log = ms->rh.log; + rh_stop_recovery(&ms->rh); if (log->type->suspend && log->type->suspend(log)) /* FIXME: need better error handling */ @@ -1181,7 +1192,6 @@ static void mirror_resume(struct dm_target *ti) static int mirror_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { - char buffer[32]; unsigned int m, sz; struct mirror_set *ms = (struct mirror_set *) ti->private; @@ -1190,23 +1200,20 @@ static int mirror_status(struct dm_target *ti, status_type_t type, switch (type) { case STATUSTYPE_INFO: DMEMIT("%d ", ms->nr_mirrors); - for (m = 0; m < ms->nr_mirrors; m++) { - format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); - DMEMIT("%s ", buffer); - } + for (m = 0; m < ms->nr_mirrors; m++) + DMEMIT("%s ", ms->mirror[m].dev->name); - DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, - ms->rh.log->type->get_sync_count(ms->rh.log), - ms->nr_regions); + DMEMIT("%llu/%llu", + (unsigned long long)ms->rh.log->type-> + get_sync_count(ms->rh.log), + (unsigned long long)ms->nr_regions); break; case STATUSTYPE_TABLE: DMEMIT("%d ", ms->nr_mirrors); - for (m = 0; m < ms->nr_mirrors; m++) { - format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); - DMEMIT("%s " SECTOR_FORMAT " ", - buffer, ms->mirror[m].offset); - } + for (m = 0; m < ms->nr_mirrors; m++) + DMEMIT("%s %llu ", ms->mirror[m].dev->name, + (unsigned long long)ms->mirror[m].offset); } return 0; @@ -1220,7 +1227,7 @@ static struct target_type mirror_target = { .dtr = mirror_dtr, .map = mirror_map, .end_io = mirror_end_io, - .suspend = mirror_suspend, + .postsuspend = mirror_postsuspend, .resume = mirror_resume, .status = mirror_status, }; @@ -1233,7 +1240,7 @@ static int __init dm_mirror_init(void) if (r) return r; - _kmirrord_wq = create_workqueue("kmirrord"); + _kmirrord_wq = create_singlethread_workqueue("kmirrord"); if (!_kmirrord_wq) { DMERR("couldn't start kmirrord"); dm_dirty_log_exit();