diff --git a/scst/README b/scst/README index 1f42e569e..e41044892 100644 --- a/scst/README +++ b/scst/README @@ -982,7 +982,7 @@ Intended to be used for performance measurements at the same way as blocksize, read_only, removable, tst. See vdisk_fileio above for description of those parameters. -vdisk_nullio also has extra attribute: +vdisk_nullio devices have the following two additional attributes: - dummy - if this flag is set, LUNs corresponding to this device will not appear at the initiator side. This is because SCST will set the @@ -991,6 +991,13 @@ vdisk_nullio also has extra attribute: See also SPC-4 for more information. It is designed to be used as a "dummy" placeholder on LUN 0, if LUN 0 is not desired. + - read_zero - if this flag is set, reading from a vdisk_nullio device + returns a buffer filled with byte 0x00. If this flag is cleared + (which is the default behavior), the buffer returned to the + initiator is not cleared. Although this results in slightly faster + operation this is a security hole since any data that is present in + kernel memory can be returned to the initiator. + Handler vcdrom allows emulation of a virtual CDROM device using an ISO file as backend. It has only single parameter: tst. diff --git a/scst/README_in-tree b/scst/README_in-tree index 739647867..18b10cded 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -840,7 +840,7 @@ Intended to be used for performance measurements at the same way as blocksize, read_only, removable, tst. See vdisk_fileio above for description of those parameters. -vdisk_nullio also has extra attribute: +vdisk_nullio devices have the following two additional attributes: - dummy - if this flag is set, LUNs corresponding to this device will not appear at the initiator side. This is because SCST will set the @@ -849,6 +849,13 @@ vdisk_nullio also has extra attribute: See also SPC-4 for more information. It is designed to be used as a "dummy" placeholder on LUN 0, if LUN 0 is not desired. + - read_zero - if this flag is set, reading from a vdisk_nullio device + returns a buffer filled with byte 0x00. If this flag is cleared + (which is the default behavior), the buffer returned to the + initiator is not cleared. Although this results in slightly faster + operation this is a security hole since any data that is present in + kernel memory can be returned to the initiator. + Handler vcdrom allows emulation of a virtual CDROM device using an ISO file as backend. It has only single parameter: tst. diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 5f87c8e98..0fc593860 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -109,6 +109,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = { #define DEF_NV_CACHE 0 #define DEF_O_DIRECT 0 #define DEF_DUMMY 0 +#define DEF_READ_ZERO 0 #define DEF_REMOVABLE 0 #define DEF_ROTATIONAL 1 #define DEF_THIN_PROVISIONED 0 @@ -160,6 +161,7 @@ struct scst_vdisk_dev { unsigned int blockio:1; unsigned int cdrom_empty:1; unsigned int dummy:1; + unsigned int read_zero:1; unsigned int removable:1; unsigned int thin_provisioned:1; unsigned int thin_provisioned_manually_set:1; @@ -263,7 +265,8 @@ static int vcdrom_parse(struct scst_cmd *); static int non_fileio_parse(struct scst_cmd *); static int vdisk_exec(struct scst_cmd *cmd); static int vcdrom_exec(struct scst_cmd *cmd); -static int non_fileio_exec(struct scst_cmd *cmd); +static int blockio_exec(struct scst_cmd *cmd); +static int nullio_exec(struct scst_cmd *cmd); static void fileio_on_free_cmd(struct scst_cmd *cmd); static enum compl_status_e nullio_exec_read(struct vdisk_cmd_params *p); static enum compl_status_e blockio_exec_read(struct vdisk_cmd_params *p); @@ -349,6 +352,10 @@ static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_dummy_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_rz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_rz_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_filename_show(struct kobject *kobj, @@ -421,6 +428,9 @@ static struct kobj_attribute vdisk_o_direct_attr = __ATTR(o_direct, S_IRUGO, vdisk_sysfs_o_direct_show, NULL); static struct kobj_attribute vdev_dummy_attr = __ATTR(dummy, S_IRUGO, vdev_sysfs_dummy_show, NULL); +static struct kobj_attribute vdev_read_zero_attr = + __ATTR(read_zero, S_IWUSR|S_IRUGO, vdev_sysfs_rz_show, + vdev_sysfs_rz_store); static struct kobj_attribute vdisk_removable_attr = __ATTR(removable, S_IRUGO, vdisk_sysfs_removable_show, NULL); static struct kobj_attribute vdisk_filename_attr = @@ -516,6 +526,7 @@ static const struct attribute *vdisk_nullio_attrs[] = { &vdisk_rd_only_attr.attr, &vdisk_tst_attr.attr, &vdev_dummy_attr.attr, + &vdev_read_zero_attr.attr, &vdisk_removable_attr.attr, &vdev_t10_vend_id_attr.attr, &vdev_vend_specific_id_attr.attr, @@ -634,7 +645,7 @@ static struct scst_dev_type vdisk_blk_devtype = { .attach_tgt = vdisk_attach_tgt, .detach_tgt = vdisk_detach_tgt, .parse = non_fileio_parse, - .exec = non_fileio_exec, + .exec = blockio_exec, .task_mgmt_fn_done = vdisk_task_mgmt_fn_done, .get_supported_opcodes = vdisk_get_supported_opcodes, .devt_priv = (void *)blockio_ops, @@ -677,7 +688,7 @@ static struct scst_dev_type vdisk_null_devtype = { .attach_tgt = vdisk_attach_tgt, .detach_tgt = vdisk_detach_tgt, .parse = non_fileio_parse, - .exec = non_fileio_exec, + .exec = nullio_exec, .task_mgmt_fn_done = vdisk_task_mgmt_fn_done, .devt_priv = (void *)nullio_ops, .get_supported_opcodes = vdisk_get_supported_opcodes, @@ -2847,8 +2858,7 @@ out: return; } -/* blockio and nullio */ -static int non_fileio_exec(struct scst_cmd *cmd) +static int blockio_exec(struct scst_cmd *cmd) { struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv; const vdisk_op_fn *ops = virt_dev->vdev_devt->devt_priv; @@ -2875,6 +2885,31 @@ err: goto out; } +static int nullio_exec(struct scst_cmd *cmd) +{ + struct scst_device *dev = cmd->dev; + struct scst_vdisk_dev *virt_dev = dev->dh_priv; + + if (unlikely(virt_dev->read_zero && + (cmd->data_direction == SCST_DATA_READ || + cmd->data_direction == SCST_DATA_BIDI))) { + struct scatterlist *sge; + int i; + void *p; + + for_each_sg(cmd->sg, sge, cmd->sg_cnt, i) { + p = kmap(sg_page(sge)); + if (sge->offset == 0 && sge->length == PAGE_SIZE) + clear_page(p); + else + memset(p + sge->offset, 0, sge->length); + kunmap(p); + } + } + + return blockio_exec(cmd); +} + static int vcdrom_exec(struct scst_cmd *cmd) { int res = SCST_EXEC_COMPLETED; @@ -5942,6 +5977,7 @@ static int vdev_create(struct scst_dev_type *devt, virt_dev->rd_only = DEF_RD_ONLY; virt_dev->dummy = DEF_DUMMY; + virt_dev->read_zero = DEF_READ_ZERO; virt_dev->removable = DEF_REMOVABLE; virt_dev->rotational = DEF_ROTATIONAL; virt_dev->thin_provisioned = DEF_THIN_PROVISIONED; @@ -7012,6 +7048,51 @@ static ssize_t vdev_sysfs_dummy_show(struct kobject *kobj, virt_dev->dummy != DEF_DUMMY ? SCST_SYSFS_KEY_MARK "\n" : ""); } +static ssize_t vdev_sysfs_rz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, + dev_kobj); + struct scst_vdisk_dev *virt_dev = dev->dh_priv; + bool read_zero = virt_dev->read_zero; + + return sprintf(buf, "%d\n%s", read_zero, read_zero != DEF_READ_ZERO ? + SCST_SYSFS_KEY_MARK "\n" : ""); +} + +static ssize_t vdev_sysfs_rz_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, + dev_kobj); + struct scst_vdisk_dev *virt_dev = dev->dh_priv; + long read_zero; + int res; + char ch[16]; + + sprintf(ch, "%.*s", min_t(int, sizeof(ch) - 1, count), buf); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + res = kstrtol(ch, 0, &read_zero); +#else + res = strict_strtol(ch, 0, &read_zero); +#endif + if (res) + goto out; + res = -EINVAL; + if (read_zero != 0 && read_zero != 1) + goto out; + + spin_lock(&virt_dev->flags_lock); + virt_dev->read_zero = read_zero; + spin_unlock(&virt_dev->flags_lock); + + res = count; + +out: + return res; +} + static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {