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

📄 dm-ioctl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		}		r = dm_table_add_target(table, spec->target_type,					(sector_t) spec->sector_start,					(sector_t) spec->length,					target_params);		if (r) {			DMWARN("error adding target to table");			return r;		}		next = spec->next;	}	return dm_table_complete(table);}static int table_load(struct dm_ioctl *param, size_t param_size){	int r;	struct hash_cell *hc;	struct dm_table *t;	struct mapped_device *md;	md = find_device(param);	if (!md)		return -ENXIO;	r = dm_table_create(&t, get_mode(param), param->target_count, md);	if (r)		goto out;	r = populate_table(t, param, param_size);	if (r) {		dm_table_put(t);		goto out;	}	down_write(&_hash_lock);	hc = dm_get_mdptr(md);	if (!hc || hc->md != md) {		DMWARN("device has been removed from the dev hash table.");		dm_table_put(t);		up_write(&_hash_lock);		r = -ENXIO;		goto out;	}	if (hc->new_map)		dm_table_put(hc->new_map);	hc->new_map = t;	up_write(&_hash_lock);	param->flags |= DM_INACTIVE_PRESENT_FLAG;	r = __dev_status(md, param);out:	dm_put(md);	return r;}static int table_clear(struct dm_ioctl *param, size_t param_size){	int r;	struct hash_cell *hc;	struct mapped_device *md;	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;	}	if (hc->new_map) {		dm_table_put(hc->new_map);		hc->new_map = NULL;	}	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;	r = __dev_status(hc->md, param);	md = hc->md;	up_write(&_hash_lock);	dm_put(md);	return r;}/* * Retrieves a list of devices used by a particular dm device. */static void retrieve_deps(struct dm_table *table,			  struct dm_ioctl *param, size_t param_size){	unsigned int count = 0;	struct list_head *tmp;	size_t len, needed;	struct dm_dev *dd;	struct dm_target_deps *deps;	deps = get_result_buffer(param, param_size, &len);	/*	 * Count the devices.	 */	list_for_each (tmp, dm_table_get_devices(table))		count++;	/*	 * Check we have enough space.	 */	needed = sizeof(*deps) + (sizeof(*deps->dev) * count);	if (len < needed) {		param->flags |= DM_BUFFER_FULL_FLAG;		return;	}	/*	 * Fill in the devices.	 */	deps->count = count;	count = 0;	list_for_each_entry (dd, dm_table_get_devices(table), list)		deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);	param->data_size = param->data_start + needed;}static int table_deps(struct dm_ioctl *param, size_t param_size){	int r = 0;	struct mapped_device *md;	struct dm_table *table;	md = find_device(param);	if (!md)		return -ENXIO;	r = __dev_status(md, param);	if (r)		goto out;	table = dm_get_table(md);	if (table) {		retrieve_deps(table, param, param_size);		dm_table_put(table);	} out:	dm_put(md);	return r;}/* * Return the status of a device as a text string for each * target. */static int table_status(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;	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;}/* * Pass a message to the target that's at the supplied device offset. */static int target_message(struct dm_ioctl *param, size_t param_size){	int r, argc;	char **argv;	struct mapped_device *md;	struct dm_table *table;	struct dm_target *ti;	struct dm_target_msg *tmsg = (void *) param + param->data_start;	md = find_device(param);	if (!md)		return -ENXIO;	r = __dev_status(md, param);	if (r)		goto out;	if (tmsg < (struct dm_target_msg *) param->data ||	    invalid_str(tmsg->message, (void *) param + param_size)) {		DMWARN("Invalid target message parameters.");		r = -EINVAL;		goto out;	}	r = dm_split_args(&argc, &argv, tmsg->message);	if (r) {		DMWARN("Failed to split target message parameters");		goto out;	}	table = dm_get_table(md);	if (!table)		goto out_argv;	ti = dm_table_find_target(table, tmsg->sector);	if (!dm_target_is_valid(ti)) {		DMWARN("Target message sector outside device.");		r = -EINVAL;	} else if (ti->type->message)		r = ti->type->message(ti, argc, argv);	else {		DMWARN("Target type does not support messages");		r = -EINVAL;	}	dm_table_put(table); out_argv:	kfree(argv); out:	param->data_size = 0;	dm_put(md);	return r;}/*----------------------------------------------------------------- * Implementation of open/close/ioctl on the special char * device. *---------------------------------------------------------------*/static ioctl_fn lookup_ioctl(unsigned int cmd){	static struct {		int cmd;		ioctl_fn fn;	} _ioctls[] = {		{DM_VERSION_CMD, NULL},	/* version is dealt with elsewhere */		{DM_REMOVE_ALL_CMD, remove_all},		{DM_LIST_DEVICES_CMD, list_devices},		{DM_DEV_CREATE_CMD, dev_create},		{DM_DEV_REMOVE_CMD, dev_remove},		{DM_DEV_RENAME_CMD, dev_rename},		{DM_DEV_SUSPEND_CMD, dev_suspend},		{DM_DEV_STATUS_CMD, dev_status},		{DM_DEV_WAIT_CMD, dev_wait},		{DM_TABLE_LOAD_CMD, table_load},		{DM_TABLE_CLEAR_CMD, table_clear},		{DM_TABLE_DEPS_CMD, table_deps},		{DM_TABLE_STATUS_CMD, table_status},		{DM_LIST_VERSIONS_CMD, list_versions},		{DM_TARGET_MSG_CMD, target_message},		{DM_DEV_SET_GEOMETRY_CMD, dev_set_geometry}	};	return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;}/* * As well as checking the version compatibility this always * copies the kernel interface version out. */static int check_version(unsigned int cmd, struct dm_ioctl __user *user){	uint32_t version[3];	int r = 0;	if (copy_from_user(version, user->version, sizeof(version)))		return -EFAULT;	if ((DM_VERSION_MAJOR != version[0]) ||	    (DM_VERSION_MINOR < version[1])) {		DMWARN("ioctl interface mismatch: "		       "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",		       DM_VERSION_MAJOR, DM_VERSION_MINOR,		       DM_VERSION_PATCHLEVEL,		       version[0], version[1], version[2], cmd);		r = -EINVAL;	}	/*	 * Fill in the kernel version.	 */	version[0] = DM_VERSION_MAJOR;	version[1] = DM_VERSION_MINOR;	version[2] = DM_VERSION_PATCHLEVEL;	if (copy_to_user(user->version, version, sizeof(version)))		return -EFAULT;	return r;}static void free_params(struct dm_ioctl *param){	vfree(param);}static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param){	struct dm_ioctl tmp, *dmi;	if (copy_from_user(&tmp, user, sizeof(tmp)))		return -EFAULT;	if (tmp.data_size < sizeof(tmp))		return -EINVAL;	dmi = vmalloc(tmp.data_size);	if (!dmi)		return -ENOMEM;	if (copy_from_user(dmi, user, tmp.data_size)) {		vfree(dmi);		return -EFAULT;	}	*param = dmi;	return 0;}static int validate_params(uint cmd, struct dm_ioctl *param){	/* Always clear this flag */	param->flags &= ~DM_BUFFER_FULL_FLAG;	/* Ignores parameters */	if (cmd == DM_REMOVE_ALL_CMD ||	    cmd == DM_LIST_DEVICES_CMD ||	    cmd == DM_LIST_VERSIONS_CMD)		return 0;	if ((cmd == DM_DEV_CREATE_CMD)) {		if (!*param->name) {			DMWARN("name not supplied when creating device");			return -EINVAL;		}	} else if ((*param->uuid && *param->name)) {		DMWARN("only supply one of name or uuid, cmd(%u)", cmd);		return -EINVAL;	}	/* Ensure strings are terminated */	param->name[DM_NAME_LEN - 1] = '\0';	param->uuid[DM_UUID_LEN - 1] = '\0';	return 0;}static int ctl_ioctl(struct inode *inode, struct file *file,		     uint command, ulong u){	int r = 0;	unsigned int cmd;	struct dm_ioctl *param;	struct dm_ioctl __user *user = (struct dm_ioctl __user *) u;	ioctl_fn fn = NULL;	size_t param_size;	/* only root can play with this */	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	if (_IOC_TYPE(command) != DM_IOCTL)		return -ENOTTY;	cmd = _IOC_NR(command);	/*	 * Check the interface version passed in.  This also	 * writes out the kernel's interface version.	 */	r = check_version(cmd, user);	if (r)		return r;	/*	 * Nothing more to do for the version command.	 */	if (cmd == DM_VERSION_CMD)		return 0;	fn = lookup_ioctl(cmd);	if (!fn) {		DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);		return -ENOTTY;	}	/*	 * Trying to avoid low memory issues when a device is	 * suspended.	 */	current->flags |= PF_MEMALLOC;	/*	 * Copy the parameters into kernel space.	 */	r = copy_params(user, &param);	current->flags &= ~PF_MEMALLOC;	if (r)		return r;	r = validate_params(cmd, param);	if (r)		goto out;	param_size = param->data_size;	param->data_size = sizeof(*param);	r = fn(param, param_size);	/*	 * Copy the results back to userland.	 */	if (!r && copy_to_user(user, param, param->data_size))		r = -EFAULT; out:	free_params(param);	return r;}static const struct file_operations _ctl_fops = {	.ioctl	 = ctl_ioctl,	.owner	 = THIS_MODULE,};static struct miscdevice _dm_misc = {	.minor 		= MISC_DYNAMIC_MINOR,	.name  		= DM_NAME,	.fops  		= &_ctl_fops};/* * Create misc character device and link to DM_DIR/control. */int __init dm_interface_init(void){	int r;	r = dm_hash_init();	if (r)		return r;	r = misc_register(&_dm_misc);	if (r) {		DMERR("misc_register failed for control device");		dm_hash_exit();		return r;	}	DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,	       DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,	       DM_DRIVER_EMAIL);	return 0;}void dm_interface_exit(void){	if (misc_deregister(&_dm_misc) < 0)		DMERR("misc_deregister failed for control device");	dm_hash_exit();}/** * dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers * @md: Pointer to mapped_device * @name: Buffer (size DM_NAME_LEN) for name * @uuid: Buffer (size DM_UUID_LEN) for uuid or empty string if uuid not defined */int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid){	int r = 0;	struct hash_cell *hc;	if (!md)		return -ENXIO;	dm_get(md);	down_read(&_hash_lock);	hc = dm_get_mdptr(md);	if (!hc || hc->md != md) {		r = -ENXIO;		goto out;	}	strcpy(name, hc->name);	strcpy(uuid, hc->uuid ? : "");out:	up_read(&_hash_lock);	dm_put(md);	return r;}

⌨️ 快捷键说明

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