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 + -
显示快捷键?