3403 lines · 86.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2013 Shaohua Li <shli@kernel.org> * Copyright (C) 2014 Red Hat, Inc. * Copyright (C) 2015 Arrikto, Inc. * Copyright (C) 2017 Chinamobile, Inc. */ #include <linux/spinlock.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/parser.h>#include <linux/vmalloc.h>#include <linux/uio_driver.h>#include <linux/xarray.h>#include <linux/stringify.h>#include <linux/bitops.h>#include <linux/highmem.h>#include <linux/configfs.h>#include <linux/mutex.h>#include <linux/workqueue.h>#include <linux/pagemap.h>#include <net/genetlink.h>#include <scsi/scsi_common.h>#include <scsi/scsi_proto.h>#include <target/target_core_base.h>#include <target/target_core_fabric.h>#include <target/target_core_backend.h> #include <linux/target_core_user.h> /** * DOC: Userspace I/O * Userspace I/O * ------------- * * Define a shared-memory interface for LIO to pass SCSI commands and * data to userspace for processing. This is to allow backends that * are too complex for in-kernel support to be possible. * * It uses the UIO framework to do a lot of the device-creation and * introspection work for us. * * See the .h file for how the ring is laid out. Note that while the * command ring is defined, the particulars of the data area are * not. Offset values in the command entry point to other locations * internal to the mmap-ed area. There is separate space outside the * command ring for data buffers. This leaves maximum flexibility for * moving buffer allocations, or even page flipping or other * allocation techniques, without altering the command ring layout. * * SECURITY: * The user process must be assumed to be malicious. There's no way to * prevent it breaking the command ring protocol if it wants, but in * order to prevent other issues we must only ever read *data* from * the shared memory area, not offsets or sizes. This applies to * command ring entries as well as the mailbox. Extra code needed for * this may have a 'UAM' comment. */ #define TCMU_TIME_OUT (30 * MSEC_PER_SEC) /* For mailbox plus cmd ring, the size is fixed 8MB */#define MB_CMDR_SIZE_DEF (8 * 1024 * 1024)/* Offset of cmd ring is size of mailbox */#define CMDR_OFF ((__u32)sizeof(struct tcmu_mailbox))#define CMDR_SIZE_DEF (MB_CMDR_SIZE_DEF - CMDR_OFF) /* * For data area, the default block size is PAGE_SIZE and * the default total size is 256K * PAGE_SIZE. */#define DATA_PAGES_PER_BLK_DEF 1#define DATA_AREA_PAGES_DEF (256 * 1024) #define TCMU_MBS_TO_PAGES(_mbs) ((size_t)_mbs << (20 - PAGE_SHIFT))#define TCMU_PAGES_TO_MBS(_pages) (_pages >> (20 - PAGE_SHIFT)) /* * Default number of global data blocks(512K * PAGE_SIZE) * when the unmap thread will be started. */#define TCMU_GLOBAL_MAX_PAGES_DEF (512 * 1024) static u8 tcmu_kern_cmd_reply_supported;static u8 tcmu_netlink_blocked; static struct device *tcmu_root_device; struct tcmu_hba {	u32 host_id;}; #define TCMU_CONFIG_LEN 256 static DEFINE_MUTEX(tcmu_nl_cmd_mutex);static LIST_HEAD(tcmu_nl_cmd_list); struct tcmu_dev; struct tcmu_nl_cmd {	/* wake up thread waiting for reply */	struct completion complete;	struct list_head nl_list;	struct tcmu_dev *udev;	int cmd;	int status;}; struct tcmu_dev {	struct list_head node;	struct kref kref; 	struct se_device se_dev;	struct se_dev_plug se_plug; 	char *name;	struct se_hba *hba; #define TCMU_DEV_BIT_OPEN 0#define TCMU_DEV_BIT_BROKEN 1#define TCMU_DEV_BIT_BLOCKED 2#define TCMU_DEV_BIT_TMR_NOTIFY 3#define TCMU_DEV_BIT_PLUGGED 4	unsigned long flags; 	struct uio_info uio_info; 	struct inode *inode; 	uint64_t dev_size; 	struct tcmu_mailbox *mb_addr;	void *cmdr;	u32 cmdr_size;	u32 cmdr_last_cleaned;	/* Offset of data area from start of mb */	/* Must add data_off and mb_addr to get the address */	size_t data_off;	int data_area_mb;	uint32_t max_blocks;	size_t mmap_pages; 	struct mutex cmdr_lock;	struct list_head qfull_queue;	struct list_head tmr_queue; 	uint32_t dbi_max;	uint32_t dbi_thresh;	unsigned long *data_bitmap;	struct xarray data_pages;	uint32_t data_pages_per_blk;	uint32_t data_blk_size; 	struct xarray commands; 	struct timer_list cmd_timer;	unsigned int cmd_time_out;	struct list_head inflight_queue; 	struct timer_list qfull_timer;	int qfull_time_out; 	struct list_head timedout_entry; 	struct tcmu_nl_cmd curr_nl_cmd; 	char dev_config[TCMU_CONFIG_LEN]; 	int nl_reply_supported;}; #define TCMU_DEV(_se_dev) container_of(_se_dev, struct tcmu_dev, se_dev) struct tcmu_cmd {	struct se_cmd *se_cmd;	struct tcmu_dev *tcmu_dev;	struct list_head queue_entry; 	uint16_t cmd_id; 	/* Can't use se_cmd when cleaning up expired cmds, because if	   cmd has been completed then accessing se_cmd is off limits */	uint32_t dbi_cnt;	uint32_t dbi_bidi_cnt;	uint32_t dbi_cur;	uint32_t *dbi; 	uint32_t data_len_bidi; 	unsigned long deadline; #define TCMU_CMD_BIT_EXPIRED 0#define TCMU_CMD_BIT_KEEP_BUF 1	unsigned long flags;}; struct tcmu_tmr {	struct list_head queue_entry; 	uint8_t tmr_type;	uint32_t tmr_cmd_cnt;	int16_t tmr_cmd_ids[] __counted_by(tmr_cmd_cnt);}; /* * To avoid dead lock the mutex lock order should always be: * * mutex_lock(&root_udev_mutex); * ... * mutex_lock(&tcmu_dev->cmdr_lock); * mutex_unlock(&tcmu_dev->cmdr_lock); * ... * mutex_unlock(&root_udev_mutex); */static DEFINE_MUTEX(root_udev_mutex);static LIST_HEAD(root_udev); static DEFINE_SPINLOCK(timed_out_udevs_lock);static LIST_HEAD(timed_out_udevs); static struct kmem_cache *tcmu_cmd_cache; static atomic_t global_page_count = ATOMIC_INIT(0);static struct delayed_work tcmu_unmap_work;static int tcmu_global_max_pages = TCMU_GLOBAL_MAX_PAGES_DEF; static int tcmu_set_global_max_data_area(const char *str,					 const struct kernel_param *kp){	int ret, max_area_mb; 	ret = kstrtoint(str, 10, &max_area_mb);	if (ret)		return -EINVAL; 	if (max_area_mb <= 0) {		pr_err("global_max_data_area must be larger than 0.\n");		return -EINVAL;	} 	tcmu_global_max_pages = TCMU_MBS_TO_PAGES(max_area_mb);	if (atomic_read(&global_page_count) > tcmu_global_max_pages)		schedule_delayed_work(&tcmu_unmap_work, 0);	else		cancel_delayed_work_sync(&tcmu_unmap_work); 	return 0;} static int tcmu_get_global_max_data_area(char *buffer,					 const struct kernel_param *kp){	return sprintf(buffer, "%d\n", TCMU_PAGES_TO_MBS(tcmu_global_max_pages));} static const struct kernel_param_ops tcmu_global_max_data_area_op = {	.set = tcmu_set_global_max_data_area,	.get = tcmu_get_global_max_data_area,}; module_param_cb(global_max_data_area_mb, &tcmu_global_max_data_area_op, NULL,		S_IWUSR | S_IRUGO);MODULE_PARM_DESC(global_max_data_area_mb,		 "Max MBs allowed to be allocated to all the tcmu device's "		 "data areas."); static int tcmu_get_block_netlink(char *buffer,				  const struct kernel_param *kp){	return sprintf(buffer, "%s\n", tcmu_netlink_blocked ?		       "blocked" : "unblocked");} static int tcmu_set_block_netlink(const char *str,				  const struct kernel_param *kp){	int ret;	u8 val; 	ret = kstrtou8(str, 0, &val);	if (ret < 0)		return ret; 	if (val > 1) {		pr_err("Invalid block netlink value %u\n", val);		return -EINVAL;	} 	tcmu_netlink_blocked = val;	return 0;} static const struct kernel_param_ops tcmu_block_netlink_op = {	.set = tcmu_set_block_netlink,	.get = tcmu_get_block_netlink,}; module_param_cb(block_netlink, &tcmu_block_netlink_op, NULL, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(block_netlink, "Block new netlink commands."); static int tcmu_fail_netlink_cmd(struct tcmu_nl_cmd *nl_cmd){	struct tcmu_dev *udev = nl_cmd->udev; 	if (!tcmu_netlink_blocked) {		pr_err("Could not reset device's netlink interface. Netlink is not blocked.\n");		return -EBUSY;	} 	if (nl_cmd->cmd != TCMU_CMD_UNSPEC) {		pr_debug("Aborting nl cmd %d on %s\n", nl_cmd->cmd, udev->name);		nl_cmd->status = -EINTR;		list_del(&nl_cmd->nl_list);		complete(&nl_cmd->complete);	}	return 0;} static int tcmu_set_reset_netlink(const char *str,				  const struct kernel_param *kp){	struct tcmu_nl_cmd *nl_cmd, *tmp_cmd;	int ret;	u8 val; 	ret = kstrtou8(str, 0, &val);	if (ret < 0)		return ret; 	if (val != 1) {		pr_err("Invalid reset netlink value %u\n", val);		return -EINVAL;	} 	mutex_lock(&tcmu_nl_cmd_mutex);	list_for_each_entry_safe(nl_cmd, tmp_cmd, &tcmu_nl_cmd_list, nl_list) {		ret = tcmu_fail_netlink_cmd(nl_cmd);		if (ret)			break;	}	mutex_unlock(&tcmu_nl_cmd_mutex); 	return ret;} static const struct kernel_param_ops tcmu_reset_netlink_op = {	.set = tcmu_set_reset_netlink,}; module_param_cb(reset_netlink, &tcmu_reset_netlink_op, NULL, S_IWUSR);MODULE_PARM_DESC(reset_netlink, "Reset netlink commands."); /* multicast group */enum tcmu_multicast_groups {	TCMU_MCGRP_CONFIG,}; static const struct genl_multicast_group tcmu_mcgrps[] = {	[TCMU_MCGRP_CONFIG] = { .name = "config", },}; static const struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX + 1] = {	[TCMU_ATTR_DEVICE]	= { .type = NLA_STRING },	[TCMU_ATTR_MINOR]	= { .type = NLA_U32 },	[TCMU_ATTR_CMD_STATUS]	= { .type = NLA_S32 },	[TCMU_ATTR_DEVICE_ID]	= { .type = NLA_U32 },	[TCMU_ATTR_SUPP_KERN_CMD_REPLY] = { .type = NLA_U8 },}; static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd){	struct tcmu_dev *udev = NULL;	struct tcmu_nl_cmd *nl_cmd;	int dev_id, rc, ret = 0; 	if (!info->attrs[TCMU_ATTR_CMD_STATUS] ||	    !info->attrs[TCMU_ATTR_DEVICE_ID]) {		printk(KERN_ERR "TCMU_ATTR_CMD_STATUS or TCMU_ATTR_DEVICE_ID not set, doing nothing\n");		return -EINVAL;        } 	dev_id = nla_get_u32(info->attrs[TCMU_ATTR_DEVICE_ID]);	rc = nla_get_s32(info->attrs[TCMU_ATTR_CMD_STATUS]); 	mutex_lock(&tcmu_nl_cmd_mutex);	list_for_each_entry(nl_cmd, &tcmu_nl_cmd_list, nl_list) {		if (nl_cmd->udev->se_dev.dev_index == dev_id) {			udev = nl_cmd->udev;			break;		}	} 	if (!udev) {		pr_err("tcmu nl cmd %u/%d completion could not find device with dev id %u.\n",		       completed_cmd, rc, dev_id);		ret = -ENODEV;		goto unlock;	}	list_del(&nl_cmd->nl_list); 	pr_debug("%s genl cmd done got id %d curr %d done %d rc %d stat %d\n",		 udev->name, dev_id, nl_cmd->cmd, completed_cmd, rc,		 nl_cmd->status); 	if (nl_cmd->cmd != completed_cmd) {		pr_err("Mismatched commands on %s (Expecting reply for %d. Current %d).\n",		       udev->name, completed_cmd, nl_cmd->cmd);		ret = -EINVAL;		goto unlock;	} 	nl_cmd->status = rc;	complete(&nl_cmd->complete);unlock:	mutex_unlock(&tcmu_nl_cmd_mutex);	return ret;} static int tcmu_genl_rm_dev_done(struct sk_buff *skb, struct genl_info *info){	return tcmu_genl_cmd_done(info, TCMU_CMD_REMOVED_DEVICE);} static int tcmu_genl_add_dev_done(struct sk_buff *skb, struct genl_info *info){	return tcmu_genl_cmd_done(info, TCMU_CMD_ADDED_DEVICE);} static int tcmu_genl_reconfig_dev_done(struct sk_buff *skb,				       struct genl_info *info){	return tcmu_genl_cmd_done(info, TCMU_CMD_RECONFIG_DEVICE);} static int tcmu_genl_set_features(struct sk_buff *skb, struct genl_info *info){	if (info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]) {		tcmu_kern_cmd_reply_supported  =			nla_get_u8(info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]);		printk(KERN_INFO "tcmu daemon: command reply support %u.\n",		       tcmu_kern_cmd_reply_supported);	} 	return 0;} static const struct genl_small_ops tcmu_genl_ops[] = {	{		.cmd	= TCMU_CMD_SET_FEATURES,		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,		.flags	= GENL_ADMIN_PERM,		.doit	= tcmu_genl_set_features,	},	{		.cmd	= TCMU_CMD_ADDED_DEVICE_DONE,		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,		.flags	= GENL_ADMIN_PERM,		.doit	= tcmu_genl_add_dev_done,	},	{		.cmd	= TCMU_CMD_REMOVED_DEVICE_DONE,		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,		.flags	= GENL_ADMIN_PERM,		.doit	= tcmu_genl_rm_dev_done,	},	{		.cmd	= TCMU_CMD_RECONFIG_DEVICE_DONE,		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,		.flags	= GENL_ADMIN_PERM,		.doit	= tcmu_genl_reconfig_dev_done,	},}; /* Our generic netlink family */static struct genl_family tcmu_genl_family __ro_after_init = {	.module = THIS_MODULE,	.hdrsize = 0,	.name = "TCM-USER",	.version = 2,	.maxattr = TCMU_ATTR_MAX,	.policy = tcmu_attr_policy,	.mcgrps = tcmu_mcgrps,	.n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),	.netnsok = true,	.small_ops = tcmu_genl_ops,	.n_small_ops = ARRAY_SIZE(tcmu_genl_ops),	.resv_start_op = TCMU_CMD_SET_FEATURES + 1,}; #define tcmu_cmd_set_dbi_cur(cmd, index) ((cmd)->dbi_cur = (index))#define tcmu_cmd_reset_dbi_cur(cmd) tcmu_cmd_set_dbi_cur(cmd, 0)#define tcmu_cmd_set_dbi(cmd, index) ((cmd)->dbi[(cmd)->dbi_cur++] = (index))#define tcmu_cmd_get_dbi(cmd) ((cmd)->dbi[(cmd)->dbi_cur++]) static void tcmu_cmd_free_data(struct tcmu_cmd *tcmu_cmd, uint32_t len){	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;	uint32_t i;

Lines 1–500 of 3403.