md.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,796 行 · 第 1/5 页

C
2,796
字号
	bdevname(rdev->bdev, b);	sb = (mdp_super_t*)page_address(rdev->sb_page);	if (sb->md_magic != MD_SB_MAGIC) {		printk(KERN_ERR "md: invalid raid superblock magic on %s\n",		       b);		goto abort;	}	if (sb->major_version != 0 ||	    sb->minor_version != 90) {		printk(KERN_WARNING "Bad version number %d.%d on %s\n",			sb->major_version, sb->minor_version,			b);		goto abort;	}	if (sb->raid_disks <= 0)		goto abort;	if (calc_sb_csum(sb) != sb->sb_csum &&		calc_sb_csum_common(sb) != sb->sb_csum) {		printk(KERN_WARNING "md: invalid superblock checksum on %s\n",			b);		goto abort;	}	rdev->preferred_minor = sb->md_minor;	rdev->data_offset = 0;	if (sb->level == MULTIPATH)		rdev->desc_nr = -1;	else		rdev->desc_nr = sb->this_disk.number;	if (refdev == 0)		ret = 1;	else {		__u64 ev1, ev2;		mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page);		if (!uuid_equal(refsb, sb)) {			printk(KERN_WARNING "md: %s has different UUID to %s\n",				b, bdevname(refdev->bdev,b2));			goto abort;		}		if (!sb_equal(refsb, sb)) {			printk(KERN_WARNING "md: %s has same UUID"			       " but different superblock to %s\n",			       b, bdevname(refdev->bdev, b2));			goto abort;		}		ev1 = md_event(sb);		ev2 = md_event(refsb);		if (ev1 > ev2)			ret = 1;		else 			ret = 0;	}	rdev->size = calc_dev_size(rdev, sb->chunk_size); abort:	return ret;}/* * validate_super for 0.90.0 */static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev){	mdp_disk_t *desc;	mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);	if (mddev->raid_disks == 0) {		mddev->major_version = 0;		mddev->minor_version = sb->minor_version;		mddev->patch_version = sb->patch_version;		mddev->persistent = ! sb->not_persistent;		mddev->chunk_size = sb->chunk_size;		mddev->ctime = sb->ctime;		mddev->utime = sb->utime;		mddev->level = sb->level;		mddev->layout = sb->layout;		mddev->raid_disks = sb->raid_disks;		mddev->size = sb->size;		mddev->events = md_event(sb);		if (sb->state & (1<<MD_SB_CLEAN))			mddev->recovery_cp = MaxSector;		else {			if (sb->events_hi == sb->cp_events_hi && 				sb->events_lo == sb->cp_events_lo) {				mddev->recovery_cp = sb->recovery_cp;			} else				mddev->recovery_cp = 0;		}		memcpy(mddev->uuid+0, &sb->set_uuid0, 4);		memcpy(mddev->uuid+4, &sb->set_uuid1, 4);		memcpy(mddev->uuid+8, &sb->set_uuid2, 4);		memcpy(mddev->uuid+12,&sb->set_uuid3, 4);		mddev->max_disks = MD_SB_DISKS;	} else {		__u64 ev1;		ev1 = md_event(sb);		++ev1;		if (ev1 < mddev->events) 			return -EINVAL;	}	if (mddev->level != LEVEL_MULTIPATH) {		rdev->raid_disk = -1;		rdev->in_sync = rdev->faulty = 0;		desc = sb->disks + rdev->desc_nr;		if (desc->state & (1<<MD_DISK_FAULTY))			rdev->faulty = 1;		else if (desc->state & (1<<MD_DISK_SYNC) &&			 desc->raid_disk < mddev->raid_disks) {			rdev->in_sync = 1;			rdev->raid_disk = desc->raid_disk;		}	}	return 0;}/* * sync_super for 0.90.0 */static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev){	mdp_super_t *sb;	struct list_head *tmp;	mdk_rdev_t *rdev2;	int next_spare = mddev->raid_disks;	/* make rdev->sb match mddev data..	 *	 * 1/ zero out disks	 * 2/ Add info for each disk, keeping track of highest desc_nr (next_spare);	 * 3/ any empty disks < next_spare become removed	 *	 * disks[0] gets initialised to REMOVED because	 * we cannot be sure from other fields if it has	 * been initialised or not.	 */	int i;	int active=0, working=0,failed=0,spare=0,nr_disks=0;	sb = (mdp_super_t*)page_address(rdev->sb_page);	memset(sb, 0, sizeof(*sb));	sb->md_magic = MD_SB_MAGIC;	sb->major_version = mddev->major_version;	sb->minor_version = mddev->minor_version;	sb->patch_version = mddev->patch_version;	sb->gvalid_words  = 0; /* ignored */	memcpy(&sb->set_uuid0, mddev->uuid+0, 4);	memcpy(&sb->set_uuid1, mddev->uuid+4, 4);	memcpy(&sb->set_uuid2, mddev->uuid+8, 4);	memcpy(&sb->set_uuid3, mddev->uuid+12,4);	sb->ctime = mddev->ctime;	sb->level = mddev->level;	sb->size  = mddev->size;	sb->raid_disks = mddev->raid_disks;	sb->md_minor = mddev->md_minor;	sb->not_persistent = !mddev->persistent;	sb->utime = mddev->utime;	sb->state = 0;	sb->events_hi = (mddev->events>>32);	sb->events_lo = (u32)mddev->events;	if (mddev->in_sync)	{		sb->recovery_cp = mddev->recovery_cp;		sb->cp_events_hi = (mddev->events>>32);		sb->cp_events_lo = (u32)mddev->events;		if (mddev->recovery_cp == MaxSector)			sb->state = (1<< MD_SB_CLEAN);	} else		sb->recovery_cp = 0;	sb->layout = mddev->layout;	sb->chunk_size = mddev->chunk_size;	sb->disks[0].state = (1<<MD_DISK_REMOVED);	ITERATE_RDEV(mddev,rdev2,tmp) {		mdp_disk_t *d;		if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty)			rdev2->desc_nr = rdev2->raid_disk;		else			rdev2->desc_nr = next_spare++;		d = &sb->disks[rdev2->desc_nr];		nr_disks++;		d->number = rdev2->desc_nr;		d->major = MAJOR(rdev2->bdev->bd_dev);		d->minor = MINOR(rdev2->bdev->bd_dev);		if (rdev2->raid_disk >= 0 && rdev->in_sync && !rdev2->faulty)			d->raid_disk = rdev2->raid_disk;		else			d->raid_disk = rdev2->desc_nr; /* compatibility */		if (rdev2->faulty) {			d->state = (1<<MD_DISK_FAULTY);			failed++;		} else if (rdev2->in_sync) {			d->state = (1<<MD_DISK_ACTIVE);			d->state |= (1<<MD_DISK_SYNC);			active++;			working++;		} else {			d->state = 0;			spare++;			working++;		}	}		/* now set the "removed" and "faulty" bits on any missing devices */	for (i=0 ; i < mddev->raid_disks ; i++) {		mdp_disk_t *d = &sb->disks[i];		if (d->state == 0 && d->number == 0) {			d->number = i;			d->raid_disk = i;			d->state = (1<<MD_DISK_REMOVED);			d->state |= (1<<MD_DISK_FAULTY);			failed++;		}	}	sb->nr_disks = nr_disks;	sb->active_disks = active;	sb->working_disks = working;	sb->failed_disks = failed;	sb->spare_disks = spare;	sb->this_disk = sb->disks[rdev->desc_nr];	sb->sb_csum = calc_sb_csum(sb);}/* * version 1 superblock */static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb){	unsigned int disk_csum, csum;	unsigned long long newcsum;	int size = 256 + sb->max_dev*2;	unsigned int *isuper = (unsigned int*)sb;	int i;	disk_csum = sb->sb_csum;	sb->sb_csum = 0;	newcsum = 0;	for (i=0; size>=4; size -= 4 )		newcsum += le32_to_cpu(*isuper++);	if (size == 2)		newcsum += le16_to_cpu(*(unsigned short*) isuper);	csum = (newcsum & 0xffffffff) + (newcsum >> 32);	sb->sb_csum = disk_csum;	return csum;}static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version){	struct mdp_superblock_1 *sb;	int ret;	sector_t sb_offset;	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];	/*	 * Calculate the position of the superblock.	 * It is always aligned to a 4K boundary and	 * depeding on minor_version, it can be:	 * 0: At least 8K, but less than 12K, from end of device	 * 1: At start of device	 * 2: 4K from start of device.	 */	switch(minor_version) {	case 0:		sb_offset = rdev->bdev->bd_inode->i_size >> 9;		sb_offset -= 8*2;		sb_offset &= ~(4*2);		/* convert from sectors to K */		sb_offset /= 2;		break;	case 1:		sb_offset = 0;		break;	case 2:		sb_offset = 4;		break;	default:		return -EINVAL;	}	rdev->sb_offset = sb_offset;	ret = read_disk_sb(rdev);	if (ret) return ret;	sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);	if (sb->magic != cpu_to_le32(MD_SB_MAGIC) ||	    sb->major_version != cpu_to_le32(1) ||	    le32_to_cpu(sb->max_dev) > (4096-256)/2 ||	    le64_to_cpu(sb->super_offset) != (rdev->sb_offset<<1) ||	    sb->feature_map != 0)		return -EINVAL;	if (calc_sb_1_csum(sb) != sb->sb_csum) {		printk("md: invalid superblock checksum on %s\n",			bdevname(rdev->bdev,b));		return -EINVAL;	}	rdev->preferred_minor = 0xffff;	rdev->data_offset = le64_to_cpu(sb->data_offset);	if (refdev == 0)		return 1;	else {		__u64 ev1, ev2;		struct mdp_superblock_1 *refsb = 			(struct mdp_superblock_1*)page_address(refdev->sb_page);		if (memcmp(sb->set_uuid, refsb->set_uuid, 16) != 0 ||		    sb->level != refsb->level ||		    sb->layout != refsb->layout ||		    sb->chunksize != refsb->chunksize) {			printk(KERN_WARNING "md: %s has strangely different"				" superblock to %s\n",				bdevname(rdev->bdev,b),				bdevname(refdev->bdev,b2));			return -EINVAL;		}		ev1 = le64_to_cpu(sb->events);		ev2 = le64_to_cpu(refsb->events);		if (ev1 > ev2)			return 1;	}	if (minor_version) 		rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2;	else		rdev->size = rdev->sb_offset;	if (rdev->size < le64_to_cpu(sb->data_size)/2)		return -EINVAL;	rdev->size = le64_to_cpu(sb->data_size)/2;	if (le32_to_cpu(sb->chunksize))		rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1);	return 0;}static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev){	struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);	if (mddev->raid_disks == 0) {		mddev->major_version = 1;		mddev->minor_version = 0;		mddev->patch_version = 0;		mddev->persistent = 1;		mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9;		mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);		mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);		mddev->level = le32_to_cpu(sb->level);		mddev->layout = le32_to_cpu(sb->layout);		mddev->raid_disks = le32_to_cpu(sb->raid_disks);		mddev->size = (u32)le64_to_cpu(sb->size);		mddev->events = le64_to_cpu(sb->events);				mddev->recovery_cp = le64_to_cpu(sb->resync_offset);		memcpy(mddev->uuid, sb->set_uuid, 16);		mddev->max_disks =  (4096-256)/2;	} else {		__u64 ev1;		ev1 = le64_to_cpu(sb->events);		++ev1;		if (ev1 < mddev->events)			return -EINVAL;	}	if (mddev->level != LEVEL_MULTIPATH) {		int role;		rdev->desc_nr = le32_to_cpu(sb->dev_number);		role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);		switch(role) {		case 0xffff: /* spare */			rdev->in_sync = 0;			rdev->faulty = 0;			rdev->raid_disk = -1;			break;		case 0xfffe: /* faulty */			rdev->in_sync = 0;			rdev->faulty = 1;			rdev->raid_disk = -1;			break;		default:			rdev->in_sync = 1;			rdev->faulty = 0;			rdev->raid_disk = role;			break;		}	}	return 0;}static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev){	struct mdp_superblock_1 *sb;	struct list_head *tmp;	mdk_rdev_t *rdev2;	int max_dev, i;	/* make rdev->sb match mddev and rdev data. */	sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);	sb->feature_map = 0;	sb->pad0 = 0;	memset(sb->pad1, 0, sizeof(sb->pad1));	memset(sb->pad2, 0, sizeof(sb->pad2));	memset(sb->pad3, 0, sizeof(sb->pad3));	sb->utime = cpu_to_le64((__u64)mddev->utime);	sb->events = cpu_to_le64(mddev->events);	if (mddev->in_sync)		sb->resync_offset = cpu_to_le64(mddev->recovery_cp);	else		sb->resync_offset = cpu_to_le64(0);	max_dev = 0;	ITERATE_RDEV(mddev,rdev2,tmp)		if (rdev2->desc_nr > max_dev)			max_dev = rdev2->desc_nr;		sb->max_dev = max_dev;	for (i=0; i<max_dev;i++)		sb->dev_roles[max_dev] = cpu_to_le16(0xfffe);		ITERATE_RDEV(mddev,rdev2,tmp) {		i = rdev2->desc_nr;		if (rdev2->faulty)			sb->dev_roles[i] = cpu_to_le16(0xfffe);		else if (rdev2->in_sync)			sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);		else			sb->dev_roles[i] = cpu_to_le16(0xffff);	}	sb->recovery_offset = cpu_to_le64(0); /* not supported yet */}struct super_type super_types[] = {	[0] = {		.name	= "0.90.0",		.owner	= THIS_MODULE,		.load_super	= super_90_load,		.validate_super	= super_90_validate,		.sync_super	= super_90_sync,	},	[1] = {		.name	= "md-1",		.owner	= THIS_MODULE,		.load_super	= super_1_load,		.validate_super	= super_1_validate,		.sync_super	= super_1_sync,	},};	static mdk_rdev_t * match_dev_unit(mddev_t *mddev, mdk_rdev_t *dev){	struct list_head *tmp;	mdk_rdev_t *rdev;	ITERATE_RDEV(mddev,rdev,tmp)		if (rdev->bdev->bd_contains == dev->bdev->bd_contains)			return rdev;	return NULL;}static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2){	struct list_head *tmp;	mdk_rdev_t *rdev;	ITERATE_RDEV(mddev1,rdev,tmp)		if (match_dev_unit(mddev2, rdev))			return 1;	return 0;}static LIST_HEAD(pending_raid_disks);static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev){	mdk_rdev_t *same_pdev;	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];	if (rdev->mddev) {		MD_BUG();		return -EINVAL;	}	same_pdev = match_dev_unit(mddev, rdev);	if (same_pdev)		printk(KERN_WARNING			"%s: WARNING: %s appears to be on the same physical"	 		" disk as %s. True\n     protection against single-disk"			" failure might be compromised.\n",			mdname(mddev), bdevname(rdev->bdev,b),			bdevname(same_pdev->bdev,b2));	/* Verify rdev->desc_nr is unique.	 * If it is -1, assign a free number, else	 * check number is not in use	 */	if (rdev->desc_nr < 0) {		int choice = 0;		if (mddev->pers) choice = mddev->raid_disks;		while (find_rdev_nr(mddev, choice))			choice++;		rdev->desc_nr = choice;	} else {		if (find_rdev_nr(mddev, rdev->desc_nr))			return -EBUSY;	}				list_add(&rdev->same_set, &mddev->disks);	rdev->mddev = mddev;	printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));	return 0;}static void unbind_rdev_from_array(mdk_rdev_t * rdev){	char b[BDEVNAME_SIZE];	if (!rdev->mddev) {		MD_BUG();		return;	}	list_del_init(&rdev->same_set);	printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));	rdev->mddev = NULL;}/* * prevent the device from being mounted, repartitioned or * otherwise reused by a RAID array (or any other kernel * subsystem), by bd_claiming the device. */static int lock_rdev(mdk_rdev_t *rdev, dev_t dev){	int err = 0;	struct block_device *bdev;	char b[BDEVNAME_SIZE];

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?