md.c

来自「linux 内核源代码」· C语言 代码 · 共 2,595 行 · 第 1/5 页

C
2,595
字号
			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 void 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;			set_bit(In_sync, &rdev->flags);		} else if (rdev->raid_disk >= mddev->raid_disks) {			rdev->raid_disk = -1;			clear_bit(In_sync, &rdev->flags);		}	}	if (mddev->recovery_cp != MaxSector &&	    mddev->level >= 1)		printk(KERN_ERR "md: %s: raid array is not clean"		       " -- starting background reconstruction\n",		       mdname(mddev));}static ssize_tsafe_delay_show(mddev_t *mddev, char *page){	int msec = (mddev->safemode_delay*1000)/HZ;	return sprintf(page, "%d.%03d\n", msec/1000, msec%1000);}static ssize_tsafe_delay_store(mddev_t *mddev, const char *cbuf, size_t len){	int scale=1;	int dot=0;	int i;	unsigned long msec;	char buf[30];	char *e;	/* remove a period, and count digits after it */	if (len >= sizeof(buf))		return -EINVAL;	strlcpy(buf, cbuf, len);	buf[len] = 0;	for (i=0; i<len; i++) {		if (dot) {			if (isdigit(buf[i])) {				buf[i-1] = buf[i];				scale *= 10;			}			buf[i] = 0;		} else if (buf[i] == '.') {			dot=1;			buf[i] = 0;		}	}	msec = simple_strtoul(buf, &e, 10);	if (e == buf || (*e && *e != '\n'))		return -EINVAL;	msec = (msec * 1000) / scale;	if (msec == 0)		mddev->safemode_delay = 0;	else {		mddev->safemode_delay = (msec*HZ)/1000;		if (mddev->safemode_delay == 0)			mddev->safemode_delay = 1;	}	return len;}static struct md_sysfs_entry md_safe_delay =__ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store);static ssize_tlevel_show(mddev_t *mddev, char *page){	struct mdk_personality *p = mddev->pers;	if (p)		return sprintf(page, "%s\n", p->name);	else if (mddev->clevel[0])		return sprintf(page, "%s\n", mddev->clevel);	else if (mddev->level != LEVEL_NONE)		return sprintf(page, "%d\n", mddev->level);	else		return 0;}static ssize_tlevel_store(mddev_t *mddev, const char *buf, size_t len){	int rv = len;	if (mddev->pers)		return -EBUSY;	if (len == 0)		return 0;	if (len >= sizeof(mddev->clevel))		return -ENOSPC;	strncpy(mddev->clevel, buf, len);	if (mddev->clevel[len-1] == '\n')		len--;	mddev->clevel[len] = 0;	mddev->level = LEVEL_NONE;	return rv;}static struct md_sysfs_entry md_level =__ATTR(level, S_IRUGO|S_IWUSR, level_show, level_store);static ssize_tlayout_show(mddev_t *mddev, char *page){	/* just a number, not meaningful for all levels */	if (mddev->reshape_position != MaxSector &&	    mddev->layout != mddev->new_layout)		return sprintf(page, "%d (%d)\n",			       mddev->new_layout, mddev->layout);	return sprintf(page, "%d\n", mddev->layout);}static ssize_tlayout_store(mddev_t *mddev, const char *buf, size_t len){	char *e;	unsigned long n = simple_strtoul(buf, &e, 10);	if (!*buf || (*e && *e != '\n'))		return -EINVAL;	if (mddev->pers)		return -EBUSY;	if (mddev->reshape_position != MaxSector)		mddev->new_layout = n;	else		mddev->layout = n;	return len;}static struct md_sysfs_entry md_layout =__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);static ssize_traid_disks_show(mddev_t *mddev, char *page){	if (mddev->raid_disks == 0)		return 0;	if (mddev->reshape_position != MaxSector &&	    mddev->delta_disks != 0)		return sprintf(page, "%d (%d)\n", mddev->raid_disks,			       mddev->raid_disks - mddev->delta_disks);	return sprintf(page, "%d\n", mddev->raid_disks);}static int update_raid_disks(mddev_t *mddev, int raid_disks);static ssize_traid_disks_store(mddev_t *mddev, const char *buf, size_t len){	char *e;	int rv = 0;	unsigned long n = simple_strtoul(buf, &e, 10);	if (!*buf || (*e && *e != '\n'))		return -EINVAL;	if (mddev->pers)		rv = update_raid_disks(mddev, n);	else if (mddev->reshape_position != MaxSector) {		int olddisks = mddev->raid_disks - mddev->delta_disks;		mddev->delta_disks = n - olddisks;		mddev->raid_disks = n;	} else		mddev->raid_disks = n;	return rv ? rv : len;}static struct md_sysfs_entry md_raid_disks =__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);static ssize_tchunk_size_show(mddev_t *mddev, char *page){	if (mddev->reshape_position != MaxSector &&	    mddev->chunk_size != mddev->new_chunk)		return sprintf(page, "%d (%d)\n", mddev->new_chunk,			       mddev->chunk_size);	return sprintf(page, "%d\n", mddev->chunk_size);}static ssize_tchunk_size_store(mddev_t *mddev, const char *buf, size_t len){	/* can only set chunk_size if array is not yet active */	char *e;	unsigned long n = simple_strtoul(buf, &e, 10);	if (!*buf || (*e && *e != '\n'))		return -EINVAL;	if (mddev->pers)		return -EBUSY;	else if (mddev->reshape_position != MaxSector)		mddev->new_chunk = n;	else		mddev->chunk_size = n;	return len;}static struct md_sysfs_entry md_chunk_size =__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);static ssize_tresync_start_show(mddev_t *mddev, char *page){	return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp);}static ssize_tresync_start_store(mddev_t *mddev, const char *buf, size_t len){	/* can only set chunk_size if array is not yet active */	char *e;	unsigned long long n = simple_strtoull(buf, &e, 10);	if (mddev->pers)		return -EBUSY;	if (!*buf || (*e && *e != '\n'))		return -EINVAL;	mddev->recovery_cp = n;	return len;}static struct md_sysfs_entry md_resync_start =__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);/* * The array state can be: * * clear *     No devices, no size, no level *     Equivalent to STOP_ARRAY ioctl * inactive *     May have some settings, but array is not active *        all IO results in error *     When written, doesn't tear down array, but just stops it * suspended (not supported yet) *     All IO requests will block. The array can be reconfigured. *     Writing this, if accepted, will block until array is quiessent * readonly *     no resync can happen.  no superblocks get written. *     write requests fail * read-auto *     like readonly, but behaves like 'clean' on a write request. * * clean - no pending writes, but otherwise active. *     When written to inactive array, starts without resync *     If a write request arrives then *       if metadata is known, mark 'dirty' and switch to 'active'. *       if not known, block and switch to write-pending *     If written to an active array that has pending writes, then fails. * active *     fully active: IO and resync can be happening. *     When written to inactive array, starts with resync * * write-pending *     clean, but writes are blocked waiting for 'active' to be written. * * active-idle *     like active, but no writes have been seen for a while (100msec). * */enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active,		   write_pending, active_idle, bad_word};static char *array_states[] = {	"clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active",	"write-pending", "active-idle", NULL };static int match_word(const char *word, char **list){	int n;	for (n=0; list[n]; n++)		if (cmd_match(word, list[n]))			break;	return n;}static ssize_tarray_state_show(mddev_t *mddev, char *page){	enum array_state st = inactive;	if (mddev->pers)		switch(mddev->ro) {		case 1:			st = readonly;			break;		case 2:			st = read_auto;			break;		case 0:			if (mddev->in_sync)				st = clean;			else if (mddev->safemode)				st = active_idle;			else				st = active;		}	else {		if (list_empty(&mddev->disks) &&		    mddev->raid_disks == 0 &&		    mddev->size == 0)			st = clear;		else			st = inactive;	}	return sprintf(page, "%s\n", array_states[st]);}static int do_md_stop(mddev_t * mddev, int ro);static int do_md_run(mddev_t * mddev);static int restart_array(mddev_t *mddev);static ssize_tarray_state_store(mddev_t *mddev, const char *buf, size_t len){	int err = -EINVAL;	enum array_state st = match_word(buf, array_states);	switch(st) {	case bad_word:		break;	case clear:		/* stopping an active array */		if (mddev->pers) {			if (atomic_read(&mddev->active) > 1)				return -EBUSY;			err = do_md_stop(mddev, 0);		}		break;	case inactive:		/* stopping an active array */		if (mddev->pers) {			if (atomic_read(&mddev->active) > 1)				return -EBUSY;			err = do_md_stop(mddev, 2);		}		break;	case suspended:		break; /* not supported yet */	case readonly:		if (mddev->pers)			err = do_md_stop(mddev, 1);		else {			mddev->ro = 1;			err = do_md_run(mddev);		}		break;	case read_auto:		/* stopping an active array */		if (mddev->pers) {			err = do_md_stop(mddev, 1);			if (err == 0)				mddev->ro = 2; /* FIXME mark devices writable */		} else {			mddev->ro = 2;			err = do_md_run(mddev);		}		break;	case clean:		if (mddev->pers) {			restart_array(mddev);			spin_lock_irq(&mddev->write_lock);			if (atomic_read(&mddev->writes_pending) == 0) {				mddev->in_sync = 1;				set_bit(MD_CHANGE_CLEAN, &mddev->flags);			}			spin_unlock_irq(&mddev->write_lock);		} else {			mddev->ro = 0;			mddev->recovery_cp = MaxSector;			err = do_md_run(mddev);		}		break;	case active:		if (mddev->pers) {			restart_array(mddev);			clear_bit(MD_CHANGE_CLEAN, &mddev->flags);			wake_up(&mddev->sb_wait);			err = 0;		} else {			mddev->ro = 0;			err = do_md_run(mddev);		}		break;	case write_pending:	case active_idle:		/* these cannot be set */		break;	}	if (err)		return err;	else		return len;}static struct md_sysfs_entry md_array_state =__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);static ssize_tnull_show(mddev_t *mddev, char *page){	return -EINVAL;}static ssize_tnew_dev_store(mddev_t *mddev, const char *buf, size_t len){	/* buf must be %d:%d\n? giving major and minor numbers */	/* The new device is added to the array.	 * If the array has a persistent superblock, we read the	 * superblock to initialise info and check validity.	 * Otherwise, only checking done is that in bind_rdev_to_array,	 * which mainly checks size.	 */	char *e;	int major = simple_strtoul(buf, &e, 10);	int minor;	dev_t dev;	mdk_rdev_t *rdev;	int err;	if (!*buf || *e != ':' || !e[1] || e[1] == '\n')		return -EINVAL;	minor = simple_strtoul(e+1, &e, 10);	if (*e && *e != '\n')		return -EINVAL;	dev = MKDEV(major, minor);	if (major != MAJOR(dev) ||	    minor != MINOR(dev))		return -EOVERFLOW;	if (mddev->persistent) {		rdev = md_import_device(dev, mddev->major_version,					mddev->minor_version);		if (!IS_ERR(rdev) && !list_empty(&mddev->disks)) {			mdk_rdev_t *rdev0 = list_entry(mddev->disks.next,						       mdk_rdev_t, same_set);			err = super_types[mddev->major_version]				.load_super(rdev, rdev0, mddev->minor_version);			if (err < 0)				goto out;		}	} else		rdev = md_import_device(dev, -1, -1);	if (IS_ERR(rdev))		return PTR_ERR(rdev);	err = bind_rdev_to_array(rdev, mddev); out:	if (err)		export_rdev(rdev);	return err ? err : len;}static struct md_sysfs_entry md_new_device =__ATTR(new_dev, S_IWUSR, null

⌨️ 快捷键说明

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