⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm-ioctl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{	if (strchr(name, '/')) {		DMWARN("invalid device name");		return -EINVAL;	}	return 0;}/* * Fills in a dm_ioctl structure, ready for sending back to * userland. */static int __dev_status(struct mapped_device *md, struct dm_ioctl *param){	struct gendisk *disk = dm_disk(md);	struct dm_table *table;	param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |			  DM_ACTIVE_PRESENT_FLAG);	if (dm_suspended(md))		param->flags |= DM_SUSPEND_FLAG;	param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));	/*	 * Yes, this will be out of date by the time it gets back	 * to userland, but it is still very useful for	 * debugging.	 */	param->open_count = dm_open_count(md);	if (disk->policy)		param->flags |= DM_READONLY_FLAG;	param->event_nr = dm_get_event_nr(md);	table = dm_get_table(md);	if (table) {		param->flags |= DM_ACTIVE_PRESENT_FLAG;		param->target_count = dm_table_get_num_targets(table);		dm_table_put(table);	} else		param->target_count = 0;	return 0;}static int dev_create(struct dm_ioctl *param, size_t param_size){	int r, m = DM_ANY_MINOR;	struct mapped_device *md;	r = check_name(param->name);	if (r)		return r;	if (param->flags & DM_PERSISTENT_DEV_FLAG)		m = MINOR(huge_decode_dev(param->dev));	r = dm_create(m, &md);	if (r)		return r;	r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);	if (r) {		dm_put(md);		return r;	}	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;	r = __dev_status(md, param);	dm_put(md);	return r;}/* * Always use UUID for lookups if it's present, otherwise use name or dev. */static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param){	struct mapped_device *md;	void *mdptr = NULL;	if (*param->uuid)		return __get_uuid_cell(param->uuid);	if (*param->name)		return __get_name_cell(param->name);	md = dm_get_md(huge_decode_dev(param->dev));	if (!md)		goto out;	mdptr = dm_get_mdptr(md);	if (!mdptr)		dm_put(md);out:	return mdptr;}static struct mapped_device *find_device(struct dm_ioctl *param){	struct hash_cell *hc;	struct mapped_device *md = NULL;	down_read(&_hash_lock);	hc = __find_device_hash_cell(param);	if (hc) {		md = hc->md;		/*		 * Sneakily write in both the name and the uuid		 * while we have the cell.		 */		strncpy(param->name, hc->name, sizeof(param->name));		if (hc->uuid)			strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1);		else			param->uuid[0] = '\0';		if (hc->new_map)			param->flags |= DM_INACTIVE_PRESENT_FLAG;		else			param->flags &= ~DM_INACTIVE_PRESENT_FLAG;	}	up_read(&_hash_lock);	return md;}static int dev_remove(struct dm_ioctl *param, size_t param_size){	struct hash_cell *hc;	struct mapped_device *md;	int r;	down_write(&_hash_lock);	hc = __find_device_hash_cell(param);	if (!hc) {		DMWARN("device doesn't appear to be in the dev hash table.");		up_write(&_hash_lock);		return -ENXIO;	}	md = hc->md;	/*	 * Ensure the device is not open and nothing further can open it.	 */	r = dm_lock_for_deletion(md);	if (r) {		DMWARN("unable to remove open device %s", hc->name);		up_write(&_hash_lock);		dm_put(md);		return r;	}	__hash_remove(hc);	up_write(&_hash_lock);	dm_put(md);	param->data_size = 0;	return 0;}/* * Check a string doesn't overrun the chunk of * memory we copied from userland. */static int invalid_str(char *str, void *end){	while ((void *) str < end)		if (!*str++)			return 0;	return -EINVAL;}static int dev_rename(struct dm_ioctl *param, size_t param_size){	int r;	char *new_name = (char *) param + param->data_start;	if (new_name < (char *) param->data ||	    invalid_str(new_name, (void *) param + param_size)) {		DMWARN("Invalid new logical volume name supplied.");		return -EINVAL;	}	r = check_name(new_name);	if (r)		return r;	param->data_size = 0;	return dm_hash_rename(param->name, new_name);}static int dev_set_geometry(struct dm_ioctl *param, size_t param_size){	int r = -EINVAL, x;	struct mapped_device *md;	struct hd_geometry geometry;	unsigned long indata[4];	char *geostr = (char *) param + param->data_start;	md = find_device(param);	if (!md)		return -ENXIO;	if (geostr < (char *) param->data ||	    invalid_str(geostr, (void *) param + param_size)) {		DMWARN("Invalid geometry supplied.");		goto out;	}	x = sscanf(geostr, "%lu %lu %lu %lu", indata,		   indata + 1, indata + 2, indata + 3);	if (x != 4) {		DMWARN("Unable to interpret geometry settings.");		goto out;	}	if (indata[0] > 65535 || indata[1] > 255 ||	    indata[2] > 255 || indata[3] > ULONG_MAX) {		DMWARN("Geometry exceeds range limits.");		goto out;	}	geometry.cylinders = indata[0];	geometry.heads = indata[1];	geometry.sectors = indata[2];	geometry.start = indata[3];	r = dm_set_geometry(md, &geometry);	if (!r)		r = __dev_status(md, param);	param->data_size = 0;out:	dm_put(md);	return r;}static int do_suspend(struct dm_ioctl *param){	int r = 0;	unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;	struct mapped_device *md;	md = find_device(param);	if (!md)		return -ENXIO;	if (param->flags & DM_SKIP_LOCKFS_FLAG)		suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;	if (param->flags & DM_NOFLUSH_FLAG)		suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;	if (!dm_suspended(md))		r = dm_suspend(md, suspend_flags);	if (!r)		r = __dev_status(md, param);	dm_put(md);	return r;}static int do_resume(struct dm_ioctl *param){	int r = 0;	unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;	struct hash_cell *hc;	struct mapped_device *md;	struct dm_table *new_map;	down_write(&_hash_lock);	hc = __find_device_hash_cell(param);	if (!hc) {		DMWARN("device doesn't appear to be in the dev hash table.");		up_write(&_hash_lock);		return -ENXIO;	}	md = hc->md;	new_map = hc->new_map;	hc->new_map = NULL;	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;	up_write(&_hash_lock);	/* Do we need to load a new map ? */	if (new_map) {		/* Suspend if it isn't already suspended */		if (param->flags & DM_SKIP_LOCKFS_FLAG)			suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;		if (param->flags & DM_NOFLUSH_FLAG)			suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;		if (!dm_suspended(md))			dm_suspend(md, suspend_flags);		r = dm_swap_table(md, new_map);		if (r) {			dm_put(md);			dm_table_put(new_map);			return r;		}		if (dm_table_get_mode(new_map) & FMODE_WRITE)			set_disk_ro(dm_disk(md), 0);		else			set_disk_ro(dm_disk(md), 1);		dm_table_put(new_map);	}	if (dm_suspended(md))		r = dm_resume(md);	if (!r)		r = __dev_status(md, param);	dm_put(md);	return r;}/* * Set or unset the suspension state of a device. * If the device already is in the requested state we just return its status. */static int dev_suspend(struct dm_ioctl *param, size_t param_size){	if (param->flags & DM_SUSPEND_FLAG)		return do_suspend(param);	return do_resume(param);}/* * Copies device info back to user space, used by * the create and info ioctls. */static int dev_status(struct dm_ioctl *param, size_t param_size){	int r;	struct mapped_device *md;	md = find_device(param);	if (!md)		return -ENXIO;	r = __dev_status(md, param);	dm_put(md);	return r;}/* * Build up the status struct for each target */static void retrieve_status(struct dm_table *table,			    struct dm_ioctl *param, size_t param_size){	unsigned int i, num_targets;	struct dm_target_spec *spec;	char *outbuf, *outptr;	status_type_t type;	size_t remaining, len, used = 0;	outptr = outbuf = get_result_buffer(param, param_size, &len);	if (param->flags & DM_STATUS_TABLE_FLAG)		type = STATUSTYPE_TABLE;	else		type = STATUSTYPE_INFO;	/* Get all the target info */	num_targets = dm_table_get_num_targets(table);	for (i = 0; i < num_targets; i++) {		struct dm_target *ti = dm_table_get_target(table, i);		remaining = len - (outptr - outbuf);		if (remaining <= sizeof(struct dm_target_spec)) {			param->flags |= DM_BUFFER_FULL_FLAG;			break;		}		spec = (struct dm_target_spec *) outptr;		spec->status = 0;		spec->sector_start = ti->begin;		spec->length = ti->len;		strncpy(spec->target_type, ti->type->name,			sizeof(spec->target_type));		outptr += sizeof(struct dm_target_spec);		remaining = len - (outptr - outbuf);		if (remaining <= 0) {			param->flags |= DM_BUFFER_FULL_FLAG;			break;		}		/* Get the status/table string from the target driver */		if (ti->type->status) {			if (ti->type->status(ti, type, outptr, remaining)) {				param->flags |= DM_BUFFER_FULL_FLAG;				break;			}		} else			outptr[0] = '\0';		outptr += strlen(outptr) + 1;		used = param->data_start + (outptr - outbuf);		outptr = align_ptr(outptr);		spec->next = outptr - outbuf;	}	if (used)		param->data_size = used;	param->target_count = num_targets;}/* * Wait for a device to report an event */static int dev_wait(struct dm_ioctl *param, size_t param_size){	int r;	struct mapped_device *md;	struct dm_table *table;	md = find_device(param);	if (!md)		return -ENXIO;	/*	 * Wait for a notification event	 */	if (dm_wait_event(md, param->event_nr)) {		r = -ERESTARTSYS;		goto out;	}	/*	 * The userland program is going to want to know what	 * changed to trigger the event, so we may as well tell	 * him and save an ioctl.	 */	r = __dev_status(md, param);	if (r)		goto out;	table = dm_get_table(md);	if (table) {		retrieve_status(table, param, param_size);		dm_table_put(table);	} out:	dm_put(md);	return r;}static inline int get_mode(struct dm_ioctl *param){	int mode = FMODE_READ | FMODE_WRITE;	if (param->flags & DM_READONLY_FLAG)		mode = FMODE_READ;	return mode;}static int next_target(struct dm_target_spec *last, uint32_t next, void *end,		       struct dm_target_spec **spec, char **target_params){	*spec = (struct dm_target_spec *) ((unsigned char *) last + next);	*target_params = (char *) (*spec + 1);	if (*spec < (last + 1))		return -EINVAL;	return invalid_str(*target_params, end);}static int populate_table(struct dm_table *table,			  struct dm_ioctl *param, size_t param_size){	int r;	unsigned int i = 0;	struct dm_target_spec *spec = (struct dm_target_spec *) param;	uint32_t next = param->data_start;	void *end = (void *) param + param_size;	char *target_params;	if (!param->target_count) {		DMWARN("populate_table: no targets specified");		return -EINVAL;	}	for (i = 0; i < param->target_count; i++) {		r = next_target(spec, next, end, &spec, &target_params);		if (r) {			DMWARN("unable to find target");			return r;

⌨️ 快捷键说明

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