md.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,796 行 · 第 1/5 页
C
2,796 行
bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); if (IS_ERR(bdev)) { printk(KERN_ERR "md: could not open %s.\n", __bdevname(dev, b)); return PTR_ERR(bdev); } err = bd_claim(bdev, rdev); if (err) { printk(KERN_ERR "md: could not bd_claim %s.\n", bdevname(bdev, b)); blkdev_put(bdev); return err; } rdev->bdev = bdev; return err;}static void unlock_rdev(mdk_rdev_t *rdev){ struct block_device *bdev = rdev->bdev; rdev->bdev = NULL; if (!bdev) MD_BUG(); bd_release(bdev); blkdev_put(bdev);}void md_autodetect_dev(dev_t dev);static void export_rdev(mdk_rdev_t * rdev){ char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: export_rdev(%s)\n", bdevname(rdev->bdev,b)); if (rdev->mddev) MD_BUG(); free_disk_sb(rdev); list_del_init(&rdev->same_set);#ifndef MODULE md_autodetect_dev(rdev->bdev->bd_dev);#endif unlock_rdev(rdev); kfree(rdev);}static void kick_rdev_from_array(mdk_rdev_t * rdev){ unbind_rdev_from_array(rdev); export_rdev(rdev);}static void export_array(mddev_t *mddev){ struct list_head *tmp; mdk_rdev_t *rdev; ITERATE_RDEV(mddev,rdev,tmp) { if (!rdev->mddev) { MD_BUG(); continue; } kick_rdev_from_array(rdev); } if (!list_empty(&mddev->disks)) MD_BUG(); mddev->raid_disks = 0; mddev->major_version = 0;}static void print_desc(mdp_disk_t *desc){ printk(" DISK<N:%d,(%d,%d),R:%d,S:%d>\n", desc->number, desc->major,desc->minor,desc->raid_disk,desc->state);}static void print_sb(mdp_super_t *sb){ int i; printk(KERN_INFO "md: SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", sb->major_version, sb->minor_version, sb->patch_version, sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, sb->ctime); printk(KERN_INFO "md: L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, sb->layout, sb->chunk_size); printk(KERN_INFO "md: UT:%08x ST:%d AD:%d WD:%d" " FD:%d SD:%d CSUM:%08x E:%08lx\n", sb->utime, sb->state, sb->active_disks, sb->working_disks, sb->failed_disks, sb->spare_disks, sb->sb_csum, (unsigned long)sb->events_lo); printk(KERN_INFO); for (i = 0; i < MD_SB_DISKS; i++) { mdp_disk_t *desc; desc = sb->disks + i; if (desc->number || desc->major || desc->minor || desc->raid_disk || (desc->state && (desc->state != 4))) { printk(" D %2d: ", i); print_desc(desc); } } printk(KERN_INFO "md: THIS: "); print_desc(&sb->this_disk);}static void print_rdev(mdk_rdev_t *rdev){ char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n", bdevname(rdev->bdev,b), (unsigned long long)rdev->size, rdev->faulty, rdev->in_sync, rdev->desc_nr); if (rdev->sb_loaded) { printk(KERN_INFO "md: rdev superblock:\n"); print_sb((mdp_super_t*)page_address(rdev->sb_page)); } else printk(KERN_INFO "md: no rdev superblock!\n");}void md_print_devices(void){ struct list_head *tmp, *tmp2; mdk_rdev_t *rdev; mddev_t *mddev; char b[BDEVNAME_SIZE]; printk("\n"); printk("md: **********************************\n"); printk("md: * <COMPLETE RAID STATE PRINTOUT> *\n"); printk("md: **********************************\n"); ITERATE_MDDEV(mddev,tmp) { printk("%s: ", mdname(mddev)); ITERATE_RDEV(mddev,rdev,tmp2) printk("<%s>", bdevname(rdev->bdev,b)); printk("\n"); ITERATE_RDEV(mddev,rdev,tmp2) print_rdev(rdev); } printk("md: **********************************\n"); printk("\n");}static int write_disk_sb(mdk_rdev_t * rdev){ char b[BDEVNAME_SIZE]; if (!rdev->sb_loaded) { MD_BUG(); return 1; } if (rdev->faulty) { MD_BUG(); return 1; } dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", bdevname(rdev->bdev,b), (unsigned long long)rdev->sb_offset); if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) return 0; printk("md: write_disk_sb failed for device %s\n", bdevname(rdev->bdev,b)); return 1;}static void sync_sbs(mddev_t * mddev){ mdk_rdev_t *rdev; struct list_head *tmp; ITERATE_RDEV(mddev,rdev,tmp) { super_types[mddev->major_version]. sync_super(mddev, rdev); rdev->sb_loaded = 1; }}static void md_update_sb(mddev_t * mddev){ int err, count = 100; struct list_head *tmp; mdk_rdev_t *rdev; mddev->sb_dirty = 0;repeat: mddev->utime = get_seconds(); mddev->events ++; if (!mddev->events) { /* * oops, this 64-bit counter should never wrap. * Either we are in around ~1 trillion A.C., assuming * 1 reboot per second, or we have a bug: */ MD_BUG(); mddev->events --; } sync_sbs(mddev); /* * do not write anything to disk if using * nonpersistent superblocks */ if (!mddev->persistent) return; dprintk(KERN_INFO "md: updating %s RAID superblock on device (in sync %d)\n", mdname(mddev),mddev->in_sync); err = 0; ITERATE_RDEV(mddev,rdev,tmp) { char b[BDEVNAME_SIZE]; dprintk(KERN_INFO "md: "); if (rdev->faulty) dprintk("(skipping faulty "); dprintk("%s ", bdevname(rdev->bdev,b)); if (!rdev->faulty) { err += write_disk_sb(rdev); } else dprintk(")\n"); if (!err && mddev->level == LEVEL_MULTIPATH) /* only need to write one superblock... */ break; } if (err) { if (--count) { printk(KERN_ERR "md: errors occurred during superblock" " update, repeating\n"); goto repeat; } printk(KERN_ERR \ "md: excessive errors occurred during superblock update, exiting\n"); }}/* * Import a device. If 'super_format' >= 0, then sanity check the superblock * * mark the device faulty if: * * - the device is nonexistent (zero size) * - the device has no valid superblock * * a faulty rdev _never_ has rdev->sb set. */static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_minor){ char b[BDEVNAME_SIZE]; int err; mdk_rdev_t *rdev; sector_t size; rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { printk(KERN_ERR "md: could not alloc mem for new device!\n"); return ERR_PTR(-ENOMEM); } memset(rdev, 0, sizeof(*rdev)); if ((err = alloc_disk_sb(rdev))) goto abort_free; err = lock_rdev(rdev, newdev); if (err) goto abort_free; rdev->desc_nr = -1; rdev->faulty = 0; rdev->in_sync = 0; rdev->data_offset = 0; atomic_set(&rdev->nr_pending, 0); size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; if (!size) { printk(KERN_WARNING "md: %s has zero or unknown size, marking faulty!\n", bdevname(rdev->bdev,b)); err = -EINVAL; goto abort_free; } if (super_format >= 0) { err = super_types[super_format]. load_super(rdev, NULL, super_minor); if (err == -EINVAL) { printk(KERN_WARNING "md: %s has invalid sb, not importing!\n", bdevname(rdev->bdev,b)); goto abort_free; } if (err < 0) { printk(KERN_WARNING "md: could not read %s's sb, not importing!\n", bdevname(rdev->bdev,b)); goto abort_free; } } INIT_LIST_HEAD(&rdev->same_set); return rdev;abort_free: if (rdev->sb_page) { if (rdev->bdev) unlock_rdev(rdev); free_disk_sb(rdev); } kfree(rdev); return ERR_PTR(err);}/* * Check a full RAID array for plausibility */static int analyze_sbs(mddev_t * mddev){ int i; struct list_head *tmp; mdk_rdev_t *rdev, *freshest; char b[BDEVNAME_SIZE]; freshest = NULL; ITERATE_RDEV(mddev,rdev,tmp) switch (super_types[mddev->major_version]. load_super(rdev, freshest, mddev->minor_version)) { case 1: freshest = rdev; break; case 0: break; default: printk( KERN_ERR \ "md: fatal superblock inconsistency in %s" " -- removing from array\n", bdevname(rdev->bdev,b)); kick_rdev_from_array(rdev); } super_types[mddev->major_version]. validate_super(mddev, freshest); i = 0; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev != freshest) if (super_types[mddev->major_version]. validate_super(mddev, rdev)) { printk(KERN_WARNING "md: kicking non-fresh %s" " from array!\n", bdevname(rdev->bdev,b)); kick_rdev_from_array(rdev); continue; } if (mddev->level == LEVEL_MULTIPATH) { rdev->desc_nr = i++; rdev->raid_disk = rdev->desc_nr; rdev->in_sync = 1; } } /* * Check if we can support this RAID array */ if (mddev->major_version != MD_MAJOR_VERSION || mddev->minor_version > MD_MINOR_VERSION) { printk(KERN_ALERT "md: %s: unsupported raid array version %d.%d.%d\n", mdname(mddev), mddev->major_version, mddev->minor_version, mddev->patch_version); goto abort; } if ((mddev->recovery_cp != MaxSector) && ((mddev->level == 1) || ((mddev->level >= 4) && (mddev->level <= 6)))) printk(KERN_ERR "md: %s: raid array is not clean" " -- starting background reconstruction\n", mdname(mddev)); return 0;abort: return 1;}int mdp_major = 0;static struct kobject *md_probe(dev_t dev, int *part, void *data){ static DECLARE_MUTEX(disks_sem); mddev_t *mddev = mddev_find(dev); struct gendisk *disk; int partitioned = (MAJOR(dev) != MD_MAJOR); int shift = partitioned ? MdpMinorShift : 0; int unit = MINOR(dev) >> shift; if (!mddev) return NULL; down(&disks_sem); if (mddev->gendisk) { up(&disks_sem); mddev_put(mddev); return NULL; } disk = alloc_disk(1 << shift); if (!disk) { up(&disks_sem); mddev_put(mddev); return NULL; } disk->major = MAJOR(dev); disk->first_minor = unit << shift; if (partitioned) sprintf(disk->disk_name, "md_d%d", unit); else sprintf(disk->disk_name, "md%d", unit); disk->fops = &md_fops; disk->private_data = mddev; disk->queue = mddev->queue; add_disk(disk); mddev->gendisk = disk; up(&disks_sem); return NULL;}void md_wakeup_thread(mdk_thread_t *thread);static void md_safemode_timeout(unsigned long data){ mddev_t *mddev = (mddev_t *) data; mddev->safemode = 1; md_wakeup_thread(mddev->thread);}static int do_md_run(mddev_t * mddev){ int pnum, err; int chunk_size; struct list_head *tmp; mdk_rdev_t *rdev; struct gendisk *disk; char b[BDEVNAME_SIZE]; if (list_empty(&mddev->disks)) { MD_BUG(); return -EINVAL; } if (mddev->pers) return -EBUSY; /* * Analyze all RAID superblock(s) */ if (!mddev->raid_disks && analyze_sbs(mddev)) { MD_BUG(); return -EINVAL; } chunk_size = mddev->chunk_size; pnum = level_to_pers(mddev->level); if ((pnum != MULTIPATH) && (pnum != RAID1)) { if (!chunk_size) { /* * 'default chunksize' in the old md code used to * be PAGE_SIZE, baaad. * we abort here to be on the safe side. We don't * want to continue the bad practice. */ printk(KERN_ERR "no chunksize specified, see 'man raidtab'\n"); return -EINVAL; } if (chunk_size > MAX_CHUNK_SIZE) { printk(KERN_ERR "too big chunk_size: %d > %d\n", chunk_size, MAX_CHUNK_SIZE); return -EINVAL; } /* * chunk-size has to be a power of 2 and multiples of PAGE_SIZE */ if ( (1 << ffz(~chunk_size)) != chunk_size) { MD_BUG(); return -EINVAL; } if (chunk_size < PAGE_SIZE) { printk(KERN_ERR "too small chunk_size: %d < %ld\n", chunk_size, PAGE_SIZE); return -EINVAL; } /* devices must have minimum size of one chunk */ ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; if (rdev->size < chunk_size / 1024) { printk(KERN_WARNING "md: Dev %s smaller than chunk_size:" " %lluk < %dk\n", bdevname(rdev->bdev,b), (unsigned long long)rdev->size, chunk_size / 1024); return -EINVAL; } } } if (pnum >= MAX_PERSONALITY) { MD_BUG(); return -EINVAL; }#ifdef CONFIG_KMOD if (!pers[pnum]) { request_module("md-personality-%d", pnum); }#endif /* * Drop all container device buffers, from now on * the only valid external interface is through the md * device. * Also find largest hardsector size */ ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; sync_blockdev(rdev->bdev); invalidate_bdev(rdev->bdev, 0); } md_probe(mddev->unit, NULL, NULL); disk = mddev->gendisk; if (!disk) return -ENOMEM; spin_lock(&pers_lock); if (!pers[pnum] || !try_module_get(pers[pnum]->owner)) { spin_unlock(&pers_lock); printk(KERN_WARNING "md: personality %d is not loaded!\n", pnum); return -EINVAL; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?