From c4d0b670e92d5cb2e01a688408616c9fdcd0e4ef Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 6 Oct 2018 21:41:30 +0000 Subject: [PATCH 1/4] scst: Fix spelling of 'delimiter' in source code comments git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7494 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index c92d4a26a..5dfc9f770 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -14063,8 +14063,8 @@ EXPORT_SYMBOL(scst_reassign_retained_sess_states); * scst_get_next_lexem() - parse and return next lexem in the string * * Returns pointer to the next lexem from token_str skipping - * spaces and '=' character and using them then as a delimeter. Content - * of token_str is modified by setting '\0' at the delimeter's position. + * spaces and '=' character and using them then as a delimiter. Content + * of token_str is modified by setting '\0' at the delimiter's position. */ char *scst_get_next_lexem(char **token_str) { @@ -14107,8 +14107,8 @@ EXPORT_SYMBOL_GPL(scst_restore_token_str); * scst_get_next_token_str() - parse and return next token * * This function returns pointer to the next token strings from input_str - * using '\n', ';' and '\0' as a delimeter. Content of input_str is - * modified by setting '\0' at the delimeter's position. + * using '\n', ';' and '\0' as a delimiter. Content of input_str is + * modified by setting '\0' at the delimiter's position. */ char *scst_get_next_token_str(char **input_str) { From 090252f695f30755ccab5717e3b366b13eb2eb8b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 6 Oct 2018 21:42:02 +0000 Subject: [PATCH 2/4] cst/include/backport.h: Add a printk_once() backport This patch is only relevant for regression testing SCST against kernel 2.6.29 or older. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7495 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/backport.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scst/include/backport.h b/scst/include/backport.h index 3455f3769..b3af751fb 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -569,6 +569,21 @@ static inline long get_user_pages_backport(unsigned long start, #endif #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) */ +/* See also commit f036be96dd9c ("printk: introduce printk_once()") */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) +#define printk_once(fmt, ...) \ +({ \ + static bool __print_once __read_mostly; \ + bool __ret_print_once = !__print_once; \ + \ + if (!__print_once) { \ + __print_once = true; \ + printk(fmt, ##__VA_ARGS__); \ + } \ + unlikely(__ret_print_once); \ +}) +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) /* * See also patch "kernel.h: add pr_warn for symmetry to dev_warn, From 5b565802530dec35b6a79623032251b3f82fe13a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 6 Oct 2018 21:57:50 +0000 Subject: [PATCH 3/4] scst: Introduce __scst_unblock_aborted_cmds() This patch does not change any functionality but makes it easier for static analyzers like sparse and smatch to verify locking in scst_unblock_aborted_cmds(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7496 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_lib.c | 4 ++-- scst/src/scst_priv.h | 5 +++-- scst/src/scst_targ.c | 38 ++++++++++++++++++++------------------ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 5dfc9f770..fd7d4562a 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -13050,7 +13050,7 @@ void scst_dev_check_set_UA(struct scst_device *dev, scst_res_unlock(dev, &lksb); if (rc) - scst_unblock_aborted_cmds(NULL, NULL, dev, false); + scst_unblock_aborted_cmds(NULL, NULL, dev); return; } @@ -13724,7 +13724,7 @@ static void scst_process_qerr(struct scst_cmd *cmd) spin_unlock_bh(&dev->dev_lock); if (unblock) - scst_unblock_aborted_cmds(cmd->tgt, cmd->sess, dev, false); + scst_unblock_aborted_cmds(cmd->tgt, cmd->sess, dev); TRACE_EXIT(); return; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 603c78259..79c02cbbf 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -724,9 +724,10 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd, void scst_process_reset(struct scst_device *dev, struct scst_session *originator, struct scst_cmd *exclude_cmd, struct scst_mgmt_cmd *mcmd, bool setUA); +void __scst_unblock_aborted_cmds(const struct scst_tgt *tgt, + const struct scst_session *sess, const struct scst_device *device); void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, - const struct scst_session *sess, const struct scst_device *device, - bool scst_mutex_held); + const struct scst_session *sess, const struct scst_device *device); void scst_clear_aca(struct scst_tgt_dev *tgt_dev, bool other_ini); bool scst_is_ua_global(const uint8_t *sense, int len); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index f0441eb9b..2aab40bef 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -6370,18 +6370,14 @@ static bool __scst_check_unblock_aborted_cmd(struct scst_cmd *cmd, return res; } -void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, - const struct scst_session *sess, const struct scst_device *device, - bool scst_mutex_held) +void __scst_unblock_aborted_cmds(const struct scst_tgt *tgt, + const struct scst_session *sess, const struct scst_device *device) { struct scst_device *dev; TRACE_ENTRY(); - if (!scst_mutex_held) - mutex_lock(&scst_mutex); - else - lockdep_assert_held(&scst_mutex); + lockdep_assert_held(&scst_mutex); list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { struct scst_cmd *cmd, *tcmd; @@ -6435,13 +6431,18 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, local_irq_enable_nort(); } - if (!scst_mutex_held) - mutex_unlock(&scst_mutex); - TRACE_EXIT(); return; } +void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, + const struct scst_session *sess, const struct scst_device *device) +{ + mutex_lock(&scst_mutex); + __scst_unblock_aborted_cmds(tgt, sess, device); + mutex_unlock(&scst_mutex); +} + static void __scst_abort_task_set(struct scst_mgmt_cmd *mcmd, struct scst_tgt_dev *tgt_dev) { @@ -6520,7 +6521,8 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd) tm_dbg_task_mgmt(mcmd->mcmd_tgt_dev->dev, "ABORT TASK SET/PR ABORT", 0); - scst_unblock_aborted_cmds(tgt_dev->sess->tgt, tgt_dev->sess, tgt_dev->dev, false); + scst_unblock_aborted_cmds(tgt_dev->sess->tgt, tgt_dev->sess, + tgt_dev->dev); scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev); @@ -6608,7 +6610,7 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd) tm_dbg_task_mgmt(mcmd->mcmd_tgt_dev->dev, "CLEAR TASK SET", 0); - scst_unblock_aborted_cmds(NULL, NULL, dev, true); + __scst_unblock_aborted_cmds(NULL, NULL, dev); if (!dev->tas) { uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; @@ -6803,7 +6805,7 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd) list_add_tail(&dev->tm_dev_list_entry, &host_devs); } - scst_unblock_aborted_cmds(NULL, NULL, NULL, true); + __scst_unblock_aborted_cmds(NULL, NULL, NULL); /* * We suppose here that for all commands that already on devices @@ -6909,7 +6911,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd) dev->scsi_dev->was_reset = 0; } - scst_unblock_aborted_cmds(NULL, NULL, dev, false); + scst_unblock_aborted_cmds(NULL, NULL, dev); tm_dbg_task_mgmt(mcmd->mcmd_tgt_dev->dev, "LUN RESET", 0); @@ -6986,7 +6988,7 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd, } } - scst_unblock_aborted_cmds(NULL, sess, NULL, true); + __scst_unblock_aborted_cmds(NULL, sess, NULL); mutex_unlock(&scst_mutex); @@ -7070,7 +7072,7 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd, } } - scst_unblock_aborted_cmds(tgt, NULL, NULL, true); + __scst_unblock_aborted_cmds(tgt, NULL, NULL); mutex_unlock(&scst_mutex); @@ -7110,7 +7112,7 @@ static int scst_abort_task(struct scst_mgmt_cmd *mcmd) scst_abort_cmd(cmd, mcmd, 0, 1); spin_unlock_irq(&cmd->sess->sess_list_lock); - scst_unblock_aborted_cmds(cmd->tgt, cmd->sess, cmd->dev, false); + scst_unblock_aborted_cmds(cmd->tgt, cmd->sess, cmd->dev); } res = scst_set_mcmd_next_state(mcmd); @@ -7219,7 +7221,7 @@ static int scst_clear_aca_mcmd(struct scst_mgmt_cmd *mcmd) scst_make_deferred_commands_active(order_data); scst_unblock_aborted_cmds(mcmd_tgt_dev->sess->tgt, mcmd_tgt_dev->sess, - mcmd_tgt_dev->dev, false); + mcmd_tgt_dev->dev); out_state: res = scst_set_mcmd_next_state(mcmd); From a1c2a08d95f7bdf3c7acf37b6a83126c63c68503 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 6 Oct 2018 21:59:54 +0000 Subject: [PATCH 4/4] scst_vdisk: Make the filename modifiable When VAAI support is not needed can be convenient to use the vdisk_blockio handler to handle I/O redirection between nodes in a H.A. setup. Making the filename modifiable allows to keep the LUN associations of an SCST device that is used for I/O redirection in such a setup. This is a slightly modified version of a patch provided by Marc Smith . git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7497 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 106 ++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 7af89680b..23185ba85 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -443,6 +443,8 @@ 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, struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_filename_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdev_sysfs_cluster_mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_cluster_mode_store(struct kobject *kobj, @@ -546,7 +548,8 @@ static struct kobj_attribute vdev_read_zero_attr = static struct kobj_attribute vdisk_removable_attr = __ATTR(removable, S_IRUGO, vdisk_sysfs_removable_show, NULL); static struct kobj_attribute vdisk_filename_attr = - __ATTR(filename, S_IRUGO, vdev_sysfs_filename_show, NULL); + __ATTR(filename, S_IWUSR|S_IRUGO, vdev_sysfs_filename_show, + vdev_sysfs_filename_store); static struct kobj_attribute vdisk_cluster_mode_attr = __ATTR(cluster_mode, S_IWUSR|S_IRUGO, vdev_sysfs_cluster_mode_show, vdev_sysfs_cluster_mode_store); @@ -9491,6 +9494,107 @@ out: return res; } +static int vdev_sysfs_process_filename_store(struct scst_sysfs_work_item *work) +{ + struct scst_device *dev = work->dev; + struct scst_vdisk_dev *virt_dev; + int length = strlen(work->buf); + char *p, *fn; + const char *filename = NULL; + int res; + + res = mutex_lock_interruptible(&scst_mutex); + if (res) + goto out; + + res = -EINVAL; + + /* Serialize against vdisk_open_fd() and vdisk_close_fd() calls. */ + scst_alua_lock(); + + /* + * This is safe since we hold a reference on dev_kobj and since + * scst_assign_dev_handler() waits until all dev_kobj references + * have been dropped before invoking .detach(). + */ + virt_dev = dev->dh_priv; + if (virt_dev->dev_active) { + PRINT_ERROR("vdev %s: can't change the filename because the device is still active", + dev->virt_name); + goto unlock; + } + + p = work->buf; + while (isspace(*p) && *p) + p++; + if (*p == '\0') { + PRINT_ERROR("Filename is missing"); + goto unlock; + } + filename = p; + p = &work->buf[length - 1]; + while (isspace(*p)) + p--; + *(p + 1) = '\0'; + if (*filename != '/') { + PRINT_ERROR("Path \"%s\" is not absolute", filename); + goto unlock; + } + fn = kstrdup(filename, GFP_KERNEL); + if (fn == NULL) { + PRINT_ERROR("Filename allocation failed"); + goto unlock; + } + swap(virt_dev->filename, fn); + kfree(fn); + PRINT_INFO("vdev %s: changed filename into \"%s\"", virt_dev->name, + virt_dev->filename); + res = 0; + +unlock: + scst_alua_unlock(); + mutex_unlock(&scst_mutex); + +out: + kobject_put(&dev->dev_kobj); + + return res; +} + +static ssize_t vdev_sysfs_filename_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_sysfs_work_item *work; + char *arg; + int res; + + TRACE_ENTRY(); + + res = -ENOMEM; + arg = kasprintf(GFP_KERNEL, "%.*s", (int)count, buf); + if (!arg) + goto out; + + res = scst_alloc_sysfs_work(vdev_sysfs_process_filename_store, + false, &work); + if (res) + goto out; + work->dev = dev; + swap(work->buf, arg); + kobject_get(&dev->dev_kobj); + res = scst_sysfs_queue_wait_work(work); + if (res) + goto out; + res = count; + +out: + kfree(arg); + TRACE_EXIT_RES(res); + return res; +} + static ssize_t vdev_sysfs_cluster_mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {