From 2a5c73956769bb2021e94f32073dfc126beb9cce Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 7 Aug 2015 02:30:42 +0000 Subject: [PATCH 1/6] Web updates git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6463 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- www/contributing.html | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/www/contributing.html b/www/contributing.html index 0d049f783..def6cf2f1 100644 --- a/www/contributing.html +++ b/www/contributing.html @@ -50,6 +50,17 @@

Possible SCST extensions and improvements

+

Asynchronous FILEIO in scst_vdisk handler

+ +

At the moment scst_vdisk handler for FILEIO uses regular synchronous read/write() calls + and makes deep queue depth by using multiple threads. This is not too high performance + model of operations. It would be much better to use asynchronous I/O with not blocking + I/O calls.

+ +

In the user space native AIO is available for many years, but only very recently ability to + use it was added in the kernel. Changing FILEIO to use the new interface should significantly + (multiple times) increase performance of FILEIO devices.

+

Support for O_DIRECT in scst_vdisk handler

At the moment, scst_vdisk handler doesn't support O_DIRECT option and possibility to set it @@ -183,14 +194,6 @@ which would translate their internal READ/WRITE requests to corresponding SCSI commands and, on the way back, SCSI status and sense codes to their internal status codes.

-

iSER target

- -

iSER (iSCSI Extensions for RDMA) - protocol accelerates iSCSI by allowing direct data transfers using RDMA services (iWARP or - InfiniBand) bypassing the regular heavy weighted and CPU consuming TCP/IP data transfers path.

- -

It would be good to add support for iSER in iSCSI-SCST.

-

GET CONFIGURATION command

SCSI command GET CONFIGURATION is mandatory for SCSI multimedia devices, like CD/DVD-ROMs or From 119a2d835692083c0763dd914110330b54cfec96 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 8 Aug 2015 02:53:02 +0000 Subject: [PATCH 2/6] Follow up for r6463 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6464 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- www/contributing.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/www/contributing.html b/www/contributing.html index def6cf2f1..1c9cf66d9 100644 --- a/www/contributing.html +++ b/www/contributing.html @@ -59,14 +59,17 @@

In the user space native AIO is available for many years, but only very recently ability to use it was added in the kernel. Changing FILEIO to use the new interface should significantly - (multiple times) increase performance of FILEIO devices.

+ (up to multiple times) increase performance of FILEIO devices.

Support for O_DIRECT in scst_vdisk handler

At the moment, scst_vdisk handler doesn't support O_DIRECT option and possibility to set it was disabled. This limitation caused by Linux kernel expectation that memory supplied to - read() and write() functions with O_DIRECT flag is mapped to some user space application.

- + read() and write() functions with O_DIRECT flag is mapped to some user space application. + Having O_DIRECT together with above asynchronous FILEIO would be another significant + performance boost for modern solid state devices. For instance, in fio utility + direct AIO long ago proven to be the fastest way to benchmark storage.

+

It is relatively easy to remove that limitation. Function dio_refill_pages() should be modified to check before calling get_user_pages() if current->mm is not NULL. If it is NULL, then, instead of calling get_user_pages(), dio->pages should be filled From 870b2032257ca9a2858b458dc5492168343df166 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 8 Aug 2015 02:54:02 +0000 Subject: [PATCH 3/6] Cleanup git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6465 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- usr/fileio/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 From 90ad49cbaefa4dc05e9b81b6bc63fed17b11f5c0 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 8 Aug 2015 02:57:14 +0000 Subject: [PATCH 4/6] scst_user: optimize performance by exchanging multiple commands/responses per IOCTL git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6466 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- doc/scst_user_spec.sgml | 44 ++++++ scst/include/scst_user.h | 10 ++ scst/src/dev_handlers/scst_user.c | 215 ++++++++++++++++++++------- usr/fileio/common.c | 231 +++++++++++++++++++----------- usr/fileio/common.h | 2 + usr/fileio/fileio.c | 10 +- 6 files changed, 379 insertions(+), 133 deletions(-) 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..d066f8497 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -1908,18 +1908,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 +1927,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 +1936,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 +1953,67 @@ 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; uint64_t ureply; TRACE_ENTRY(); @@ -2007,47 +2061,7 @@ static int dev_user_reply_get_cmd(struct file *file, void __user *arg) kmem_cache_free(user_get_cmd_cachep, cmd); - 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); - - 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(arg, &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", rc, 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); + res = dev_user_get_cmd_to_user(dev, arg, true); out: TRACE_EXIT_RES(res); @@ -2058,6 +2072,106 @@ out_free: goto out; } +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; + + 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("Unable to get reply %d", i); + res = -EFAULT; + goto out_part_replies_done; + } + + 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_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; +} + static long dev_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2076,6 +2190,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 +3631,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); 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..237975afb 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; @@ -744,7 +750,7 @@ int main(int argc, char **argv) PRINT_ERROR("sigaction() failed: %s", strerror(res)); goto out_done; - } + } res = alarm(flush_interval); if (res != 0) { From 51552b5b914cabcf5460092dbd290fa688d8b2e8 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 8 Aug 2015 03:06:23 +0000 Subject: [PATCH 5/6] scst_user: microoptimization/cleanup git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6467 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_user.c | 40 ++++++------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index d066f8497..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, @@ -2012,8 +2011,7 @@ 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_reply_cmd reply; uint64_t ureply; TRACE_ENTRY(); @@ -2036,40 +2034,27 @@ 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); out: TRACE_EXIT_RES(res); return res; - -out_free: - kmem_cache_free(user_get_cmd_cachep, cmd); - goto out; } static int dev_user_reply_get_multi(struct file *file, void __user *arg) @@ -3873,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); @@ -3964,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); @@ -3998,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); From 77d65208826735b78df526349cb5f75e635d190c Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 8 Aug 2015 03:11:37 +0000 Subject: [PATCH 6/6] fileio_tgt: small logging improvement git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6468 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- usr/fileio/fileio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/usr/fileio/fileio.c b/usr/fileio/fileio.c index 237975afb..d218a5daf 100644 --- a/usr/fileio/fileio.c +++ b/usr/fileio/fileio.c @@ -718,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");