From 4e1dc1b526bc03852ffde680c707e70ee29cc79e Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 20 Dec 2016 06:07:55 +0000 Subject: [PATCH] scst: improve thin provisioning support This patch adds gen_tp_soft_threshold_reached_UA attribute for thin provisioned devices that allows to generate THIN PROVISIONING SOFT THRESHOLD REACHED Unit Attention. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7071 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/README | 10 ++++- scst/README_in-tree | 10 ++++- scst/include/scst.h | 2 + scst/include/scst_const.h | 4 +- scst/src/dev_handlers/scst_vdisk.c | 67 ++++++++++++++++++++++++++---- scst/src/scst_lib.c | 17 ++++++++ 6 files changed, 97 insertions(+), 13 deletions(-) diff --git a/scst/README b/scst/README index 6355425c9..acf646832 100644 --- a/scst/README +++ b/scst/README @@ -1246,6 +1246,11 @@ Each vdisk_fileio's device has the following attributes in - thin_provisioned - contains thin provisioning status of this virtual device. + - gen_tp_soft_threshold_reached_UA - for thin provisioned devices + writing of anything into this write-only attribute will generate THIN + PROVISIONING SOFT THRESHOLD REACHED Unit Attention to all connected + to this device initiators. + - removable - contains removable status of this virtual device. - rotational - contains rotational status of this virtual device. @@ -1347,8 +1352,9 @@ For example: Each vdisk_blockio's device has the following attributes in /sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache, read_only, removable, resync_size, rotational, size_mb, t10_dev_id, -thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See -above description of those parameters. +thin_provisioned, gen_tp_soft_threshold_reached_UA, threads_num, +threads_pool_type, tst, type, usn. See above description of those +parameters. Each vdisk_nullio's device has the following attributes in /sys/kernel/scst_tgt/devices/device_name: blocksize, read_only, diff --git a/scst/README_in-tree b/scst/README_in-tree index 65053019d..66b6e5ba6 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -1106,6 +1106,11 @@ Each vdisk_fileio's device has the following attributes in - thin_provisioned - contains thin provisioning status of this virtual device. + - gen_tp_soft_threshold_reached_UA - for thin provisioned devices + writing of anything into this write-only attribute will generate THIN + PROVISIONING SOFT THRESHOLD REACHED Unit Attention to all connected + to this device initiators. + - removable - contains removable status of this virtual device. - rotational - contains rotational status of this virtual device. @@ -1205,8 +1210,9 @@ For example: Each vdisk_blockio's device has the following attributes in /sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache, read_only, removable, resync_size, rotational, size_mb, t10_dev_id, -thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See -above description of those parameters. +thin_provisioned, gen_tp_soft_threshold_reached_UA, threads_num, +threads_pool_type, tst, type, usn. See above description of those +parameters. Each vdisk_nullio's device has the following attributes in /sys/kernel/scst_tgt/devices/device_name: blocksize, read_only, diff --git a/scst/include/scst.h b/scst/include/scst.h index 2ea9ffa32..33b5c6159 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -5665,6 +5665,8 @@ void scst_path_put(struct nameidata *nd); #endif int scst_remove_file(const char *name); +void scst_set_tp_soft_threshold_reached_UA(struct scst_tgt_dev *tgt_dev); + int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode, const char *cl_dev_id); int scst_pr_init_dev(struct scst_device *dev); diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index eee9ab793..a8f2824a7 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -337,11 +337,13 @@ static inline int scst_sense_response_code(const uint8_t *sense) #define scst_sense_asym_access_state_changed UNIT_ATTENTION, 0x2A, 0x06 #define scst_sense_capacity_data_changed UNIT_ATTENTION, 0x2A, 0x9 #define scst_sense_cleared_by_another_ini_UA UNIT_ATTENTION, 0x2F, 0 +#define scst_sense_tp_soft_threshold_reached UNIT_ATTENTION, 0x38, 0x7 #define scst_sense_inquiry_data_changed UNIT_ATTENTION, 0x3F, 0x3 #define scst_sense_reported_luns_data_changed UNIT_ATTENTION, 0x3F, 0xE /* DATA_PROTECT is 7 */ -#define scst_sense_data_protect DATA_PROTECT, 0x27, 0 +#define scst_sense_data_protect DATA_PROTECT, 0x00, 0 +#define scst_space_allocation_failed_write_protect DATA_PROTECT, 0x27, 7 /* ABORTED_COMMAND is 0xb */ #define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0 diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 22bc8ac75..7e6fb39dc 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -399,6 +399,8 @@ static ssize_t vdisk_sysfs_wt_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdisk_sysfs_tp_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static ssize_t vdisk_sysfs_gen_tp_soft_threshold_reached_UA(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdisk_sysfs_tst_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdisk_sysfs_rotational_show(struct kobject *kobj, @@ -495,6 +497,9 @@ static struct kobj_attribute vdisk_wt_attr = __ATTR(write_through, S_IRUGO, vdisk_sysfs_wt_show, NULL); static struct kobj_attribute vdisk_tp_attr = __ATTR(thin_provisioned, S_IRUGO, vdisk_sysfs_tp_show, NULL); +static struct kobj_attribute gen_tp_soft_threshold_reached_UA_attr = + __ATTR(gen_tp_soft_threshold_reached_UA, S_IWUSR, NULL, + vdisk_sysfs_gen_tp_soft_threshold_reached_UA); static struct kobj_attribute vdisk_tst_attr = __ATTR(tst, S_IRUGO, vdisk_sysfs_tst_show, NULL); static struct kobj_attribute vdisk_rotational_attr = @@ -1054,6 +1059,17 @@ check: if (virt_dev->thin_provisioned) { int block_shift = virt_dev->dev->block_shift; +#ifndef CONFIG_SCST_PROC + int rc; + + rc = sysfs_create_file(&virt_dev->dev->dev_kobj, + &gen_tp_soft_threshold_reached_UA_attr.attr); + if (rc != 0) { + PRINT_ERROR("Can't create attr %s for dev %s", + gen_tp_soft_threshold_reached_UA_attr.attr.name, + virt_dev->name); + } +#endif if (virt_dev->blockio) { struct request_queue *q; @@ -6362,10 +6378,13 @@ restart: full_len); if (err == -EAGAIN) scst_set_busy(cmd); - else { + else if (err == -ENOSPC) { + WARN_ON(!virt_dev->thin_provisioned); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_space_allocation_failed_write_protect)); + } else scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_write_error)); - } goto out_set_fs; } else if (err < full_len) { /* @@ -6520,15 +6539,21 @@ static void blockio_endio(struct bio *bio) spin_lock_irqsave(&vdev_err_lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) - if (bio->bi_rw & (1 << BIO_RW)) + if (bio->bi_rw & (1 << BIO_RW)) { #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) - if (bio->bi_rw & REQ_WRITE) + if (bio->bi_rw & REQ_WRITE) { #else - if (op_is_write(bio_op(bio))) + if (op_is_write(bio_op(bio))) { #endif - scst_set_cmd_error(blockio_work->cmd, - SCST_LOAD_SENSE(scst_sense_write_error)); - else + if (error == -ENOSPC) { + struct scst_vdisk_dev *virt_dev = blockio_work->cmd->dev->dh_priv; + WARN_ON(!virt_dev->thin_provisioned); + scst_set_cmd_error(blockio_work->cmd, + SCST_LOAD_SENSE(scst_space_allocation_failed_write_protect)); + } else + scst_set_cmd_error(blockio_work->cmd, + SCST_LOAD_SENSE(scst_sense_write_error)); + } else scst_set_cmd_error(blockio_work->cmd, SCST_LOAD_SENSE(scst_sense_read_error)); @@ -8902,6 +8927,32 @@ static ssize_t vdisk_sysfs_tp_show(struct kobject *kobj, return pos; } +static ssize_t vdisk_sysfs_gen_tp_soft_threshold_reached_UA(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + struct scst_tgt_dev *tgt_dev; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + + if (!virt_dev->thin_provisioned) + return -EINVAL; + + spin_lock_bh(&dev->dev_lock); + list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, + dev_tgt_dev_list_entry) { + scst_set_tp_soft_threshold_reached_UA(tgt_dev); + } + spin_unlock_bh(&dev->dev_lock); + + TRACE_EXIT_RES(count); + return count; +} + static ssize_t vdisk_sysfs_expl_alua_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index ac83cac21..9daf5843c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -12813,6 +12813,23 @@ void scst_dev_check_set_UA(struct scst_device *dev, return; } +void scst_set_tp_soft_threshold_reached_UA(struct scst_tgt_dev *tgt_dev) +{ + uint8_t sense[SCST_STANDARD_SENSE_LEN]; + int len; + + TRACE_ENTRY(); + + len = scst_set_sense(sense, sizeof(sense), tgt_dev->dev->d_sense, + SCST_LOAD_SENSE(scst_sense_tp_soft_threshold_reached)); + + scst_check_set_UA(tgt_dev, sense, len, 0); + + TRACE_EXIT(); + return; +} +EXPORT_SYMBOL_GPL(scst_set_tp_soft_threshold_reached_UA); + /* Called under tgt_dev_lock or when tgt_dev is unused */ static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev) {