Merge branch 'svn-trunk'

Conflicts:
	www/contributing.html
This commit is contained in:
Bart Van Assche
2015-08-08 13:33:15 -07:00
7 changed files with 384 additions and 161 deletions

View File

@@ -336,6 +336,50 @@ You can see description of possible subcommands in section
<ref id="subcommands" name="subcommands">.
<sect1> SCST_USER_REPLY_AND_GET_MULTI
<p>
SCST_USER_REPLY_AND_GET_MULTI allows at one call reply on the multiple
subcommands from SCST and get the multiple next subcommands.
Its argument is defined as:
<verb>
struct scst_user_get_multi {
aligned_u64 preplies;
int16_t replies_cnt;
int16_t replies_done;
int16_t cmds_cnt;
struct scst_user_get_cmd cmds[0];
},
</verb>
where:
<itemize>
<item> <bf/preplies/ - pointer to array of replies with size
<it/replies_cnt/. See SCST_USER_REPLY_CMD for description of struct
scst_user_reply_cmd fields
<item> <bf/replies_cnt/ - number of entries in <it/preplies/ array. If 0,
there are no replies
<item> <bf/replies_done/ - returns how many replies were processed by SCST. If there are
unprocessed replies, the user space device handler must retry the
unprocessed replies.
<item> <bf/cmds_cnt/ - on entry: number of available entries in <it/cmds/ array; on exit -
number of valid subcommands in <it/cmds/ array
<item> <bf/cmds/ - returned array of subcommands
</itemize>
Returns 0 on success or -1 in case of error, and errno is set
appropriately.
<sect1> SCST_USER_REPLY_CMD
<p>

View File

@@ -303,6 +303,15 @@ union scst_user_prealloc_buffer {
struct scst_user_prealloc_buffer_out out;
};
struct scst_user_get_multi {
aligned_u64 preplies; /* in */
int16_t replies_cnt; /* in */
int16_t replies_done; /* out */
int16_t cmds_cnt; /* in/out */
int16_t pad;
struct scst_user_get_cmd cmds[0]; /* out */
};
#define SCST_USER_REGISTER_DEVICE _IOW('u', 1, struct scst_user_dev_desc)
#define SCST_USER_UNREGISTER_DEVICE _IO('u', 2)
#define SCST_USER_SET_OPTIONS _IOW('u', 3, struct scst_user_opt)
@@ -313,6 +322,7 @@ union scst_user_prealloc_buffer {
#define SCST_USER_DEVICE_CAPACITY_CHANGED _IO('u', 8)
#define SCST_USER_GET_EXTENDED_CDB _IOWR('u', 9, struct scst_user_get_ext_cdb)
#define SCST_USER_PREALLOC_BUFFER _IOWR('u', 10, union scst_user_prealloc_buffer)
#define SCST_USER_REPLY_AND_GET_MULTI _IOWR('u', 11, struct scst_user_get_multi)
/* Values for scst_user_get_cmd.subcode */
#define SCST_USER_ATTACH_SESS \

View File

@@ -217,7 +217,6 @@ static int dev_usr_parse(struct scst_cmd *cmd);
static struct kmem_cache *user_dev_cachep;
static struct kmem_cache *user_cmd_cachep;
static struct kmem_cache *user_get_cmd_cachep;
static const struct file_operations dev_user_fops = {
.poll = dev_user_poll,
@@ -1908,18 +1907,18 @@ again:
return u;
}
static inline int test_cmd_threads(struct scst_user_dev *dev)
static inline int test_cmd_threads(struct scst_user_dev *dev, bool can_block)
{
int res = !list_empty(&dev->udev_cmd_threads.active_cmd_list) ||
!list_empty(&dev->ready_cmd_list) ||
!dev->blocking || dev->cleanup_done ||
!can_block || !dev->blocking || dev->cleanup_done ||
signal_pending(current);
return res;
}
/* Called under udev_cmd_threads.cmd_list_lock and IRQ off */
static int dev_user_get_next_cmd(struct scst_user_dev *dev,
struct scst_user_cmd **ucmd)
struct scst_user_cmd **ucmd, bool can_block)
{
int res = 0;
@@ -1927,7 +1926,7 @@ static int dev_user_get_next_cmd(struct scst_user_dev *dev,
while (1) {
wait_event_locked(dev->udev_cmd_threads.cmd_list_waitQ,
test_cmd_threads(dev), lock_irq,
test_cmd_threads(dev, can_block), lock_irq,
dev->udev_cmd_threads.cmd_list_lock);
dev_user_process_scst_commands(dev);
@@ -1936,7 +1935,7 @@ static int dev_user_get_next_cmd(struct scst_user_dev *dev,
if (*ucmd != NULL)
break;
if (!dev->blocking || dev->cleanup_done) {
if (!can_block || !dev->blocking || dev->cleanup_done) {
res = -EAGAIN;
TRACE_DBG("No ready commands, returning %d", res);
break;
@@ -1953,13 +1952,66 @@ static int dev_user_get_next_cmd(struct scst_user_dev *dev,
return res;
}
/* No locks */
static int dev_user_get_cmd_to_user(struct scst_user_dev *dev,
void __user *where, bool can_block)
{
int res;
struct scst_user_cmd *ucmd;
TRACE_ENTRY();
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
again:
res = dev_user_get_next_cmd(dev, &ucmd, can_block);
if (res == 0) {
int len, rc;
/*
* A misbehaving user space handler can make ucmd to get dead
* immediately after we released the lock, which can lead to
* copy of dead data to the user space, which can lead to a
* leak of sensitive information.
*/
if (unlikely(ucmd_get_check(ucmd))) {
/* Oops, this ucmd is already being destroyed. Retry. */
goto again;
}
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
EXTRACHECKS_BUG_ON(ucmd->user_cmd_payload_len == 0);
len = ucmd->user_cmd_payload_len;
TRACE_DBG("ucmd %p (user_cmd %p), payload_len %d (len %d)",
ucmd, &ucmd->user_cmd, ucmd->user_cmd_payload_len, len);
TRACE_BUFFER("UCMD", &ucmd->user_cmd, len);
rc = copy_to_user(where, &ucmd->user_cmd, len);
if (unlikely(rc != 0)) {
PRINT_ERROR("Copy to user failed (%d), requeuing ucmd "
"%p back to head of ready cmd list", res, ucmd);
res = -EFAULT;
/* Requeue ucmd back */
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
list_add(&ucmd->ready_cmd_list_entry,
&dev->ready_cmd_list);
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
}
#ifdef CONFIG_SCST_EXTRACHECKS
else
ucmd->user_cmd_payload_len = 0;
#endif
ucmd_put(ucmd);
} else
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
TRACE_EXIT_RES(res);
return res;
}
static int dev_user_reply_get_cmd(struct file *file, void __user *arg)
{
int res = 0, rc;
struct scst_user_dev *dev;
struct scst_user_get_cmd *cmd;
struct scst_user_reply_cmd *reply;
struct scst_user_cmd *ucmd;
struct scst_user_reply_cmd reply;
uint64_t ureply;
TRACE_ENTRY();
@@ -1982,79 +2034,126 @@ static int dev_user_reply_get_cmd(struct file *file, void __user *arg)
TRACE_DBG("ureply %lld (dev %s)", (unsigned long long int)ureply,
dev->name);
cmd = kmem_cache_alloc(user_get_cmd_cachep, GFP_KERNEL);
if (unlikely(cmd == NULL)) {
res = -ENOMEM;
goto out;
}
if (ureply != 0) {
unsigned long u = (unsigned long)ureply;
reply = (struct scst_user_reply_cmd *)cmd;
rc = copy_from_user(reply, (void __user *)u, sizeof(*reply));
rc = copy_from_user(&reply, (void __user *)u, sizeof(reply));
if (unlikely(rc != 0)) {
PRINT_ERROR("Failed to copy %d user's bytes", rc);
res = -EFAULT;
goto out_free;
goto out;
}
TRACE_BUFFER("Reply", reply, sizeof(*reply));
TRACE_BUFFER("Reply", &reply, sizeof(reply));
res = dev_user_process_reply(dev, reply);
res = dev_user_process_reply(dev, &reply);
if (unlikely(res < 0))
goto out_free;
goto out;
}
kmem_cache_free(user_get_cmd_cachep, cmd);
res = dev_user_get_cmd_to_user(dev, arg, true);
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
again:
res = dev_user_get_next_cmd(dev, &ucmd);
if (res == 0) {
int len;
/*
* A misbehaving user space handler can make ucmd to get dead
* immediately after we released the lock, which can lead to
* copy of dead data to the user space, which can lead to a
* leak of sensitive information.
*/
if (unlikely(ucmd_get_check(ucmd))) {
/* Oops, this ucmd is already being destroyed. Retry. */
goto again;
}
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
out:
TRACE_EXIT_RES(res);
return res;
}
EXTRACHECKS_BUG_ON(ucmd->user_cmd_payload_len == 0);
static int dev_user_reply_get_multi(struct file *file, void __user *arg)
{
int res = 0, rc;
struct scst_user_dev *dev;
struct scst_user_reply_cmd __user *replies;
int16_t i, replies_cnt, replies_done = 0, cmds_cnt = 0;
len = ucmd->user_cmd_payload_len;
TRACE_DBG("ucmd %p (user_cmd %p), payload_len %d (len %d)",
ucmd, &ucmd->user_cmd, ucmd->user_cmd_payload_len, len);
TRACE_BUFFER("UCMD", &ucmd->user_cmd, len);
rc = copy_to_user(arg, &ucmd->user_cmd, len);
TRACE_ENTRY();
dev = (struct scst_user_dev *)file->private_data;
res = dev_user_check_reg(dev);
if (unlikely(res != 0))
goto out;
res = get_user(replies_cnt, (int16_t __user *)
&((struct scst_user_get_multi *)arg)->replies_cnt);
if (unlikely(res < 0)) {
PRINT_ERROR("%s", "Unable to get replies_cnt");
goto out;
}
res = get_user(cmds_cnt, (int16_t __user *)
&((struct scst_user_get_multi *)arg)->cmds_cnt);
if (unlikely(res < 0)) {
PRINT_ERROR("%s", "Unable to get cmds_cnt");
goto out;
}
TRACE_DBG("replies %d, space %d (dev %s)",
replies_cnt, cmds_cnt, dev->name);
if (replies_cnt == 0)
goto get_cmds;
/* get_user() can't be used with 64-bit values on x86_32 */
rc = copy_from_user(&replies, (uint64_t __user *)
&((struct scst_user_get_multi __user *)arg)->preplies, sizeof(&replies));
if (unlikely(rc != 0)) {
PRINT_ERROR("%s", "Unable to get preply");
res = -EFAULT;
goto out;
}
for (i = 0; i < replies_cnt; i++) {
struct scst_user_reply_cmd reply;
rc = copy_from_user(&reply, &replies[i], sizeof(reply));
if (unlikely(rc != 0)) {
PRINT_ERROR("Copy to user failed (%d), requeuing ucmd "
"%p back to head of ready cmd list", rc, ucmd);
PRINT_ERROR("Unable to get reply %d", i);
res = -EFAULT;
/* Requeue ucmd back */
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
list_add(&ucmd->ready_cmd_list_entry,
&dev->ready_cmd_list);
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
goto out_part_replies_done;
}
#ifdef CONFIG_SCST_EXTRACHECKS
else
ucmd->user_cmd_payload_len = 0;
#endif
ucmd_put(ucmd);
} else
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
TRACE_BUFFER("Reply", &reply, sizeof(reply));
res = dev_user_process_reply(dev, &reply);
if (unlikely(res < 0))
goto out_part_replies_done;
replies_done++;
}
TRACE_DBG("Returning %d replies_done", replies_done);
res = put_user(replies_done, (int16_t __user *)
&((struct scst_user_get_multi *)arg)->replies_done);
if (unlikely(res < 0))
goto out;
get_cmds:
for (i = 0; i < cmds_cnt; i++) {
res = dev_user_get_cmd_to_user(dev,
&((struct scst_user_get_multi __user *)arg)->cmds[i], i == 0);
if (res != 0) {
if ((res == -EAGAIN) && (i > 0))
res = 0;
break;
}
}
TRACE_DBG("Returning %d cmds_ret", i);
rc = put_user(i, (int16_t __user *)
&((struct scst_user_get_multi *)arg)->cmds_cnt);
if (unlikely(rc < 0)) {
res = rc; /* this error is more important */
goto out;
}
out:
TRACE_EXIT_RES(res);
return res;
out_free:
kmem_cache_free(user_get_cmd_cachep, cmd);
out_part_replies_done:
TRACE_DBG("Partial returning %d replies_done", replies_done);
put_user(replies_done, (int16_t __user *)
&((struct scst_user_get_multi *)arg)->replies_done);
rc = put_user(0, (int16_t __user *)
&((struct scst_user_get_multi *)arg)->cmds_cnt);
goto out;
}
@@ -2076,6 +2175,11 @@ static long dev_user_ioctl(struct file *file, unsigned int cmd,
res = dev_user_reply_cmd(file, (void __user *)arg);
break;
case SCST_USER_REPLY_AND_GET_MULTI:
TRACE_DBG("%s", "REPLY_AND_GET_MULTI");
res = dev_user_reply_get_multi(file, (void __user *)arg);
break;
case SCST_USER_GET_EXTENDED_CDB:
TRACE_DBG("%s", "GET_EXTENDED_CDB");
res = dev_user_get_ext_cdb(file, (void __user *)arg);
@@ -3512,7 +3616,7 @@ static int dev_user_process_cleanup(struct scst_user_dev *dev)
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
rc = dev_user_get_next_cmd(dev, &ucmd);
rc = dev_user_get_next_cmd(dev, &ucmd, false);
if (rc == 0)
dev_user_unjam_cmd(ucmd, 1, NULL);
@@ -3754,18 +3858,11 @@ static int __init init_scst_user(void)
goto out_dev_cache;
}
user_get_cmd_cachep = KMEM_CACHE(max_get_reply,
SCST_SLAB_FLAGS|SLAB_HWCACHE_ALIGN);
if (user_get_cmd_cachep == NULL) {
res = -ENOMEM;
goto out_cache;
}
dev_user_devtype.module = THIS_MODULE;
res = scst_register_virtual_dev_driver(&dev_user_devtype);
if (res < 0)
goto out_cache1;
goto out_cache;
#ifdef CONFIG_SCST_PROC
res = scst_dev_handler_build_std_proc(&dev_user_devtype);
@@ -3845,9 +3942,6 @@ out_proc:
out_unreg:
scst_unregister_dev_driver(&dev_user_devtype);
out_cache1:
kmem_cache_destroy(user_get_cmd_cachep);
out_cache:
kmem_cache_destroy(user_cmd_cachep);
@@ -3879,7 +3973,6 @@ static void __exit exit_scst_user(void)
#endif
scst_unregister_virtual_dev_driver(&dev_user_devtype);
kmem_cache_destroy(user_get_cmd_cachep);
kmem_cache_destroy(user_cmd_cachep);
kmem_cache_destroy(user_dev_cachep);

View File

@@ -1,14 +1,14 @@
#
# SCSI target mid-level makefile
#
#
# Copyright (C) 2007 - 2015 Vladislav Bolkhovitin <vst@vlnb.net>
# Copyright (C) 2007 - 2015 SanDisk Corporation
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, version 2
# of the License.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

View File

@@ -48,6 +48,26 @@ static void exec_read(struct vdisk_cmd *vcmd, loff_t loff);
static void exec_write(struct vdisk_cmd *vcmd, loff_t loff);
static void exec_verify(struct vdisk_cmd *vcmd, loff_t loff);
static int open_dev_fd(struct vdisk_dev *dev)
{
int res;
int open_flags = O_LARGEFILE;
if (dev->rd_only_flag)
open_flags |= O_RDONLY;
else
open_flags |= O_RDWR;
if (dev->o_direct_flag)
open_flags |= O_DIRECT;
if (dev->wt_flag)
open_flags |= O_DSYNC;
TRACE_DBG("Opening file %s, flags 0x%x", dev->file_name, open_flags);
res = open(dev->file_name, open_flags);
return res;
}
static inline void set_cmd_error_status(struct scst_user_scsi_cmd_reply_exec *reply,
int status)
{
@@ -400,7 +420,7 @@ static int do_exec(struct vdisk_cmd *vcmd)
break;
case REPORT_LUNS:
default:
TRACE_DBG("Invalid opcode %d", opcode);
TRACE_DBG("Invalid opcode 0x%x", opcode);
set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
break;
}
@@ -602,35 +622,92 @@ reply:
return res;
}
static int open_dev_fd(struct vdisk_dev *dev)
static int process_cmd(struct vdisk_cmd *vcmd)
{
int res;
int open_flags = O_LARGEFILE;
struct scst_user_get_cmd *cmd = vcmd->cmd;
struct scst_user_reply_cmd *reply = vcmd->reply;
int res = 0;
if (dev->rd_only_flag)
open_flags |= O_RDONLY;
else
open_flags |= O_RDWR;
if (dev->o_direct_flag)
open_flags |= O_DIRECT;
if (dev->wt_flag)
open_flags |= O_DSYNC;
TRACE_ENTRY();
TRACE_DBG("Opening file %s, flags 0x%x", dev->file_name, open_flags);
res = open(dev->file_name, open_flags);
TRACE_BUFFER("Received cmd", &cmd, sizeof(cmd));
switch(cmd->subcode) {
case SCST_USER_EXEC:
if (cmd->exec_cmd.data_direction & SCST_DATA_WRITE) {
TRACE_BUFFER("Received cmd data",
(void *)(unsigned long)cmd->exec_cmd.pbuf,
cmd->exec_cmd.bufflen);
}
res = do_exec(vcmd);
if ((reply->exec_reply.resp_data_len != 0) && (res != 150)) {
TRACE_BUFFER("Reply data",
(void *)(unsigned long)reply->exec_reply.pbuf,
reply->exec_reply.resp_data_len);
}
break;
case SCST_USER_ALLOC_MEM:
res = do_alloc_mem(vcmd);
break;
case SCST_USER_PARSE:
res = do_parse(vcmd);
break;
case SCST_USER_ON_CACHED_MEM_FREE:
res = do_cached_mem_free(vcmd);
break;
case SCST_USER_ON_FREE_CMD:
res = do_on_free_cmd(vcmd);
break;
case SCST_USER_TASK_MGMT_RECEIVED:
res = do_tm(vcmd, 0);
break;
case SCST_USER_TASK_MGMT_DONE:
res = do_tm(vcmd, 1);
#if DEBUG_TM_FN_IGNORE
if (dev->debug_tm_ignore) {
sleep(15);
}
#endif
break;
case SCST_USER_ATTACH_SESS:
case SCST_USER_DETACH_SESS:
res = do_sess(vcmd);
break;
default:
PRINT_ERROR("Unknown or wrong cmd subcode %x",
cmd->subcode);
res = -EINVAL;
goto out;
}
out:
TRACE_EXIT_RES(res);
return res;
}
void *main_loop(void *arg)
{
int res = 0;
int res = 0, i, j;
struct vdisk_dev *dev = (struct vdisk_dev *)arg;
struct scst_user_get_cmd cmd;
struct scst_user_reply_cmd reply;
struct vdisk_cmd vcmd = { -1, &cmd, dev, &reply, {0}};
int scst_usr_fd = dev->scst_usr_fd;
struct pollfd pl;
#define MULTI_CMDS_CNT 128
struct {
struct scst_user_reply_cmd replies[MULTI_CMDS_CNT];
struct scst_user_get_multi multi_cmd;
struct scst_user_get_cmd cmds[MULTI_CMDS_CNT];
} multi;
TRACE_ENTRY();
@@ -647,6 +724,9 @@ void *main_loop(void *arg)
pl.events = POLLIN;
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
while(1) {
#ifdef DEBUG_TM_IGNORE_ALL
@@ -661,38 +741,50 @@ void *main_loop(void *arg)
}
}
#endif
res = ioctl(scst_usr_fd, SCST_USER_REPLY_AND_GET_CMD, &cmd);
if (use_multi) {
TRACE_DBG("preplies %p (first: %p), replies_cnt %d, "
"replies_done %d, cmds_cnt %d", (void *)multi.multi_cmd.preplies,
&multi.replies[0], multi.multi_cmd.replies_cnt,
multi.multi_cmd.replies_done, multi.multi_cmd.cmds_cnt);
res = ioctl(scst_usr_fd, SCST_USER_REPLY_AND_GET_MULTI, &multi.multi_cmd);
} else
res = ioctl(scst_usr_fd, SCST_USER_REPLY_AND_GET_CMD, &cmd);
if (res != 0) {
res = errno;
switch(res) {
case ESRCH:
case EBUSY:
TRACE_MGMT_DBG("SCST_USER_REPLY_AND_GET_CMD returned "
"%d (%s)", res, strerror(res));
TRACE_MGMT_DBG("SCST_USER returned %d (%s)", res, strerror(res));
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
case EINTR:
continue;
case EAGAIN:
TRACE_DBG("SCST_USER_REPLY_AND_GET_CMD returned "
"EAGAIN (%d)", res);
TRACE_DBG("SCST_USER returned EAGAIN (%d)", res);
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
if (dev->non_blocking)
break;
else
continue;
default:
PRINT_ERROR("SCST_USER_REPLY_AND_GET_CMD failed: "
"%s (%d)", strerror(res), res);
PRINT_ERROR("SCST_USER failed: %s (%d)", strerror(res), res);
#if 1
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
continue;
#else
goto out_close;
#endif
}
again_poll:
res = poll(&pl, 1, 2000);
res = poll(&pl, 1, -1);
if (res > 0)
continue;
else if (res == 0)
@@ -718,74 +810,47 @@ again_poll:
}
}
TRACE_BUFFER("Received cmd", &cmd, sizeof(cmd));
switch(cmd.subcode) {
case SCST_USER_EXEC:
if (cmd.exec_cmd.data_direction & SCST_DATA_WRITE) {
TRACE_BUFFER("Received cmd data",
(void *)(unsigned long)cmd.exec_cmd.pbuf,
cmd.exec_cmd.bufflen);
if (use_multi) {
if (multi.multi_cmd.replies_done < multi.multi_cmd.replies_cnt) {
TRACE_MGMT_DBG("replies_done %d < replies_cnt %d (dev %s)",
multi.multi_cmd.replies_done, multi.multi_cmd.replies_cnt, dev->name);
multi.multi_cmd.preplies = (uint64_t)&multi.replies[multi.multi_cmd.replies_done];
multi.multi_cmd.replies_cnt = multi.multi_cmd.replies_cnt - multi.multi_cmd.replies_done;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
continue;
}
res = do_exec(&vcmd);
TRACE_DBG("cmds_cnt %d", multi.multi_cmd.cmds_cnt);
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
for (i = 0, j = 0; i < multi.multi_cmd.cmds_cnt; i++, j++) {
vcmd.cmd = &multi.cmds[i];
vcmd.reply = &multi.replies[j];
res = process_cmd(&vcmd);
#ifdef DEBUG_TM_IGNORE
if (res == 150) {
j--;
continue;
}
#endif
if (res != 0)
goto out_close;
TRACE_BUFFER("Sending reply", vcmd.reply, sizeof(reply));
}
multi.multi_cmd.replies_cnt = j;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
} else {
res = process_cmd(&vcmd);
#ifdef DEBUG_TM_IGNORE
if (res == 150) {
cmd.preply = 0;
continue;
}
#endif
if (reply.exec_reply.resp_data_len != 0) {
TRACE_BUFFER("Reply data",
(void *)(unsigned long)reply.exec_reply.pbuf,
reply.exec_reply.resp_data_len);
}
break;
if (res != 0)
goto out_close;
case SCST_USER_ALLOC_MEM:
res = do_alloc_mem(&vcmd);
break;
case SCST_USER_PARSE:
res = do_parse(&vcmd);
break;
case SCST_USER_ON_CACHED_MEM_FREE:
res = do_cached_mem_free(&vcmd);
break;
case SCST_USER_ON_FREE_CMD:
res = do_on_free_cmd(&vcmd);
break;
case SCST_USER_TASK_MGMT_RECEIVED:
res = do_tm(&vcmd, 0);
break;
case SCST_USER_TASK_MGMT_DONE:
res = do_tm(&vcmd, 1);
#if DEBUG_TM_FN_IGNORE
if (dev->debug_tm_ignore) {
sleep(15);
}
#endif
break;
case SCST_USER_ATTACH_SESS:
case SCST_USER_DETACH_SESS:
res = do_sess(&vcmd);
break;
default:
PRINT_ERROR("Unknown or wrong cmd subcode %x",
cmd.subcode);
goto out_close;
cmd.preply = (unsigned long)&reply;
TRACE_BUFFER("Sending reply", &reply, sizeof(reply));
}
if (res != 0)
goto out_close;
cmd.preply = (unsigned long)&reply;
TRACE_BUFFER("Sending reply", &reply, sizeof(reply));
}
out_close:

View File

@@ -17,6 +17,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <scst_user.h>
@@ -116,6 +117,7 @@ struct vdisk_cmd
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
extern int vdisk_ID;
extern bool use_multi;
uint32_t crc32buf(const char *buf, size_t len);

View File

@@ -93,6 +93,7 @@ static int debug_tm_ignore;
#endif
static int non_blocking, sgv_shared, sgv_single_alloc_pages, sgv_purge_interval;
static int sgv_disable_clustered_pool, prealloc_buffers_num, prealloc_buffer_size;
bool use_multi = true;
static void *(*alloc_fn)(size_t size) = align_alloc;
@@ -118,6 +119,7 @@ static struct option const long_options[] =
{"sgv_disable_clustered_pool", no_argument, 0, 'D'},
{"prealloc_buffers", required_argument, 0, 'R'},
{"prealloc_buffer_size", required_argument, 0, 'Z'},
{"multi_cmd", required_argument, 0, 'M'},
#if defined(DEBUG) || defined(TRACING)
{"debug", required_argument, 0, 'd'},
#endif
@@ -156,6 +158,7 @@ static void usage(void)
printf(" -D, --sgv_disable_clustered_pool Disable clustered SGV pool\n");
printf(" -R, --prealloc_buffers=n Prealloc n buffers\n");
printf(" -Z, --prealloc_buffer_size=n Sets the size in KB of each prealloced buffer\n");
printf(" -M, --multi_cmd=v Use or not multi-commands processing (default: 1)\n");
#if defined(DEBUG) || defined(TRACING)
printf(" -d, --debug=level Debug tracing level\n");
#endif
@@ -507,7 +510,7 @@ int main(int argc, char **argv)
memset(devs, 0, sizeof(devs));
while ((ch = getopt_long(argc, argv, "+b:e:trongluF:I:cp:f:m:d:vsS:P:hDR:Z:",
while ((ch = getopt_long(argc, argv, "+b:e:trongluF:I:cp:f:m:d:vsS:P:hDR:Z:M:",
long_options, &longindex)) >= 0) {
switch (ch) {
case 'b':
@@ -579,6 +582,9 @@ int main(int argc, char **argv)
case 'Z':
prealloc_buffer_size = atoi(optarg) * 1024;
break;
case 'M':
use_multi = atoi(optarg);
break;
case 'm':
if (strncmp(optarg, "all", 3) == 0)
memory_reuse_type = SCST_USER_MEM_REUSE_ALL;
@@ -712,6 +718,9 @@ int main(int argc, char **argv)
alloc_fn = malloc;
}
if (!use_multi)
PRINT_INFO(" %s", "Using SCST_USER_REPLY_AND_GET_CMD");
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
if (debug_tm_ignore)
PRINT_INFO(" %s", "DEBUG_TM_IGNORE");
@@ -744,7 +753,7 @@ int main(int argc, char **argv)
PRINT_ERROR("sigaction() failed: %s",
strerror(res));
goto out_done;
}
}
res = alarm(flush_interval);
if (res != 0) {