raid1.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,426 行 · 第 1/3 页
C
1,426 行
bio->bi_rw = READ; unplug = 1; generic_make_request(bio); } } } spin_unlock_irqrestore(&retry_list_lock, flags); if (unplug) unplug_slaves(mddev);}static int init_resync(conf_t *conf){ int buffs; buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; if (conf->r1buf_pool) BUG(); conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, conf->poolinfo); if (!conf->r1buf_pool) return -ENOMEM; conf->next_resync = 0; return 0;}/* * perform a "sync" on one "block" * * We need to make sure that no normal I/O request - particularly write * requests - conflict with active sync requests. * * This is achieved by tracking pending requests and a 'barrier' concept * that can be installed to exclude normal IO requests. */static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster){ conf_t *conf = mddev_to_conf(mddev); mirror_info_t *mirror; r1bio_t *r1_bio; struct bio *bio; sector_t max_sector, nr_sectors; int disk; int i; int write_targets = 0; if (!conf->r1buf_pool) if (init_resync(conf)) return -ENOMEM; max_sector = mddev->size << 1; if (sector_nr >= max_sector) { close_sync(conf); return 0; } /* * If there is non-resync activity waiting for us then * put in a delay to throttle resync. */ if (!go_faster && waitqueue_active(&conf->wait_resume)) schedule_timeout(HZ); device_barrier(conf, sector_nr + RESYNC_SECTORS); /* * If reconstructing, and >1 working disc, * could dedicate one to rebuild and others to * service read requests .. */ disk = conf->last_used; /* make sure disk is operational */ spin_lock_irq(&conf->device_lock); while (conf->mirrors[disk].rdev == NULL || !conf->mirrors[disk].rdev->in_sync) { if (disk <= 0) disk = conf->raid_disks; disk--; if (disk == conf->last_used) break; } conf->last_used = disk; atomic_inc(&conf->mirrors[disk].rdev->nr_pending); spin_unlock_irq(&conf->device_lock); mirror = conf->mirrors + disk; r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); spin_lock_irq(&conf->resync_lock); conf->nr_pending++; spin_unlock_irq(&conf->resync_lock); r1_bio->mddev = mddev; r1_bio->sector = sector_nr; set_bit(R1BIO_IsSync, &r1_bio->state); r1_bio->read_disk = disk; for (i=0; i < conf->raid_disks; i++) { bio = r1_bio->bios[i]; /* take from bio_init */ bio->bi_next = NULL; bio->bi_flags |= 1 << BIO_UPTODATE; bio->bi_rw = 0; bio->bi_vcnt = 0; bio->bi_idx = 0; bio->bi_phys_segments = 0; bio->bi_hw_segments = 0; bio->bi_size = 0; bio->bi_end_io = NULL; bio->bi_private = NULL; if (i == disk) { bio->bi_rw = READ; bio->bi_end_io = end_sync_read; } else if (conf->mirrors[i].rdev && !conf->mirrors[i].rdev->faulty && (!conf->mirrors[i].rdev->in_sync || sector_nr + RESYNC_SECTORS > mddev->recovery_cp)) { bio->bi_rw = WRITE; bio->bi_end_io = end_sync_write; write_targets ++; } else continue; bio->bi_sector = sector_nr + conf->mirrors[i].rdev->data_offset; bio->bi_bdev = conf->mirrors[i].rdev->bdev; bio->bi_private = r1_bio; } if (write_targets == 0) { /* There is nowhere to write, so all non-sync * drives must be failed - so we are finished */ int rv = max_sector - sector_nr; md_done_sync(mddev, rv, 1); put_buf(r1_bio); atomic_dec(&conf->mirrors[disk].rdev->nr_pending); return rv; } nr_sectors = 0; do { struct page *page; int len = PAGE_SIZE; if (sector_nr + (len>>9) > max_sector) len = (max_sector - sector_nr) << 9; if (len == 0) break; for (i=0 ; i < conf->raid_disks; i++) { bio = r1_bio->bios[i]; if (bio->bi_end_io) { page = r1_bio->bios[0]->bi_io_vec[bio->bi_vcnt].bv_page; if (bio_add_page(bio, page, len, 0) == 0) { /* stop here */ r1_bio->bios[0]->bi_io_vec[bio->bi_vcnt].bv_page = page; while (i > 0) { i--; bio = r1_bio->bios[i]; if (bio->bi_end_io==NULL) continue; /* remove last page from this bio */ bio->bi_vcnt--; bio->bi_size -= len; bio->bi_flags &= ~(1<< BIO_SEG_VALID); } goto bio_full; } } } nr_sectors += len>>9; sector_nr += len>>9; } while (r1_bio->bios[disk]->bi_vcnt < RESYNC_PAGES); bio_full: bio = r1_bio->bios[disk]; r1_bio->sectors = nr_sectors; md_sync_acct(mirror->rdev->bdev, nr_sectors); generic_make_request(bio); return nr_sectors;}static int run(mddev_t *mddev){ conf_t *conf; int i, j, disk_idx; mirror_info_t *disk; mdk_rdev_t *rdev; struct list_head *tmp; if (mddev->level != 1) { printk("raid1: %s: raid level not set to mirroring (%d)\n", mdname(mddev), mddev->level); goto out; } /* * copy the already verified devices into our private RAID1 * bookkeeping area. [whatever we allocate in run(), * should be freed in stop()] */ conf = kmalloc(sizeof(conf_t), GFP_KERNEL); mddev->private = conf; if (!conf) goto out_no_mem; memset(conf, 0, sizeof(*conf)); conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks, GFP_KERNEL); if (!conf->mirrors) goto out_no_mem; memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks); conf->poolinfo = kmalloc(sizeof(*conf->poolinfo), GFP_KERNEL); if (!conf->poolinfo) goto out_no_mem; conf->poolinfo->mddev = mddev; conf->poolinfo->raid_disks = mddev->raid_disks; conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, r1bio_pool_free, conf->poolinfo); if (!conf->r1bio_pool) goto out_no_mem; mddev->queue->unplug_fn = raid1_unplug; mddev->queue->issue_flush_fn = raid1_issue_flush; ITERATE_RDEV(mddev, rdev, tmp) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) continue; disk = conf->mirrors + disk_idx; disk->rdev = rdev; blk_queue_stack_limits(mddev->queue, rdev->bdev->bd_disk->queue); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && mddev->queue->max_sectors > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; if (!rdev->faulty && rdev->in_sync) conf->working_disks++; } conf->raid_disks = mddev->raid_disks; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; if (conf->working_disks == 1) mddev->recovery_cp = MaxSector; conf->resync_lock = SPIN_LOCK_UNLOCKED; init_waitqueue_head(&conf->wait_idle); init_waitqueue_head(&conf->wait_resume); if (!conf->working_disks) { printk(KERN_ERR "raid1: no operational mirrors for %s\n", mdname(mddev)); goto out_free_conf; } mddev->degraded = 0; for (i = 0; i < conf->raid_disks; i++) { disk = conf->mirrors + i; if (!disk->rdev) { disk->head_position = 0; mddev->degraded++; } } /* * find the first working one and use it as a starting point * to read balancing. */ for (j = 0; j < conf->raid_disks && (!conf->mirrors[j].rdev || !conf->mirrors[j].rdev->in_sync) ; j++) /* nothing */; conf->last_used = j; { mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1"); if (!mddev->thread) { printk(KERN_ERR "raid1: couldn't allocate thread for %s\n", mdname(mddev)); goto out_free_conf; } } printk(KERN_INFO "raid1: raid set %s active with %d out of %d mirrors\n", mdname(mddev), mddev->raid_disks - mddev->degraded, mddev->raid_disks); /* * Ok, everything is just fine now */ mddev->array_size = mddev->size; return 0;out_no_mem: printk(KERN_ERR "raid1: couldn't allocate memory for %s\n", mdname(mddev));out_free_conf: if (conf) { if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); if (conf->mirrors) kfree(conf->mirrors); if (conf->poolinfo) kfree(conf->poolinfo); kfree(conf); mddev->private = NULL; }out: return -EIO;}static int stop(mddev_t *mddev){ conf_t *conf = mddev_to_conf(mddev); md_unregister_thread(mddev->thread); mddev->thread = NULL; if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); if (conf->mirrors) kfree(conf->mirrors); if (conf->poolinfo) kfree(conf->poolinfo); kfree(conf); mddev->private = NULL; return 0;}static int raid1_resize(mddev_t *mddev, sector_t sectors){ /* no resync is happening, and there is enough space * on all devices, so we can resize. * We need to make sure resync covers any new space. * If the array is shrinking we should possibly wait until * any io in the removed space completes, but it hardly seems * worth it. */ mddev->array_size = sectors>>1; set_capacity(mddev->gendisk, mddev->array_size << 1); mddev->changed = 1; if (mddev->array_size > mddev->size && mddev->recovery_cp == MaxSector) { mddev->recovery_cp = mddev->size << 1; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); } mddev->size = mddev->array_size; return 0;}static int raid1_reshape(mddev_t *mddev, int raid_disks){ /* We need to: * 1/ resize the r1bio_pool * 2/ resize conf->mirrors * * We allocate a new r1bio_pool if we can. * Then raise a device barrier and wait until all IO stops. * Then resize conf->mirrors and swap in the new r1bio pool. */ mempool_t *newpool, *oldpool; struct pool_info *newpoolinfo; mirror_info_t *newmirrors; conf_t *conf = mddev_to_conf(mddev); int d; for (d= raid_disks; d < conf->raid_disks; d++) if (conf->mirrors[d].rdev) return -EBUSY; newpoolinfo = kmalloc(sizeof(newpoolinfo), GFP_KERNEL); if (!newpoolinfo) return -ENOMEM; newpoolinfo->mddev = mddev; newpoolinfo->raid_disks = raid_disks; newpool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, r1bio_pool_free, newpoolinfo); if (!newpool) { kfree(newpoolinfo); return -ENOMEM; } newmirrors = kmalloc(sizeof(struct mirror_info) * raid_disks, GFP_KERNEL); if (!newmirrors) { kfree(newpoolinfo); mempool_destroy(newpool); return -ENOMEM; } memset(newmirrors, 0, sizeof(struct mirror_info)*raid_disks); spin_lock_irq(&conf->resync_lock); conf->barrier++; wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, conf->resync_lock, unplug_slaves(mddev)); spin_unlock_irq(&conf->resync_lock); /* ok, everything is stopped */ oldpool = conf->r1bio_pool; conf->r1bio_pool = newpool; for (d=0; d < raid_disks && d < conf->raid_disks; d++) newmirrors[d] = conf->mirrors[d]; kfree(conf->mirrors); conf->mirrors = newmirrors; kfree(conf->poolinfo); conf->poolinfo = newpoolinfo; mddev->degraded += (raid_disks - conf->raid_disks); conf->raid_disks = mddev->raid_disks = raid_disks; spin_lock_irq(&conf->resync_lock); conf->barrier--; spin_unlock_irq(&conf->resync_lock); wake_up(&conf->wait_resume); wake_up(&conf->wait_idle); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); mempool_destroy(oldpool); return 0;}static mdk_personality_t raid1_personality ={ .name = "raid1", .owner = THIS_MODULE, .make_request = make_request, .run = run, .stop = stop, .status = status, .error_handler = error, .hot_add_disk = raid1_add_disk, .hot_remove_disk= raid1_remove_disk, .spare_active = raid1_spare_active, .sync_request = sync_request, .resize = raid1_resize, .reshape = raid1_reshape,};static int __init raid_init(void){ return register_md_personality(RAID1, &raid1_personality);}static void raid_exit(void){ unregister_md_personality(RAID1);}module_init(raid_init);module_exit(raid_exit);MODULE_LICENSE("GPL");MODULE_ALIAS("md-personality-3"); /* RAID1 */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?