diff --git a/doc/scst_user_spec.sgml b/doc/scst_user_spec.sgml index 08ec6efb9..121e4df97 100644 --- a/doc/scst_user_spec.sgml +++ b/doc/scst_user_spec.sgml @@ -336,6 +336,50 @@ You can see description of possible subcommands in section . + SCST_USER_REPLY_AND_GET_MULTI + +

+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: + + +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]; +}, + + +where: + + + + + +Returns 0 on success or -1 in case of error, and errno is set +appropriately. + + SCST_USER_REPLY_CMD

diff --git a/scst/include/scst_user.h b/scst/include/scst_user.h index 69e90bdea..0a2e53f92 100644 --- a/scst/include/scst_user.h +++ b/scst/include/scst_user.h @@ -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 \ diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 60a5077e2..2527d7a1d 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -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); diff --git a/usr/fileio/Makefile b/usr/fileio/Makefile index 8dfd4ad6d..7f6b23695 100644 --- a/usr/fileio/Makefile +++ b/usr/fileio/Makefile @@ -1,14 +1,14 @@ # # SCSI target mid-level makefile -# +# # Copyright (C) 2007 - 2015 Vladislav Bolkhovitin # 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 diff --git a/usr/fileio/common.c b/usr/fileio/common.c index ecc91a77c..e308359bf 100644 --- a/usr/fileio/common.c +++ b/usr/fileio/common.c @@ -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: diff --git a/usr/fileio/common.h b/usr/fileio/common.h index e36697332..f526bd8ca 100644 --- a/usr/fileio/common.h +++ b/usr/fileio/common.h @@ -17,6 +17,7 @@ #include #include +#include #include @@ -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); diff --git a/usr/fileio/fileio.c b/usr/fileio/fileio.c index 935f75d70..d218a5daf 100644 --- a/usr/fileio/fileio.c +++ b/usr/fileio/fileio.c @@ -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) {