From 93bea9e0e8f36770b23dd91ec04e21378f7a148c Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 3 Jun 2017 02:38:51 +0000 Subject: [PATCH 1/5] Update to 4.11 kernels git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7203 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/qla_bsg.c | 10 +++ qla2x00t/qla_isr.c | 10 +++ scst/kernel/nolockdep-4.11.patch | 114 +++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 scst/kernel/nolockdep-4.11.patch diff --git a/qla2x00t/qla_bsg.c b/qla2x00t/qla_bsg.c index a2ab0e179..214552766 100644 --- a/qla2x00t/qla_bsg.c +++ b/qla2x00t/qla_bsg.c @@ -987,8 +987,13 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) ql_log(ql_log_warn, vha, 0x702c, "Vendor request %s failed.\n", type); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) + fw_sts_ptr = ((uint8_t *)scsi_req(bsg_job->req)->sense) + + sizeof(struct fc_bsg_reply); +#else fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); +#endif memcpy(fw_sts_ptr, response, sizeof(response)); fw_sts_ptr += sizeof(response); @@ -1011,8 +1016,13 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) bsg_reply->reply_payload_rcv_len = #endif bsg_job->reply_payload.payload_len; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) + fw_sts_ptr = ((uint8_t *)scsi_req(bsg_job->req)->sense) + + sizeof(struct fc_bsg_reply); +#else fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); +#endif memcpy(fw_sts_ptr, response, sizeof(response)); fw_sts_ptr += sizeof(response); *fw_sts_ptr = command_sent; diff --git a/qla2x00t/qla_isr.c b/qla2x00t/qla_isr.c index 4835b055d..a24098631 100644 --- a/qla2x00t/qla_isr.c +++ b/qla2x00t/qla_isr.c @@ -1228,7 +1228,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, type, sp->handle, comp_status, fw_status[1], fw_status[2], le16_to_cpu(((struct els_sts_entry_24xx *) pkt)->total_byte_count)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) + fw_sts_ptr = ((uint8_t*)scsi_req(bsg_job->req)->sense) + + sizeof(struct fc_bsg_reply); +#else fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); +#endif memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); } else { @@ -1246,7 +1251,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, #else bsg_reply->reply_payload_rcv_len = 0; #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) + fw_sts_ptr = ((uint8_t*)scsi_req(bsg_job->req)->sense) + + sizeof(struct fc_bsg_reply); +#else fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); +#endif memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); } ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056, diff --git a/scst/kernel/nolockdep-4.11.patch b/scst/kernel/nolockdep-4.11.patch new file mode 100644 index 000000000..21c312e34 --- /dev/null +++ b/scst/kernel/nolockdep-4.11.patch @@ -0,0 +1,114 @@ +=== modified file 'include/linux/lockdep.h' +--- old/include/linux/lockdep.h 2017-06-02 03:24:57 +0000 ++++ new/include/linux/lockdep.h 2017-06-02 03:31:44 +0000 +@@ -373,7 +373,7 @@ extern struct pin_cookie lock_pin_lock(s + extern void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie); + extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); + +-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, ++# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0, + + #define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) + + +=== modified file 'include/linux/sched.h' +--- old/include/linux/sched.h 2017-06-02 03:24:57 +0000 ++++ new/include/linux/sched.h 2017-06-02 03:31:44 +0000 +@@ -808,6 +808,9 @@ struct task_struct { + # define MAX_LOCK_DEPTH 48UL + u64 curr_chain_key; + int lockdep_depth; ++# define NOLOCKDEP_SUPPORTED 1 ++ unsigned int nolockdep_call:1; ++ unsigned int nolockdep_call_irq_saved:1; + unsigned int lockdep_recursion; + struct held_lock held_locks[MAX_LOCK_DEPTH]; + gfp_t lockdep_reclaim_gfp; + +=== modified file 'kernel/locking/lockdep.c' +--- old/kernel/locking/lockdep.c 2017-06-02 03:24:57 +0000 ++++ new/kernel/locking/lockdep.c 2017-06-02 03:31:44 +0000 +@@ -3754,9 +3754,11 @@ void lock_acquire(struct lockdep_map *lo + if (unlikely(current->lockdep_recursion)) + return; + ++ if (unlikely(current->nolockdep_call)) ++ return; ++ + raw_local_irq_save(flags); + check_flags(flags); +- + current->lockdep_recursion = 1; + trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip); + __lock_acquire(lock, subclass, trylock, read, check, +@@ -3774,6 +3776,9 @@ void lock_release(struct lockdep_map *lo + if (unlikely(current->lockdep_recursion)) + return; + ++ if (unlikely(current->nolockdep_call)) ++ return; ++ + raw_local_irq_save(flags); + check_flags(flags); + current->lockdep_recursion = 1; +@@ -4022,6 +4027,9 @@ void lock_contended(struct lockdep_map * + if (unlikely(current->lockdep_recursion)) + return; + ++ if (unlikely(current->nolockdep_call)) ++ return; ++ + raw_local_irq_save(flags); + check_flags(flags); + current->lockdep_recursion = 1; +@@ -4042,6 +4050,9 @@ void lock_acquired(struct lockdep_map *l + if (unlikely(current->lockdep_recursion)) + return; + ++ if (unlikely(current->nolockdep_call)) ++ return; ++ + raw_local_irq_save(flags); + check_flags(flags); + current->lockdep_recursion = 1; + +=== modified file 'kernel/softirq.c' +--- old/kernel/softirq.c 2017-06-02 03:24:57 +0000 ++++ new/kernel/softirq.c 2017-06-02 03:31:44 +0000 +@@ -335,6 +335,17 @@ asmlinkage __visible void do_softirq(voi + */ + void irq_enter(void) + { ++#ifdef CONFIG_LOCKDEP ++ if (unlikely(current->nolockdep_call)) { ++ unsigned long flags; ++ local_irq_save(flags); ++ if (current->nolockdep_call) { ++ current->nolockdep_call_irq_saved = 1; ++ current->nolockdep_call = 0; ++ } ++ local_irq_restore(flags); ++ } ++#endif + rcu_irq_enter(); + if (is_idle_task(current) && !in_interrupt()) { + /* +@@ -406,6 +417,17 @@ void irq_exit(void) + + tick_irq_exit(); + rcu_irq_exit(); ++#ifdef CONFIG_LOCKDEP ++ if (unlikely(current->nolockdep_call_irq_saved)) { ++ unsigned long flags; ++ local_irq_save(flags); ++ if (current->nolockdep_call_irq_saved) { ++ current->nolockdep_call_irq_saved = 0; ++ current->nolockdep_call = 1; ++ } ++ local_irq_restore(flags); ++ } ++#endif + trace_hardirq_exit(); /* must be last! */ + } + + From 0ae66a082ea716de4382a06c48a98243f830206e Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 3 Jun 2017 04:02:22 +0000 Subject: [PATCH 2/5] Fix dereference beyond last sg element Reported-By: David Butterfield git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7204 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/qla2x00-target/qla2x00t.c | 9 ++++++--- scst/include/scst.h | 8 ++++++-- scst/src/scst_lib.c | 8 +++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index f91ca9d83..2903ded28 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -2634,7 +2634,8 @@ static void q2t_load_cont_data_segments(struct q2t_prm *prm) (unsigned long long int)pci_dma_lo32(dma_addr), (int)sg_dma_len(prm->sg)); - prm->sg = __sg_next_inline(prm->sg); + /* prm->sg might be last here */ + prm->sg = sg_next_inline(prm->sg); } TRACE_BUFFER("Continuation packet data", @@ -2695,7 +2696,8 @@ static void q2x_load_data_segments(struct q2t_prm *prm) (unsigned long long int)pci_dma_lo32(dma_addr), (int)sg_dma_len(prm->sg)); - prm->sg = __sg_next_inline(prm->sg); + /* prm->sg might be last here */ + prm->sg = sg_next_inline(prm->sg); } TRACE_BUFFER("Scatter/gather, CTIO packet data", pkt, @@ -2756,7 +2758,8 @@ static void q24_load_data_segments(struct q2t_prm *prm) (unsigned long long int)pci_dma_lo32(dma_addr), (int)sg_dma_len(prm->sg)); - prm->sg = __sg_next_inline(prm->sg); + /* prm->sg might be last here */ + prm->sg = sg_next_inline(prm->sg); } q2t_load_cont_data_segments(prm); diff --git a/scst/include/scst.h b/scst/include/scst.h index 3b684be55..5fd6c3733 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -4946,6 +4946,10 @@ void scst_aen_done(struct scst_aen *aen); static inline struct scatterlist *__sg_next_inline(struct scatterlist *sg) { +#ifdef CONFIG_SCST_EXTRACHECKS + BUG_ON(sg_is_last(sg)); +#endif + sg++; if (unlikely(sg_is_chain(sg))) sg = sg_chain_ptr(sg); @@ -5006,7 +5010,7 @@ static inline int __scst_get_buf(struct scst_cmd *cmd, int sg_cnt, res = sg->length; cmd->get_sg_buf_entry_num++; - cmd->get_sg_buf_cur_sg_entry = __sg_next_inline(sg); + cmd->get_sg_buf_cur_sg_entry = sg_next_inline(sg); out: return res; @@ -5147,7 +5151,7 @@ static inline int __scst_get_sg_page(struct scst_cmd *cmd, int sg_cnt, res = sg->length; cmd->get_sg_buf_entry_num++; - cmd->get_sg_buf_cur_sg_entry = __sg_next_inline(sg); + cmd->get_sg_buf_cur_sg_entry = sg_next_inline(sg); out: return res; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 08c09684d..dfedd150c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -7506,7 +7506,8 @@ static void scst_restore_dif_sg(struct scst_cmd *cmd) left -= sg->length; TRACE_DBG("DIF sg %p, restored len %d (left %d)", sg, sg->length, left); - sg = __sg_next_inline(sg); + /* sg might be last here */ + sg = sg_next_inline(sg); } while (left > 0); out: @@ -7569,8 +7570,9 @@ int scst_alloc_space(struct scst_cmd *cmd) left -= sgt->length; sgt->length = (sgd->length >> block_shift) << SCST_DIF_TAG_SHIFT; TRACE_SG("sgt %p, new len %d", sgt, sgt->length); - sgd = __sg_next_inline(sgd); - sgt = __sg_next_inline(sgt); + /* sgd/sgt might be last here */ + sgd = sg_next_inline(sgd); + sgt = sg_next_inline(sgt); } while (left > 0); cmd->dif_sg_normalized = 1; From 64d07d25cf0b99c1fcd8478a5ead5aeb0c04eab5 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 6 Jun 2017 04:20:09 +0000 Subject: [PATCH 3/5] scst_vdisk: 'numa_node_id' signed attribute value fix The "numa_node_id" attribute reside in the scst_vdisk_dev struct as signed integer and may well be negative values (eg, -1), so move fetching it above the unsigned attributes and use kstrtoll() to retrieve the values. Signed-off-by: Marc A. Smith git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7205 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 77 +++++++++++++++++------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index fa8c4395a..023aecb36 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -7964,7 +7964,8 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, char *params, const char *const allowed_params[]) { int res = 0; - unsigned long long val; + unsigned long long ull_val; + long long ll_val; char *param, *p, *pp; TRACE_ENTRY(); @@ -8096,7 +8097,25 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, continue; } - res = kstrtoull(pp, 0, &val); + res = kstrtoll(pp, 0, &ll_val); + if (res != 0) { + PRINT_ERROR("strtoll() for %s failed: %d (device %s)", + pp, res, virt_dev->name); + goto out; + } + + if (!strcasecmp("numa_node_id", p)) { + virt_dev->numa_node_id = ll_val; + BUILD_BUG_ON(NUMA_NO_NODE != -1); + if (virt_dev->numa_node_id < NUMA_NO_NODE) { + res = -EINVAL; + goto out; + } + TRACE_DBG("numa_node_id %d", virt_dev->numa_node_id); + continue; + } + + res = kstrtoull(pp, 0, &ull_val); if (res != 0) { PRINT_ERROR("strtoull() for %s failed: %d (device %s)", pp, res, virt_dev->name); @@ -8104,14 +8123,14 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, } if (!strcasecmp("write_through", p)) { - virt_dev->wt_flag = val; + virt_dev->wt_flag = ull_val; TRACE_DBG("WRITE THROUGH %d", virt_dev->wt_flag); } else if (!strcasecmp("nv_cache", p)) { - virt_dev->nv_cache = val; + virt_dev->nv_cache = ull_val; TRACE_DBG("NON-VOLATILE CACHE %d", virt_dev->nv_cache); } else if (!strcasecmp("o_direct", p)) { #if 0 - virt_dev->o_direct_flag = val; + virt_dev->o_direct_flag = ull_val; TRACE_DBG("O_DIRECT %d", virt_dev->o_direct_flag); #else PRINT_INFO("O_DIRECT flag doesn't currently" @@ -8119,70 +8138,62 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, "in O_DIRECT mode instead (device %s)", virt_dev->name); #endif } else if (!strcasecmp("read_only", p)) { - virt_dev->rd_only = val; + virt_dev->rd_only = ull_val; TRACE_DBG("READ ONLY %d", virt_dev->rd_only); } else if (!strcasecmp("dummy", p)) { - if (val > 1) { + if (ull_val > 1) { res = -EINVAL; goto out; } - virt_dev->dummy = val; + virt_dev->dummy = ull_val; TRACE_DBG("DUMMY %d", virt_dev->dummy); } else if (!strcasecmp("removable", p)) { - virt_dev->removable = val; + virt_dev->removable = ull_val; TRACE_DBG("REMOVABLE %d", virt_dev->removable); } else if (!strcasecmp("active", p)) { - virt_dev->dev_active = val; + virt_dev->dev_active = ull_val; TRACE_DBG("ACTIVE %d", virt_dev->dev_active); } else if (!strcasecmp("rotational", p)) { - virt_dev->rotational = val; + virt_dev->rotational = ull_val; TRACE_DBG("ROTATIONAL %d", virt_dev->rotational); } else if (!strcasecmp("tst", p)) { - if ((val != SCST_TST_0_SINGLE_TASK_SET) && - (val != SCST_TST_1_SEP_TASK_SETS)) { - PRINT_ERROR("Invalid TST value %lld", val); + if ((ull_val != SCST_TST_0_SINGLE_TASK_SET) && + (ull_val != SCST_TST_1_SEP_TASK_SETS)) { + PRINT_ERROR("Invalid TST value %lld", ull_val); res = -EINVAL; goto out; } - virt_dev->tst = val; + virt_dev->tst = ull_val; TRACE_DBG("TST %d", virt_dev->tst); } else if (!strcasecmp("thin_provisioned", p)) { - virt_dev->thin_provisioned = val; + virt_dev->thin_provisioned = ull_val; virt_dev->thin_provisioned_manually_set = 1; TRACE_DBG("THIN PROVISIONED %d", virt_dev->thin_provisioned); } else if (!strcasecmp("zero_copy", p)) { - virt_dev->zero_copy = !!val; + virt_dev->zero_copy = !!ull_val; } else if (!strcasecmp("size", p)) { - virt_dev->file_size = val; + virt_dev->file_size = ull_val; } else if (!strcasecmp("size_mb", p)) { - virt_dev->file_size = val * 1024 * 1024; + virt_dev->file_size = ull_val * 1024 * 1024; } else if (!strcasecmp("cluster_mode", p)) { - virt_dev->initial_cluster_mode = val; + virt_dev->initial_cluster_mode = ull_val; TRACE_DBG("CLUSTER_MODE %d", virt_dev->initial_cluster_mode); } else if (!strcasecmp("blocksize", p)) { - virt_dev->blk_shift = scst_calc_block_shift(val); + virt_dev->blk_shift = scst_calc_block_shift(ull_val); if (virt_dev->blk_shift < 9) { - PRINT_ERROR("blocksize %llu too small", val); + PRINT_ERROR("blocksize %llu too small", ull_val); res = -EINVAL; goto out; } TRACE_DBG("block size %lld, block shift %d", - val, virt_dev->blk_shift); - } else if (!strcasecmp("numa_node_id", p)) { - virt_dev->numa_node_id = val; - BUILD_BUG_ON(NUMA_NO_NODE != -1); - if (virt_dev->numa_node_id < NUMA_NO_NODE) { - res = -EINVAL; - goto out; - } - TRACE_DBG("numa_node_id %d", virt_dev->numa_node_id); + ull_val, virt_dev->blk_shift); } else if (!strcasecmp("dif_type", p)) { - virt_dev->dif_type = val; + virt_dev->dif_type = ull_val; TRACE_DBG("DIF type %d", virt_dev->dif_type); } else if (!strcasecmp("dif_static_app_tag", p)) { - virt_dev->dif_static_app_tag_combined = cpu_to_be64(val); + virt_dev->dif_static_app_tag_combined = cpu_to_be64(ull_val); TRACE_DBG("DIF static app tag %llx", (long long)be64_to_cpu(virt_dev->dif_static_app_tag_combined)); } else { From e174d00f08552551103e3b79f2e079f00796e2b2 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Wed, 7 Jun 2017 01:13:58 +0000 Subject: [PATCH 4/5] scst: update ALUA documentation (Active/Non-Optimized) git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7206 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/README | 83 +++++++++++++++++++++++++++++++++++++++++++-- scst/README_in-tree | 83 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 162 insertions(+), 4 deletions(-) diff --git a/scst/README b/scst/README index 752fe3856..2d0d8c0e7 100644 --- a/scst/README +++ b/scst/README @@ -360,7 +360,8 @@ in/out in Makefile and scst.h: commands, which normally processed locally by the SCST core, not processed locally, but passed to the backend device. Intended to be used to implement NON-OPTIMIZED ALUA state together with "forwarding" - target attribute on the remote node. Disabled by default for safety. + target attribute on the remote node. See below for more details. + Disabled by default for safety. HIGHMEM kernel configurations are fully supported, but not recommended for performance reasons, except for scst_user, where they are not @@ -1679,6 +1680,12 @@ DEVICE_GROUP dgroup2 { } } +Note, if you are using "active" BLOCKIO device attribute to prevent open +of the backend block device on the passive node, it is not recommended +to set both active ("active", "nonoptimized") and passive ("standby", +etc.) ALUA states for the same device as shown above to keep internal +"active" state of the BLOCKIO device consistent. + Explicit ALUA ............. @@ -1699,7 +1706,9 @@ secondary transition, if this device is open. SCST BLOCKIO handler has necessary support for such behavior: 1. If you need to prevent an SCST BLOCKIO device from opening its block -device, you need to create it with parameter "active=0" +device, you need to create it with parameter "active=0". In case of DRBD +it would be done automatically, you don't have to use the "active" +attribute. 2. If you write new ALUA state in the "state" attribute, SCST BLOCKIO handler before transition closes open handles on all affected SCST @@ -1851,6 +1860,76 @@ information about ALUA support in Windows Server, see also: * Microsoft, ALUA MPIO Logo Test, MSDN (http://msdn.microsoft.com/en-us/library/gg607458%28v=vs.85%29.aspx). +Active/Non-Optimized via internal redirection +............................................... + +The Active-Standby configuration is simple to understand and setup, +however, it might have serious interoperability issues, because not all +initiators handle Standby state correctly. For instance, some versions +of VMware reported to have such issues. Same for Windows. + +Hence, it is better to use Non-Optimized state on the passive node +instead of Standby with internal commands redirection to the active +node. This is what the vast majority of storage vendors are doing, which +is, actually, the reason why Standby and Unavailable states have all +those initiator issues. Simply, they have had too few testing, because +only marginally used. + +SCST has necessary support for such redirection, it just needs to be +configured it correctly. It's a little bit of effort, especially to +understand how it's going to function, but then it would work MUCH more +reliable for full range of initiators. Ever poor initiators, who have no +idea about ALUA (boot from SAN, e.g.) would work now. + +1. Build SCST with CONFIG_SCST_FORWARD_MODE_PASS_THROUGH enabled in scst.h + +2. Setup on active node internal redirect target, which is going to +accept redirected commands from the passive node. It must be visible +only to the passive node. + +3. Set "forwarding" attribute for this target to 1. This is necessary to +correctly handle PRs. + +4. Export through this target the SAME backend SCST device as being +served to initiator(s) (consider for simplicity that there is only one +served device) + +5. Connect to this SCST device through this internal target from the +passive node. Now you have a local SCSI device on the passive side +pointing to the active node. + +6. Export this local device to the initiator(s) using SCST +*path-through* handler (scst_disk). Pass-though is needed to redirect +non-block commands as well: ATS, XCOPY, etc. + +7. Set ALUA state to this target as "nonoptimized". + +That's it on the normal path. Now the initiator(s) would see 2 paths: +OPTIMIZED going to the active node and NON-OPTIMIZED going to the +passive node, then redirected to the active node. + +On failover (i.e. switching active and passive states): + +1. Setup similar redirect target on the new active node. + +2. Setup connectivity to that new redirect target from the new passive +node + +3. Start ALUA change (see above) on both nodes + +4. !! Exchange in the sysfs security group(s) for the initiator(s) *LUN* +from old SCST device to the new one (blockio -> pass-through on the new +passive and pass-through -> blockio on the new active) using "replace_no_ua" +SCST command. You need to do it directly in the sysfs interface, +scstadmin can't do it. + +5. Set ALUA states to "active" on the new active node and "nonoptimized" +on the new passive node. + +6. Finish ALUA states change. + +If you have any questions, please read this above text at least 3 times +before asking. It might be tricky to understand. VAAI ---- diff --git a/scst/README_in-tree b/scst/README_in-tree index 5b7ec94a0..c97c8688b 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -250,7 +250,8 @@ your favorite kernel configuration Makefile target, e.g. "make xconfig": commands, which normally processed locally by the SCST core, not processed locally, but passed to the backend device. Intended to be used to implement NON-OPTIMIZED ALUA state together with "forwarding" - target attribute on the remote node. Disabled by default for safety. + target attribute on the remote node. See below for more details. + Disabled by default for safety. HIGHMEM kernel configurations are fully supported, but not recommended for performance reasons. @@ -1532,6 +1533,12 @@ DEVICE_GROUP dgroup2 { } } +Note, if you are using "active" BLOCKIO device attribute to prevent open +of the backend block device on the passive node, it is not recommended +to set both active ("active", "nonoptimized") and passive ("standby", +etc.) ALUA states for the same device as shown above to keep internal +"active" state of the BLOCKIO device consistent. + Explicit ALUA ............. @@ -1552,7 +1559,9 @@ secondary transition, if this device is open. SCST BLOCKIO handler has necessary support for such behavior: 1. If you need to prevent an SCST BLOCKIO device from opening its block -device, you need to create it with parameter "active=0" +device, you need to create it with parameter "active=0". In case of DRBD +it would be done automatically, you don't have to use the "active" +attribute. 2. If you write new ALUA state in the "state" attribute, SCST BLOCKIO handler before transition closes open handles on all affected SCST @@ -1704,6 +1713,76 @@ information about ALUA support in Windows Server, see also: * Microsoft, ALUA MPIO Logo Test, MSDN (http://msdn.microsoft.com/en-us/library/gg607458%28v=vs.85%29.aspx). +Active/Non-Optimized via internal redirection +............................................... + +The Active-Standby configuration is simple to understand and setup, +however, it might have serious interoperability issues, because not all +initiators handle Standby state correctly. For instance, some versions +of VMware reported to have such issues. Same for Windows. + +Hence, it is better to use Non-Optimized state on the passive node +instead of Standby with internal commands redirection to the active +node. This is what the vast majority of storage vendors are doing, which +is, actually, the reason why Standby and Unavailable states have all +those initiator issues. Simply, they have had too few testing, because +only marginally used. + +SCST has necessary support for such redirection, it just needs to be +configured it correctly. It's a little bit of effort, especially to +understand how it's going to function, but then it would work MUCH more +reliable for full range of initiators. Ever poor initiators, who have no +idea about ALUA (boot from SAN, e.g.) would work now. + +1. Build SCST with CONFIG_SCST_FORWARD_MODE_PASS_THROUGH enabled in scst.h + +2. Setup on active node internal redirect target, which is going to +accept redirected commands from the passive node. It must be visible +only to the passive node. + +3. Set "forwarding" attribute for this target to 1. This is necessary to +correctly handle PRs. + +4. Export through this target the SAME backend SCST device as being +served to initiator(s) (consider for simplicity that there is only one +served device) + +5. Connect to this SCST device through this internal target from the +passive node. Now you have a local SCSI device on the passive side +pointing to the active node. + +6. Export this local device to the initiator(s) using SCST +*path-through* handler (scst_disk). Pass-though is needed to redirect +non-block commands as well: ATS, XCOPY, etc. + +7. Set ALUA state to this target as "nonoptimized". + +That's it on the normal path. Now the initiator(s) would see 2 paths: +OPTIMIZED going to the active node and NON-OPTIMIZED going to the +passive node, then redirected to the active node. + +On failover (i.e. switching active and passive states): + +1. Setup similar redirect target on the new active node. + +2. Setup connectivity to that new redirect target from the new passive +node + +3. Start ALUA change (see above) on both nodes + +4. !! Exchange in the sysfs security group(s) for the initiator(s) *LUN* +from old SCST device to the new one (blockio -> pass-through on the new +passive and pass-through -> blockio on the new active) using "replace_no_ua" +SCST command. You need to do it directly in the sysfs interface, +scstadmin can't do it. + +5. Set ALUA states to "active" on the new active node and "nonoptimized" +on the new passive node. + +6. Finish ALUA states change. + +If you have any questions, please read this above text at least 3 times +before asking. It might be tricky to understand. VAAI ---- From 213a11e07bdae141c1aee3dd9ec05cfb17fdb70f Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Wed, 7 Jun 2017 01:23:59 +0000 Subject: [PATCH 5/5] scst: minor cleanup for previous commit git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7207 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/README | 2 +- scst/README_in-tree | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scst/README b/scst/README index 2d0d8c0e7..389840122 100644 --- a/scst/README +++ b/scst/README @@ -1876,7 +1876,7 @@ those initiator issues. Simply, they have had too few testing, because only marginally used. SCST has necessary support for such redirection, it just needs to be -configured it correctly. It's a little bit of effort, especially to +configured correctly. It's a little bit of effort, especially to understand how it's going to function, but then it would work MUCH more reliable for full range of initiators. Ever poor initiators, who have no idea about ALUA (boot from SAN, e.g.) would work now. diff --git a/scst/README_in-tree b/scst/README_in-tree index c97c8688b..df4125913 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -1729,7 +1729,7 @@ those initiator issues. Simply, they have had too few testing, because only marginally used. SCST has necessary support for such redirection, it just needs to be -configured it correctly. It's a little bit of effort, especially to +configured correctly. It's a little bit of effort, especially to understand how it's going to function, but then it would work MUCH more reliable for full range of initiators. Ever poor initiators, who have no idea about ALUA (boot from SAN, e.g.) would work now.