target/user: Disallow full passthrough (pass_level=0)

TCMU requires more work to correctly handle both user handlers that want
all SCSI commands (pass_level=0) for a se_device, and also handlers that
just want I/O commands and let the others be emulated by the kernel
(pass_level=1). Only support the latter for now.

For full passthrough, we will need to support a second se_subsystem_api
template, due to configfs attributes being different between the two modes.
Thus pass_level is extraneous, and we can remove it.

The ABI break for TCMU v2 is already applied for this release, so it's
best to do this now to avoid another ABI break in the future.

Signed-off-by: Andy Grover <agrover@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Andy Grover 2015-05-01 10:43:45 -07:00 коммит произвёл Nicholas Bellinger
Родитель a928d28d44
Коммит 8ee83a747a
2 изменённых файлов: 10 добавлений и 76 удалений

Просмотреть файл

@ -15,7 +15,7 @@ Contents:
a) Discovering and configuring TCMU uio devices
b) Waiting for events on the device(s)
c) Managing the command ring
3) Command filtering and pass_level
3) Command filtering
4) A final note
@ -360,17 +360,13 @@ int handle_device_events(int fd, void *map)
}
Command filtering and pass_level
--------------------------------
Command filtering
-----------------
TCMU supports a "pass_level" option with valid values of 0 or 1. When
the value is 0 (the default), nearly all SCSI commands received for
the device are passed through to the handler. This allows maximum
flexibility but increases the amount of code required by the handler,
to support all mandatory SCSI commands. If pass_level is set to 1,
then only IO-related commands are presented, and the rest are handled
by LIO's in-kernel command emulation. The commands presented at level
1 include all versions of:
Initial TCMU support is for a filtered commandset. Only IO-related
commands are presented to userspace, and the rest are handled by LIO's
in-kernel command emulation. The commands presented are all versions
of:
READ
WRITE

Просмотреть файл

@ -71,13 +71,6 @@ struct tcmu_hba {
u32 host_id;
};
/* User wants all cmds or just some */
enum passthru_level {
TCMU_PASS_ALL = 0,
TCMU_PASS_IO,
TCMU_PASS_INVALID,
};
#define TCMU_CONFIG_LEN 256
struct tcmu_dev {
@ -89,7 +82,6 @@ struct tcmu_dev {
#define TCMU_DEV_BIT_OPEN 0
#define TCMU_DEV_BIT_BROKEN 1
unsigned long flags;
enum passthru_level pass_level;
struct uio_info uio_info;
@ -683,8 +675,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)
setup_timer(&udev->timeout, tcmu_device_timedout,
(unsigned long)udev);
udev->pass_level = TCMU_PASS_ALL;
return &udev->se_dev;
}
@ -948,13 +938,12 @@ static void tcmu_free_device(struct se_device *dev)
}
enum {
Opt_dev_config, Opt_dev_size, Opt_err, Opt_pass_level,
Opt_dev_config, Opt_dev_size, Opt_err,
};
static match_table_t tokens = {
{Opt_dev_config, "dev_config=%s"},
{Opt_dev_size, "dev_size=%u"},
{Opt_pass_level, "pass_level=%u"},
{Opt_err, NULL}
};
@ -965,7 +954,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
char *orig, *ptr, *opts, *arg_p;
substring_t args[MAX_OPT_ARGS];
int ret = 0, token;
int arg;
opts = kstrdup(page, GFP_KERNEL);
if (!opts)
@ -998,16 +986,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
if (ret < 0)
pr_err("kstrtoul() failed for dev_size=\n");
break;
case Opt_pass_level:
match_int(args, &arg);
if (arg >= TCMU_PASS_INVALID) {
pr_warn("TCMU: Invalid pass_level: %d\n", arg);
break;
}
pr_debug("TCMU: Setting pass_level to %d\n", arg);
udev->pass_level = arg;
break;
default:
break;
}
@ -1024,8 +1002,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b)
bl = sprintf(b + bl, "Config: %s ",
udev->dev_config[0] ? udev->dev_config : "NULL");
bl += sprintf(b + bl, "Size: %zu PassLevel: %u\n",
udev->dev_size, udev->pass_level);
bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size);
return bl;
}
@ -1074,46 +1051,7 @@ static struct sbc_ops tcmu_sbc_ops = {
static sense_reason_t
tcmu_parse_cdb(struct se_cmd *cmd)
{
unsigned char *cdb = cmd->t_task_cdb;
struct tcmu_dev *udev = TCMU_DEV(cmd->se_dev);
sense_reason_t ret;
switch (udev->pass_level) {
case TCMU_PASS_ALL:
/* We're just like pscsi, then */
/*
* For REPORT LUNS we always need to emulate the response, for everything
* else, pass it up.
*/
switch (cdb[0]) {
case REPORT_LUNS:
cmd->execute_cmd = spc_emulate_report_luns;
break;
case READ_6:
case READ_10:
case READ_12:
case READ_16:
case WRITE_6:
case WRITE_10:
case WRITE_12:
case WRITE_16:
case WRITE_VERIFY:
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
/* FALLTHROUGH */
default:
cmd->execute_cmd = tcmu_pass_op;
}
ret = TCM_NO_SENSE;
break;
case TCMU_PASS_IO:
ret = sbc_parse_cdb(cmd, &tcmu_sbc_ops);
break;
default:
pr_err("Unknown tcm-user pass level %d\n", udev->pass_level);
ret = TCM_CHECK_CONDITION_ABORT_CMD;
}
return ret;
return sbc_parse_cdb(cmd, &tcmu_sbc_ops);
}
DEF_TB_DEFAULT_ATTRIBS(tcmu);