Merge branch 'svn-trunk'

This commit is contained in:
Bart Van Assche
2017-06-09 20:22:34 -07:00
9 changed files with 357 additions and 45 deletions
+6 -3
View File
@@ -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);
+10
View File
@@ -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;
+10
View File
@@ -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,
+81 -2
View File
@@ -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 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
----
+81 -2
View File
@@ -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 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
----
+6 -2
View File
@@ -4942,6 +4942,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);
@@ -5002,7 +5006,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;
@@ -5143,7 +5147,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;
+114
View File
@@ -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! */
}
+44 -33
View File
@@ -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 {
+5 -3
View File
@@ -7610,7 +7610,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:
@@ -7673,8 +7674,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;