From c0151f6cdae6574053ed36e3c532750f18b6716d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 2 Jan 2021 23:16:59 +0000 Subject: [PATCH 01/12] Bump the version number to 3.6.0 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9310 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- doc/scst_user_spec.sgml | 2 +- fcst/fcst.h | 2 +- iscsi-scst/README | 2 +- iscsi-scst/include/iscsi_scst_ver.h | 2 +- iscsi-scst/kernel/isert-scst/isert.c | 4 ++-- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.h | 2 +- qla2x00t/qla2x00-target/README | 2 +- qla2x00t/qla2x00-target/qla2x00t.h | 4 ++-- scst/README | 2 +- scst/include/scst_const.h | 2 +- scst/src/dev_handlers/scst_vdisk.c | 2 +- scst_local/scst_local.c | 2 +- scstadmin/scstadmin.sysfs/scstadmin | 2 +- srpt/src/ib_srpt.c | 4 ++-- usr/fileio/README | 2 +- usr/fileio/common.h | 2 +- usr/include/version.h | 2 +- 17 files changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/scst_user_spec.sgml b/doc/scst_user_spec.sgml index f3d867917..eff8dc3a1 100644 --- a/doc/scst_user_spec.sgml +++ b/doc/scst_user_spec.sgml @@ -10,7 +10,7 @@ SCST user space device handler interface description Vladislav Bolkhovitin -Version 3.5.0 +Version 3.6.0-pre diff --git a/fcst/fcst.h b/fcst/fcst.h index 7191c0d1a..90b6a25fc 100644 --- a/fcst/fcst.h +++ b/fcst/fcst.h @@ -30,7 +30,7 @@ #define NEW_LIBFC_API #endif -#define FT_VERSION "3.5.0" +#define FT_VERSION "3.6.0-pre" #define FT_MODULE "fcst" #define FT_MAX_HW_PENDING_TIME 20 /* max I/O time in seconds */ diff --git a/iscsi-scst/README b/iscsi-scst/README index 687d52b95..08d5b5c21 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -1,7 +1,7 @@ iSCSI SCST target driver ======================== -Version 3.5.0, 21 December 2020 +Version 3.6.0-pre, 02 January 2021 ---------------------------- ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET) diff --git a/iscsi-scst/include/iscsi_scst_ver.h b/iscsi-scst/include/iscsi_scst_ver.h index de8a33665..abac739ea 100644 --- a/iscsi-scst/include/iscsi_scst_ver.h +++ b/iscsi-scst/include/iscsi_scst_ver.h @@ -17,4 +17,4 @@ #define ISCSI_VERSION_STRING_SUFFIX -#define ISCSI_VERSION_STRING "3.5.0" ISCSI_VERSION_STRING_SUFFIX +#define ISCSI_VERSION_STRING "3.6.0-pre" ISCSI_VERSION_STRING_SUFFIX diff --git a/iscsi-scst/kernel/isert-scst/isert.c b/iscsi-scst/kernel/isert-scst/isert.c index 3c998169d..580aa32c6 100644 --- a/iscsi-scst/kernel/isert-scst/isert.c +++ b/iscsi-scst/kernel/isert-scst/isert.c @@ -515,8 +515,8 @@ out: MODULE_AUTHOR("Yan Burman"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SCST); -#define DRV_VERSION "3.5.0" "#" __stringify(OFED_FLAVOR) -#define DRV_RELDATE "21 December 2020" +#define DRV_VERSION "3.6.0-pre" "#" __stringify(OFED_FLAVOR) +#define DRV_RELDATE "02 January 2021" MODULE_DESCRIPTION("iSER target transport driver " "v" DRV_VERSION " (" DRV_RELDATE ")"); module_init(isert_init_module); diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.h b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.h index a3bf6557f..64bef4183 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.h +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.h @@ -19,7 +19,7 @@ /* Driver version number */ #define Q2T_VERSION(a, b, c, d) (((a) << 030) + ((b) << 020) + (c) << 010 + (d)) -#define Q2T_VERSION_CODE Q2T_VERSION(3, 5, 0, 0) +#define Q2T_VERSION_CODE Q2T_VERSION(3, 6, 0, 0) #define Q2T_VERSION_STRING "3.5.0" #define SQA_DEFAULT_TAGS 2048 diff --git a/qla2x00t/qla2x00-target/README b/qla2x00t/qla2x00-target/README index 28b10584d..0c9c7a7be 100644 --- a/qla2x00t/qla2x00-target/README +++ b/qla2x00t/qla2x00-target/README @@ -1,7 +1,7 @@ Target driver for QLogic 2[2-6]xx/8[1-3]xx Fibre Channel cards ============================================================== -Version 3.5.0, 21 December 2020 +Version 3.6.0-pre, 02 January 2021 ---------------------------- This is target driver for QLogic 2[2-6]xx/8[1-3]xx Fibre Channel cards. diff --git a/qla2x00t/qla2x00-target/qla2x00t.h b/qla2x00t/qla2x00-target/qla2x00t.h index 2ed0f4c11..3010efa03 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.h +++ b/qla2x00t/qla2x00-target/qla2x00t.h @@ -34,8 +34,8 @@ /* Version numbers, the same as for the kernel */ #define Q2T_VERSION(a, b, c, d) (((a) << 030) + ((b) << 020) + (c) << 010 + (d)) -#define Q2T_VERSION_CODE Q2T_VERSION(3, 5, 0, 0) -#define Q2T_VERSION_STRING "3.5.0" +#define Q2T_VERSION_CODE Q2T_VERSION(3, 6, 0, 0) +#define Q2T_VERSION_STRING "3.6.0-pre" #define Q2T_PROC_VERSION_NAME "version" #define Q2T_MAX_CDB_LEN 16 diff --git a/scst/README b/scst/README index a28e8448e..4f1626987 100644 --- a/scst/README +++ b/scst/README @@ -1,7 +1,7 @@ Generic SCSI target mid-level for Linux (SCST) ============================================== -Version 3.5.0, 21 December 2020 +Version 3.6.0-pre, 02 January 2021 ---------------------------- SCST is designed to provide unified, consistent interface between SCSI diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index b32f10c77..a604730d5 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -46,7 +46,7 @@ #define SCST_VERSION(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + d) #define SCST_VERSION_CODE SCST_VERSION(3, 4, 0, 0) #define SCST_VERSION_STRING_SUFFIX -#define SCST_VERSION_NAME "3.5.0" +#define SCST_VERSION_NAME "3.6.0-pre" #define SCST_VERSION_STRING SCST_VERSION_NAME SCST_VERSION_STRING_SUFFIX #define SCST_CONST_VERSION SCST_CONST_INTF_VER diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 819977c99..cf0b78c30 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -76,7 +76,7 @@ #define SCST_FIO_VENDOR "SCST_FIO" #define SCST_BIO_VENDOR "SCST_BIO" /* 4 byte ASCII Product Revision Level - left aligned */ -#define SCST_FIO_REV "350 " +#define SCST_FIO_REV "360 " #define MAX_USN_LEN (20+1) /* For '\0' */ #define MAX_INQ_VEND_SPECIFIC_LEN (INQ_BUF_SZ - 96) diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index 79ca63a34..df20874d2 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -89,7 +89,7 @@ static unsigned long scst_local_trace_flag = SCST_LOCAL_DEFAULT_LOG_FLAGS; #define scsi_bufflen(cmd) ((cmd)->request_bufflen) #endif -#define SCST_LOCAL_VERSION "3.5.0" +#define SCST_LOCAL_VERSION "3.6.0-pre" static const char *scst_local_version_date = "20110901"; /* Some statistics */ diff --git a/scstadmin/scstadmin.sysfs/scstadmin b/scstadmin/scstadmin.sysfs/scstadmin index a306cf676..8f6c57537 100755 --- a/scstadmin/scstadmin.sysfs/scstadmin +++ b/scstadmin/scstadmin.sysfs/scstadmin @@ -3,7 +3,7 @@ use strict; use warnings; -my $Version = 'SCST Configurator v3.5.0'; +my $Version = 'SCST Configurator v3.6.0-pre'; # Configures SCST # diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 9f60e63ef..bb4eeefec 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -63,8 +63,8 @@ /* Name of this kernel module. */ #define DRV_NAME "ib_srpt" -#define DRV_VERSION "3.5.0" "#" __stringify(OFED_FLAVOR) -#define DRV_RELDATE "21 December 2020" +#define DRV_VERSION "3.6.0-pre" "#" __stringify(OFED_FLAVOR) +#define DRV_RELDATE "02 January 2021" #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) /* Flags to be used in SCST debug tracing statements. */ #define DEFAULT_SRPT_TRACE_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR \ diff --git a/usr/fileio/README b/usr/fileio/README index bacdd1301..c449facaa 100644 --- a/usr/fileio/README +++ b/usr/fileio/README @@ -1,7 +1,7 @@ User space FILEIO handler ========================= -Version 3.5.0, 21 December 2020 +Version 3.6.0-pre, 02 January 2021 ---------------------------- User space program fileio_tgt uses interface of SCST's scst_user dev diff --git a/usr/fileio/common.h b/usr/fileio/common.h index cf7b89dda..39a73189e 100644 --- a/usr/fileio/common.h +++ b/usr/fileio/common.h @@ -30,7 +30,7 @@ /* 8 byte ASCII Vendor */ #define VENDOR "SCST_USR" /* 4 byte ASCII Product Revision Level - left aligned */ -#define FIO_REV "350 " +#define FIO_REV "360 " #define MAX_USN_LEN (20+1) /* For '\0' */ diff --git a/usr/include/version.h b/usr/include/version.h index df6d06f65..4cd28e9a6 100644 --- a/usr/include/version.h +++ b/usr/include/version.h @@ -19,6 +19,6 @@ #ifndef __VERSION_H #define __VERSION_H -#define VERSION_STR "3.5.0" +#define VERSION_STR "3.6.0-pre" #endif /* __VERSION_H */ From 10abb160b015841455b0c9d39b3eac709a0a4d36 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 00:37:37 +0000 Subject: [PATCH 02/12] scst_vdisk: Fix trailing whitespace removal code in vcdrom_change() Stop looking for trailing whitespace when p == buffer. Remove the local variable 'pp' since it always equals p + 1. Fixes: f381dbb74c84 ("Device sysfs locking reconsidered to remove recently introduced deadlock possibility") git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9311 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index cf0b78c30..eb620613e 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -7664,7 +7664,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) { loff_t err; - char *old_fn, *p, *pp; + char *old_fn, *p; bool old_empty; struct file *old_fd; struct file *old_dif_fd; @@ -7688,16 +7688,16 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, p = buffer; + /* Skip leading whitespace */ while (isspace(*p) && *p != '\0') p++; filename = p; + /* Strip trailing whitespace */ + WARN_ON_ONCE(length == 0); p = &buffer[length-1]; - pp = &buffer[length]; - while (isspace(*p) && (*p != '\0')) { - pp = p; + while (p > buffer && isspace(*p)) p--; - } - *pp = '\0'; + p[1] = '\0'; res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); if (res != 0) From 116ab5adc3a202f3fa94931bc1ea629c211b40dc Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 00:38:14 +0000 Subject: [PATCH 03/12] scst_vdisk: Split several lines that exceed 80 characters This patch does not change any functionality. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9312 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index eb620613e..27dc1e1be 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -519,7 +519,8 @@ static void vdisk_blockio_check_flush_support(struct scst_vdisk_dev *virt_dev) TRACE_ENTRY(); - if (!virt_dev->blockio || virt_dev->rd_only || virt_dev->nv_cache || virt_dev->wt_flag || !virt_dev->dev_active) + if (!virt_dev->blockio || virt_dev->rd_only || virt_dev->nv_cache || + virt_dev->wt_flag || !virt_dev->dev_active) goto out; fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); @@ -564,7 +565,7 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) virt_dev->dev_thin_provisioned = 0; - if (virt_dev->rd_only || (virt_dev->filename == NULL) || !virt_dev->dev_active) + if (virt_dev->rd_only || !virt_dev->filename || !virt_dev->dev_active) goto check; fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); @@ -587,7 +588,8 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) virt_dev->filename); goto check; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || \ + (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) virt_dev->dev_thin_provisioned = blk_queue_discard(bdev_get_queue(inode->i_bdev)); #endif @@ -686,7 +688,8 @@ static int vdisk_get_file_size(const struct scst_vdisk_dev *virt_dev, sBUG_ON(!virt_dev->filename); if (!virt_dev->dev_active) { - TRACE_DBG("Not active dev %s, skip reexaming", virt_dev->dev->virt_name); + TRACE_DBG("Not active dev %s, skip reexaming", + virt_dev->dev->virt_name); res = -EMEDIUMTYPE; goto out; } @@ -7660,8 +7663,7 @@ out: } -static int vcdrom_change(struct scst_vdisk_dev *virt_dev, - char *buffer) +static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) { loff_t err; char *old_fn, *p; @@ -7674,8 +7676,9 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, TRACE_ENTRY(); - TRACE_DBG("virt_dev %s, empty %d, fd %p (dif_fd %p), filename %p", virt_dev->name, - virt_dev->cdrom_empty, virt_dev->fd, virt_dev->dif_fd, virt_dev->filename); + TRACE_DBG("virt_dev %s, empty %d, fd %p (dif_fd %p), filename %p", + virt_dev->name, virt_dev->cdrom_empty, virt_dev->fd, + virt_dev->dif_fd, virt_dev->filename); sBUG_ON(virt_dev->dif_fd); /* DIF is not supported for CDROMs */ From b4746289926e0f0b08c455322d61ebfd7c30d3af Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 00:40:12 +0000 Subject: [PATCH 04/12] scst_lib: Port to Linux kernel v5.10 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9313 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_lib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index e8329d841..0a23fcfe3 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include /* struct kiocb for kernel v4.0 */ #include #include @@ -31,7 +32,9 @@ #include #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) #include +#endif #include #include #ifndef INSIDE_KERNEL_TREE From 6b420cfb32438134a68b06c5772fca5d1c347f36 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:46:48 +0000 Subject: [PATCH 05/12] fcst: Port to Linux kernel v5.10 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9314 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- fcst/ft_cmd.c | 6 ++++++ fcst/ft_io.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/fcst/ft_cmd.c b/fcst/ft_cmd.c index e14e5346f..a5f2dec4b 100644 --- a/fcst/ft_cmd.c +++ b/fcst/ft_cmd.c @@ -14,10 +14,16 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +#include #include #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) #include +#else +#include +#endif #include "fcst.h" /* diff --git a/fcst/ft_io.c b/fcst/ft_io.c index 1ab44f4e5..738fd7a11 100644 --- a/fcst/ft_io.c +++ b/fcst/ft_io.c @@ -19,10 +19,16 @@ * You should have received a copy of the GNU General Public License along with * this program. */ + +#include #include #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) #include +#else +#include +#endif #include "fcst.h" /* From 1c3d35bdabf07fd5ad71379e581d24bb0b8d0c87 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:48:04 +0000 Subject: [PATCH 06/12] scst_vdisk: Rework vdisk_set_wt() and vcdrom_change() This patch breaks the transactional properties of these functions but makes it easier to port these functions to Linux kernel v5.10. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9315 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 62 ++++++++---------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 27dc1e1be..1a2553828 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -1417,6 +1417,16 @@ static void vdisk_close_fd(struct scst_vdisk_dev *virt_dev) } } +static int vdisk_reopen_fd(struct scst_vdisk_dev *virt_dev, bool read_only) +{ + /* + * To do: make this function transactional. That means that it either + * succeeds or does not modify the state of @virt_dev. + */ + vdisk_close_fd(virt_dev); + return vdisk_open_fd(virt_dev, read_only); +} + /* Invoked with scst_mutex held, so no further locking is necessary here. */ static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev) { @@ -4541,7 +4551,6 @@ out_not_sup: static int vdisk_set_wt(struct scst_vdisk_dev *virt_dev, int wt, bool read_only) { int res = 0; - struct file *fd, *dif_fd = NULL; bool old_wt = virt_dev->wt_flag; TRACE_ENTRY(); @@ -4553,42 +4562,20 @@ static int vdisk_set_wt(struct scst_vdisk_dev *virt_dev, int wt, bool read_only) virt_dev->wt_flag = wt; spin_unlock(&virt_dev->flags_lock); - if (virt_dev->fd == NULL) - goto out; - /* - * MODE SELECT is strictly serialized command, so it's safe here - * to reopen fd. + * MODE SELECT is a strictly serialized command so it's safe to reopen + * the fd. */ - - fd = vdev_open_fd(virt_dev, virt_dev->filename, read_only); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - goto out_err; + if (virt_dev->fd) { + res = vdisk_reopen_fd(virt_dev, read_only); + if (res < 0) + goto out_err; } - if (virt_dev->dif_filename != NULL) { - dif_fd = vdev_open_fd(virt_dev, virt_dev->dif_filename, read_only); - if (IS_ERR(dif_fd)) { - res = PTR_ERR(dif_fd); - goto out_err_close_fd; - } - } - - filp_close(virt_dev->fd, NULL); - if (virt_dev->dif_fd) - filp_close(virt_dev->dif_fd, NULL); - - virt_dev->fd = fd; - virt_dev->dif_fd = dif_fd; - out: TRACE_EXIT_RES(res); return res; -out_err_close_fd: - filp_close(fd, NULL); - out_err: spin_lock(&virt_dev->flags_lock); virt_dev->wt_flag = old_wt; @@ -7668,8 +7655,6 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) loff_t err; char *old_fn, *p; bool old_empty; - struct file *old_fd; - struct file *old_dif_fd; const char *filename = NULL; int length = strlen(buffer); int res = 0; @@ -7680,8 +7665,6 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) virt_dev->name, virt_dev->cdrom_empty, virt_dev->fd, virt_dev->dif_fd, virt_dev->filename); - sBUG_ON(virt_dev->dif_fd); /* DIF is not supported for CDROMs */ - if (virt_dev->prevent_allow_medium_removal) { PRINT_ERROR("Prevent medium removal for " "virtual device with name %s", virt_dev->name); @@ -7710,8 +7693,6 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) mutex_lock(&scst_mutex); old_empty = virt_dev->cdrom_empty; - old_fd = virt_dev->fd; - old_dif_fd = virt_dev->dif_fd; old_fn = virt_dev->filename; if (*filename == '\0') { @@ -7739,18 +7720,10 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) if (res != 0) goto out_free_fn; if (virt_dev->fd == NULL) { - res = vdisk_open_fd(virt_dev, true); + res = vdisk_reopen_fd(virt_dev, true); if (res != 0) goto out_free_fn; sBUG_ON(!virt_dev->fd); - - TRACE_DBG("Closing old_fd %p", old_fd); - if (old_fd != NULL) - filp_close(old_fd, NULL); - if (old_dif_fd != NULL) - filp_close(old_dif_fd, NULL); - old_fd = NULL; - old_dif_fd = NULL; } } else { err = 0; @@ -7793,7 +7766,6 @@ out: return res; out_free_fn: - virt_dev->fd = old_fd; kfree(virt_dev->filename); virt_dev->filename = old_fn; From 616730270bf3e0d521451e9b4532a673417df479 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:51:31 +0000 Subject: [PATCH 07/12] scst: Rework vdisk_get_file_size() Linux kernel commit 4e7b5671c6a8 ("block: remove i_bdev"; v5.11-rc1) removes the i_bdev member of struct inode. Hence use blkdev_get_by_path() to open block devices when the struct block_device pointer is needed instead of using filp_open(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9316 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/backport.h | 23 +++++++ scst/include/scst.h | 3 + scst/src/dev_handlers/scst_vdisk.c | 46 +++---------- scst/src/scst_lib.c | 102 ++++++++++++++++++++--------- scst/src/scst_pres.c | 20 ++---- 5 files changed, 114 insertions(+), 80 deletions(-) diff --git a/scst/include/backport.h b/scst/include/backport.h index 49bc48f66..2d3787c8d 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -161,6 +161,29 @@ static inline int bdev_io_opt(struct block_device *bdev) } #endif +/* + * See also commit d4d77629953e ("block: clean up blkdev_get() wrappers and + * their users") # v2.6.38. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) +static inline struct block_device * +blkdev_get_by_path(const char *path, fmode_t mode, void *holder) +{ + struct block_device *bdev; + int err; + + bdev = lookup_bdev(path); + if (IS_ERR(bdev)) + return bdev; + + err = blkdev_get(bdev, mode); + if (err) + return ERR_PTR(err); + + return bdev; +} +#endif + /* */ /* diff --git a/scst/include/scst.h b/scst/include/scst.h index a36053e43..153b8a9e9 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -5543,6 +5543,9 @@ struct scst_data_descriptor { uint64_t sdd_blocks; }; +loff_t scst_file_size(const char *path, umode_t *mode); +loff_t scst_bdev_size(const char *path); +loff_t scst_file_or_bdev_size(const char *path); ssize_t scst_readv(struct file *file, const struct kvec *vec, unsigned long vlen, loff_t *pos); ssize_t scst_writev(struct file *file, const struct kvec *vec, diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 1a2553828..a726a912a 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -679,9 +679,7 @@ check: static int vdisk_get_file_size(const struct scst_vdisk_dev *virt_dev, loff_t *file_size) { - struct inode *inode; - int res = 0; - struct file *fd; + loff_t res; TRACE_ENTRY(); @@ -694,42 +692,18 @@ static int vdisk_get_file_size(const struct scst_vdisk_dev *virt_dev, goto out; } - *file_size = 0; - - fd = filp_open(virt_dev->filename, O_LARGEFILE | O_RDONLY, 0600); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - if ((res == -EMEDIUMTYPE) && virt_dev->blockio) - TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, " - "DRBD passive?", virt_dev->filename); - else - PRINT_ERROR("filp_open(%s) failed: %d", virt_dev->filename, res); + res = scst_file_or_bdev_size(virt_dev->filename); + if (res == -EMEDIUMTYPE && virt_dev->blockio) { + TRACE(TRACE_MINOR, + "Unable to open %s with EMEDIUMTYPE, DRBD passive?", + virt_dev->filename); goto out; } - - inode = file_inode(fd); - - if (virt_dev->blockio && !S_ISBLK(inode->i_mode)) { - PRINT_ERROR("File %s is NOT a block device", virt_dev->filename); - res = -EINVAL; - goto out_close; + if (res < 0) { + PRINT_ERROR("opening %s failed: %lld", virt_dev->filename, res); + goto out; } - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("File %s unsupported mode: mode=0%o\n", - virt_dev->filename, inode->i_mode); - res = -EINVAL; - goto out_close; - } - - *file_size = inode->i_size; - -out_close: - filp_close(fd, NULL); + *file_size = res; out: TRACE_EXIT_RES(res); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 0a23fcfe3..23a4f0acd 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6015,6 +6015,66 @@ ssize_t kernel_write(struct file *file, const void *buf, size_t count, EXPORT_SYMBOL(kernel_write); #endif +/** + * scst_file_size - returns the size of a regular file + * @path: Path of the file. + * @mode: If not NULL, the file mode will be stored in *@mode. + * + * Returns the file size or an error code. + */ +loff_t scst_file_size(const char *path, umode_t *mode) +{ + struct file *filp; + struct inode *inode; + loff_t res; + + filp = filp_open(path, O_LARGEFILE | O_RDONLY, 0600); + if (IS_ERR(filp)) + return PTR_ERR(filp); + inode = file_inode(filp); + if (mode) + *mode = inode->i_mode; + res = S_ISREG(inode->i_mode) ? i_size_read(file_inode(filp)) : -ENOTTY; + filp_close(filp, NULL); + return res; +} +EXPORT_SYMBOL(scst_file_size); + +/** + * scst_bdev_size - returns the size of a block device + * @path: Path of the block device. + * + * Returns the block device size or an error code. + */ +loff_t scst_bdev_size(const char *path) +{ + struct block_device *bdev; + loff_t res; + + bdev = blkdev_get_by_path(path, FMODE_READ, (void *)__func__); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + res = i_size_read(bdev->bd_inode); + blkdev_put(bdev, FMODE_READ); + return res; +} +EXPORT_SYMBOL(scst_bdev_size); + +loff_t scst_file_or_bdev_size(const char *path) +{ + enum { INVALID_FILE_MODE = 0 }; + umode_t mode = INVALID_FILE_MODE; + loff_t res; + + res = scst_file_size(path, &mode); + if (S_ISREG(mode)) + return res; + if (mode != INVALID_FILE_MODE && !S_ISBLK(mode)) + return -EINVAL; + return scst_bdev_size(path); +} +EXPORT_SYMBOL(scst_file_or_bdev_size); + /** * scst_readv - read data from a file into a kernel buffer * @file: File to read from. @@ -15133,7 +15193,6 @@ EXPORT_SYMBOL(scst_path_put); int scst_copy_file(const char *src, const char *dest) { int res = 0; - struct inode *inode; loff_t file_size, pos; uint8_t *buf = NULL; struct file *file_src = NULL, *file_dest = NULL; @@ -15149,6 +15208,12 @@ int scst_copy_file(const char *src, const char *dest) TRACE_DBG("Copying '%s' into '%s'", src, dest); + file_size = scst_file_or_bdev_size(src); + if (file_size < 0) { + res = file_size; + goto out; + } + file_src = filp_open(src, O_RDONLY, 0); if (IS_ERR(file_src)) { res = PTR_ERR(file_src); @@ -15164,20 +15229,6 @@ int scst_copy_file(const char *src, const char *dest) goto out_close; } - inode = file_inode(file_src); - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode); - res = -EINVAL; - goto out_skip; - } - - file_size = inode->i_size; - buf = vmalloc(file_size); if (buf == NULL) { res = -ENOMEM; @@ -15332,13 +15383,18 @@ static int __scst_read_file_transactional(const char *file_name, { int res; struct file *file = NULL; - struct inode *inode; loff_t file_size, pos; TRACE_ENTRY(); TRACE_DBG("Loading file '%s'", file_name); + file_size = scst_file_or_bdev_size(file_name); + if (file_size < 0) { + res = file_size; + goto out; + } + file = filp_open(file_name, O_RDONLY, 0); if (IS_ERR(file)) { res = PTR_ERR(file); @@ -15346,20 +15402,6 @@ static int __scst_read_file_transactional(const char *file_name, goto out; } - inode = file_inode(file); - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode); - res = -EINVAL; - goto out_close; - } - - file_size = inode->i_size; - if (file_size > size) { PRINT_ERROR("Supplied buffer (%d) too small (need %d)", size, (int)file_size); diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 96f3d77df..f38b53cdc 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -660,7 +660,6 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, { int res = 0, rc; struct file *file = NULL; - struct inode *inode; char *buf = NULL; loff_t file_size, pos, data_size; uint64_t sign, version; @@ -676,6 +675,12 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, TRACE_PR("Loading persistent file '%s'", file_name); + file_size = scst_file_or_bdev_size(file_name); + if (file_size < 0) { + res = file_size; + goto out; + } + file = filp_open(file_name, O_RDONLY, 0); if (IS_ERR(file)) { res = PTR_ERR(file); @@ -683,19 +688,6 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, goto out; } - inode = file_inode(file); - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode); - goto out_close; - } - - file_size = inode->i_size; - /* Let's limit the file size by some reasonable number */ if ((file_size == 0) || (file_size >= 15*1024*1024)) { PRINT_ERROR("Invalid PR file size %d", (int)file_size); From 8f2e1df3087c5ce4fb35202d4f11701b48cfa915 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:52:31 +0000 Subject: [PATCH 08/12] scst_vdisk: Use blkdev_get_by_path() to open block devices git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9317 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 107 ++++++++++++++--------------- 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index a726a912a..b2b9e9d39 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -514,8 +514,7 @@ out: static void vdisk_blockio_check_flush_support(struct scst_vdisk_dev *virt_dev) { - struct inode *inode; - struct file *fd; + struct block_device *bdev; TRACE_ENTRY(); @@ -523,33 +522,26 @@ static void vdisk_blockio_check_flush_support(struct scst_vdisk_dev *virt_dev) virt_dev->wt_flag || !virt_dev->dev_active) goto out; - fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); - if (IS_ERR(fd)) { - if ((PTR_ERR(fd) == -EMEDIUMTYPE) && virt_dev->blockio) + bdev = blkdev_get_by_path(virt_dev->filename, FMODE_READ, + (void *)__func__); + if (IS_ERR(bdev)) { + if (PTR_ERR(bdev) == -EMEDIUMTYPE) TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, " "DRBD passive?", virt_dev->filename); else - PRINT_ERROR("filp_open(%s) failed: %ld", - virt_dev->filename, PTR_ERR(fd)); + PRINT_ERROR("blkdev_get_by_path(%s) failed: %ld", + virt_dev->filename, PTR_ERR(bdev)); goto out; } - inode = file_inode(fd); - - if (!S_ISBLK(inode->i_mode)) { - PRINT_ERROR("%s is NOT a block device", virt_dev->filename); - goto out_close; - } - - if (vdisk_blockio_flush(inode->i_bdev, GFP_KERNEL, false, NULL, false) != 0) { + if (vdisk_blockio_flush(bdev, GFP_KERNEL, false, NULL, false) != 0) { PRINT_WARNING("Device %s doesn't support barriers, switching " "to NV_CACHE mode. Read README for more details.", virt_dev->filename); virt_dev->nv_cache = 1; } -out_close: - filp_close(fd, NULL); + blkdev_put(bdev, FMODE_READ); out: TRACE_EXIT(); @@ -558,8 +550,10 @@ out: static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) { + struct block_device *bdev = NULL; struct file *fd = NULL; bool fd_open = false; + int res; TRACE_ENTRY(); @@ -568,30 +562,32 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) if (virt_dev->rd_only || !virt_dev->filename || !virt_dev->dev_active) goto check; - fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); - if (IS_ERR(fd)) { - if ((PTR_ERR(fd) == -EMEDIUMTYPE) && virt_dev->blockio) - TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, " - "DRBD passive?", virt_dev->filename); + if (virt_dev->blockio) { + bdev = blkdev_get_by_path(virt_dev->filename, FMODE_READ, + (void *)__func__); + res = IS_ERR(bdev) ? PTR_ERR(bdev) : 0; + } else { + fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); + res = IS_ERR(fd) ? PTR_ERR(fd) : 0; + } + if (res) { + if (res == -EMEDIUMTYPE && virt_dev->blockio) + TRACE(TRACE_MINOR, + "Unable to open %s with EMEDIUMTYPE, DRBD passive?", + virt_dev->filename); else - PRINT_ERROR("filp_open(%s) failed: %ld", - virt_dev->filename, PTR_ERR(fd)); + PRINT_ERROR("opening %s failed: %d", + virt_dev->filename, res); goto check; } + fd_open = true; if (virt_dev->blockio) { - struct inode *inode = file_inode(fd); - - if (!S_ISBLK(inode->i_mode)) { - PRINT_ERROR("%s is NOT a block device", - virt_dev->filename); - goto check; - } #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || \ (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) virt_dev->dev_thin_provisioned = - blk_queue_discard(bdev_get_queue(inode->i_bdev)); + blk_queue_discard(bdev_get_queue(bdev)); #endif } else { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) @@ -635,7 +631,7 @@ check: struct request_queue *q; sBUG_ON(!fd_open); - q = bdev_get_queue(file_inode(fd)->i_bdev); + q = bdev_get_queue(bdev); virt_dev->unmap_opt_gran = q->limits.discard_granularity >> block_shift; virt_dev->unmap_align = q->limits.discard_alignment >> block_shift; if (virt_dev->unmap_opt_gran == virt_dev->unmap_align) @@ -668,8 +664,12 @@ check: virt_dev->discard_zeroes_data); } - if (fd_open) - filp_close(fd, NULL); + if (fd_open) { + if (virt_dev->blockio) + blkdev_put(bdev, FMODE_READ); + else + filp_close(fd, NULL); + } TRACE_EXIT(); return; @@ -983,28 +983,20 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) { int res; struct scst_device *dev = virt_dev->dev; - struct inode *inode; - struct file *fd; + struct block_device *bdev; struct blk_integrity *bi; const char *bi_profile_name; TRACE_ENTRY(); - fd = vdev_open_fd(virt_dev, virt_dev->filename, virt_dev->rd_only); - if (IS_ERR(fd)) { - res = -EINVAL; + bdev = blkdev_get_by_path(virt_dev->filename, FMODE_READ, + (void *)__func__); + if (IS_ERR(bdev)) { + res = PTR_ERR(bdev); goto out; } - inode = file_inode(fd); - - if (!S_ISBLK(inode->i_mode)) { - PRINT_ERROR("%s is NOT a block device!", virt_dev->filename); - res = -EINVAL; - goto out_close; - } - - bi = bdev_get_integrity(inode->i_bdev); + bi = bdev_get_integrity(bdev); if (bi == NULL) { TRACE_DBG("Block integrity not supported"); goto out_no_bi; @@ -1076,7 +1068,7 @@ out_no_bi: res = 0; out_close: - filp_close(fd, NULL); + blkdev_put(bdev, FMODE_READ); out: TRACE_EXIT_RES(res); @@ -1839,24 +1831,25 @@ static int vdisk_unmap_range(struct scst_cmd *cmd, (unsigned long long)start_lba, blocks); if (virt_dev->blockio) { + struct block_device *bdev = virt_dev->bdev; #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27) sector_t start_sector = start_lba << (cmd->dev->block_shift - 9); sector_t nr_sects = blocks << (cmd->dev->block_shift - 9); - struct inode *inode = file_inode(fd); gfp_t gfp = cmd->cmd_gfp_mask; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31) - err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp); + err = blkdev_issue_discard(bdev, start_sector, nr_sects, gfp); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) \ && !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 34) \ && defined(CONFIG_SUSE_KERNEL)) - err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, - gfp, DISCARD_FL_WAIT); + err = blkdev_issue_discard(bdev, start_sector, nr_sects, gfp, + DISCARD_FL_WAIT); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) - err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, - gfp, BLKDEV_IFL_WAIT); + err = blkdev_issue_discard(bdev, start_sector, nr_sects, gfp, + BLKDEV_IFL_WAIT); #else - err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp, 0); + err = blkdev_issue_discard(bdev, start_sector, nr_sects, gfp, + 0); #endif if (unlikely(err != 0)) { PRINT_ERROR("blkdev_issue_discard() for " From df4c250b8db54e6eec235d7104c28f827f501551 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:53:36 +0000 Subject: [PATCH 09/12] scst_vdisk: Port to Linux kernel v5.11 Use blkdev_get_by_path() to open block devices instead of filp_open(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9318 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 66 ++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index b2b9e9d39..fa36ed4e8 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -6,7 +6,7 @@ * Copyright (C) 2007 Ming Zhang * Copyright (C) 2007 Ross Walker * Copyright (C) 2007 - 2018 Western Digital Corporation - * Copyright (C) 2008 - 2018 Bart Van Assche + * Copyright (C) 2008 - 2020 Bart Van Assche * * SCSI disk (type 0) and CDROM (type 5) dev handler using files * on file systems or block devices (VDISK) @@ -191,6 +191,7 @@ struct scst_vdisk_dev { struct file *fd; struct file *dif_fd; struct block_device *bdev; + fmode_t bdev_mode; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) struct bio_set *vdisk_bioset; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) @@ -1321,21 +1322,35 @@ static void vdisk_detach(struct scst_device *dev) return; } +static bool vdisk_is_open(const struct scst_vdisk_dev *virt_dev) +{ + return virt_dev->fd || virt_dev->bdev; +} + static int vdisk_open_fd(struct scst_vdisk_dev *virt_dev, bool read_only) { int res; sBUG_ON(!virt_dev->filename); - sBUG_ON(virt_dev->fd); + sBUG_ON(vdisk_is_open(virt_dev)); - virt_dev->fd = vdev_open_fd(virt_dev, virt_dev->filename, read_only); - if (IS_ERR(virt_dev->fd)) { - res = PTR_ERR(virt_dev->fd); + if (virt_dev->blockio) { + virt_dev->bdev_mode = FMODE_READ; + if (!read_only) + virt_dev->bdev_mode |= FMODE_WRITE; + virt_dev->bdev = blkdev_get_by_path(virt_dev->filename, + virt_dev->bdev_mode, (void *)__func__); + res = IS_ERR(virt_dev->bdev) ? PTR_ERR(virt_dev->bdev) : 0; + } else { + virt_dev->fd = vdev_open_fd(virt_dev, virt_dev->filename, + read_only); + res = IS_ERR(virt_dev->fd) ? PTR_ERR(virt_dev->fd) : 0; + } + if (res) { + virt_dev->bdev = NULL; virt_dev->fd = NULL; goto out; } - virt_dev->bdev = virt_dev->blockio ? file_inode(virt_dev->fd)->i_bdev : NULL; - res = 0; /* * For block devices, get the optimal I/O size from the block device @@ -1355,27 +1370,34 @@ static int vdisk_open_fd(struct scst_vdisk_dev *virt_dev, bool read_only) } } - TRACE_DBG("virt_dev %s: fd %p open (dif_fd %p)", virt_dev->name, - virt_dev->fd, virt_dev->dif_fd); + TRACE_DBG("virt_dev %s: fd %p %p open (dif_fd %p)", virt_dev->name, + virt_dev->fd, virt_dev->bdev, virt_dev->dif_fd); out: return res; out_close_fd: - filp_close(virt_dev->fd, NULL); - virt_dev->fd = NULL; + if (virt_dev->blockio) { + blkdev_put(virt_dev->bdev, virt_dev->bdev_mode); + virt_dev->bdev = NULL; + } else { + filp_close(virt_dev->fd, NULL); + virt_dev->fd = NULL; + } goto out; } static void vdisk_close_fd(struct scst_vdisk_dev *virt_dev) { - TRACE_DBG("virt_dev %s: closing fd %p (dif_fd %p)", virt_dev->name, - virt_dev->fd, virt_dev->dif_fd); + TRACE_DBG("virt_dev %s: closing fd %p %p (dif_fd %p)", virt_dev->name, + virt_dev->fd, virt_dev->bdev, virt_dev->dif_fd); - if (virt_dev->fd) { + if (virt_dev->bdev) { + blkdev_put(virt_dev->bdev, virt_dev->bdev_mode); + virt_dev->bdev = NULL; + } else if (virt_dev->fd) { filp_close(virt_dev->fd, NULL); virt_dev->fd = NULL; - virt_dev->bdev = NULL; } if (virt_dev->dif_fd) { filp_close(virt_dev->dif_fd, NULL); @@ -1405,7 +1427,7 @@ static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev) virt_dev->tgt_dev_cnt++; - if (virt_dev->fd != NULL) + if (vdisk_is_open(virt_dev)) goto out; if (!virt_dev->nullio && !virt_dev->cdrom_empty) { @@ -1421,6 +1443,7 @@ static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev) } } else { virt_dev->fd = NULL; + virt_dev->bdev = NULL; virt_dev->dif_fd = NULL; } @@ -1810,7 +1833,6 @@ static int vdisk_unmap_range(struct scst_cmd *cmd, #else int res; #endif - struct file *fd = virt_dev->fd; TRACE_ENTRY(); @@ -1868,6 +1890,7 @@ static int vdisk_unmap_range(struct scst_cmd *cmd, } else { loff_t off = start_lba << cmd->dev->block_shift; loff_t len = blocks << cmd->dev->block_shift; + struct file *fd = virt_dev->fd; res = vdisk_unmap_file_range(cmd, virt_dev, off, len, fd); if (unlikely(res != 0)) @@ -3390,7 +3413,7 @@ static enum scst_exec_res blockio_exec(struct scst_cmd *cmd) if (unlikely(!vdisk_parse_offset(&p, cmd))) goto err; - if (unlikely(virt_dev->fd == NULL)) { + if (unlikely(virt_dev->bdev == NULL)) { if (!vdisk_no_fd_allowed_commands(cmd)) { /* * We should not get here, unless the user space @@ -4533,7 +4556,7 @@ static int vdisk_set_wt(struct scst_vdisk_dev *virt_dev, int wt, bool read_only) * MODE SELECT is a strictly serialized command so it's safe to reopen * the fd. */ - if (virt_dev->fd) { + if (vdisk_is_open(virt_dev)) { res = vdisk_reopen_fd(virt_dev, read_only); if (res < 0) goto out_err; @@ -7686,7 +7709,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) res = vdisk_get_file_size(virt_dev, &err); if (res != 0) goto out_free_fn; - if (virt_dev->fd == NULL) { + if (!vdisk_is_open(virt_dev)) { res = vdisk_reopen_fd(virt_dev, true); if (res != 0) goto out_free_fn; @@ -7696,6 +7719,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, char *buffer) err = 0; virt_dev->filename = NULL; virt_dev->fd = NULL; + virt_dev->bdev = NULL; } virt_dev->file_size = err; @@ -7852,7 +7876,7 @@ static int vdev_size_process_store(struct scst_sysfs_work_item *work) virt_dev = dev->dh_priv; - queue_ua = (virt_dev->fd != NULL); + queue_ua = vdisk_is_open(virt_dev); if ((new_size & ((1 << virt_dev->blk_shift) - 1)) == 0) { virt_dev->file_size = new_size; From cb8c3a47256de60fe6119229d49344cc1bd79ec8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:54:08 +0000 Subject: [PATCH 10/12] scst: Fix percpu-ref reinitialization for RHEL 8 / CentOS 8 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9319 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/backport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scst/include/backport.h b/scst/include/backport.h index 2d3787c8d..1752c6e2f 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -1229,12 +1229,14 @@ static inline int pcie_capability_read_dword(struct pci_dev *dev, int pos, #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0) +#if !defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 8 /* * See also commit 09ed79d6d75f ("percpu_ref: introduce PERCPU_REF_ALLOW_REINIT * flag") # v5.3. */ #define PERCPU_REF_ALLOW_REINIT 0 #endif +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) #define PERCPU_COUNT_BIAS (1U << 31) From 7f0900b858a82c1960c4ede78f371930d3ed5814 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:56:01 +0000 Subject: [PATCH 11/12] scst: Modify the code that decides whether or not to process in tasklet context Since the next patch will remove cpu_cmd_count, make this decision independent of cpu_cmd_count. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9320 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_targ.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index c9c3255f8..494f6163d 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -59,7 +59,16 @@ static inline void scst_schedule_tasklet(struct scst_cmd *cmd) i = &scst_percpu_infos[smp_processor_id()]; - if (atomic_read(&i->cpu_cmd_count) <= scst_max_tasklet_cmd) { + /* + * Commands are removed from the list they are on before being + * processed. If both lists are empty that means that at most two + * commands are being processed and hence that processing a + * command in tasklet context is possible without making a CPU core + * spend all its time in interrupt and tasklet context and thereby + * starving threads scheduled on the same CPU core. + */ + if (list_empty_careful(&i->tasklet_cmd_list) && + list_empty_careful(&cmd->cmd_threads->active_cmd_list)) { spin_lock_irqsave(&i->tasklet_lock, flags); TRACE_DBG("Adding cmd %p to tasklet %d cmd list", cmd, smp_processor_id()); @@ -69,8 +78,8 @@ static inline void scst_schedule_tasklet(struct scst_cmd *cmd) tasklet_schedule(&i->tasklet); } else { spin_lock_irqsave(&cmd->cmd_threads->cmd_list_lock, flags); - TRACE_DBG("Too many tasklet commands (%d), adding cmd %p to " - "active cmd list", atomic_read(&i->cpu_cmd_count), cmd); + TRACE_DBG("Too many tasklet commands, adding cmd %p to active cmd list", + cmd); list_add_tail(&cmd->cmd_list_entry, &cmd->cmd_threads->active_cmd_list); wake_up(&cmd->cmd_threads->cmd_list_waitQ); From 1b3d5b60eb51f3772b167702ab5317de9c277e9b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:59:31 +0000 Subject: [PATCH 12/12] scst: Rework the mechanism for suspending activity Use a percpu_ref instead of one atomic counter per CPU. This patch eliminates two atomic instructions from the command processing path. This patch decreases performance for the following configurations because the backported version of percpu_ref uses a single global counter: * RHEL 6.x / CentOS 6.x and before (maintenance ended on 2020-11-30). * Upstream kernel version v3.10 and before. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9321 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 4 +- scst/src/scst_lib.c | 14 +++--- scst/src/scst_main.c | 99 +++++++++++++++++++++++----------------- scst/src/scst_priv.h | 105 +++++++++++++++++++++---------------------- scst/src/scst_targ.c | 63 +++++++++++--------------- 5 files changed, 145 insertions(+), 140 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 153b8a9e9..30d0e2d34 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -2081,7 +2081,7 @@ struct scst_cmd { struct scst_session *sess; /* corresponding session */ - atomic_t *cpu_cmd_counter; + bool counted; atomic_t cmd_ref; @@ -2571,7 +2571,7 @@ struct scst_mgmt_cmd { struct scst_session *sess; - atomic_t *cpu_cmd_counter; + bool counted; /* Mgmt cmd state, one of SCST_MCMD_STATE_* constants */ int state; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 23a4f0acd..61eb4e789 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -5824,7 +5824,7 @@ struct scst_cmd *__scst_create_prepare_internal_cmd(const uint8_t *cdb, } scst_sess_get(res->sess); - res->cpu_cmd_counter = scst_get(); + scst_get_icmd(res); TRACE(TRACE_SCSI, "New internal cmd %p (op %s)", res, scst_get_opcode_name(res)); @@ -7534,10 +7534,8 @@ static void scst_destroy_cmd(struct scst_cmd *cmd) scst_sess_put(cmd->sess); - if (likely(cmd->cpu_cmd_counter)) { - scst_put(cmd->cpu_cmd_counter); - cmd->cpu_cmd_counter = NULL; - } + if (likely(cmd->counted)) + scst_put_cmd(cmd); EXTRACHECKS_BUG_ON(cmd->pre_alloced && cmd->internal); @@ -7777,10 +7775,8 @@ void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd) scst_sess_put(mcmd->sess); - if (mcmd->cpu_cmd_counter) { - scst_put(mcmd->cpu_cmd_counter); - mcmd->cpu_cmd_counter = NULL; - } + if (mcmd->counted) + scst_put_mcmd(mcmd); mempool_free(mcmd, scst_mgmt_mempool); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 6fa785d15..f19889273 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -112,8 +112,6 @@ struct kmem_cache *scst_cmd_cachep; unsigned long scst_trace_flag; #endif -unsigned long scst_flags; - #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) unsigned long scst_poll_ns = SCST_DEF_POLL_NS; #endif @@ -122,6 +120,9 @@ int scst_max_tasklet_cmd = SCST_DEF_MAX_TASKLET_CMD; struct scst_cmd_threads scst_main_cmd_threads; +static bool percpu_ref_killed; +struct percpu_ref scst_cmd_count; +struct percpu_ref scst_mcmd_count; struct scst_percpu_info scst_percpu_infos[NR_CPUS]; spinlock_t scst_mcmd_lock; @@ -796,13 +797,15 @@ static void __printf(2, 3) scst_to_syslog(void *arg, const char *fmt, ...) return; } +/* + * Number of SCST non-management commands, management commands and activities + * that are in progress. Must only be called if both scst_cmd_count and + * scst_mcmd_count are in atomic mode. + */ int scst_get_cmd_counter(void) { - int i, res = 0; - - for (i = 0; i < ARRAY_SIZE(scst_percpu_infos); i++) - res += atomic_read(&scst_percpu_infos[i].cpu_cmd_count); - return res; + return percpu_ref_read(&scst_cmd_count) + + percpu_ref_read(&scst_mcmd_count); } static int scst_susp_wait(unsigned long timeout) @@ -820,7 +823,7 @@ static int scst_susp_wait(unsigned long timeout) t = min(timeout, SCST_SUSP_WAIT_REPORT_TIMEOUT); res = wait_event_interruptible_timeout(scst_dev_cmd_waitQ, - (scst_get_cmd_counter() == 0), t); + percpu_ref_killed, t); if (res > 0) { res = 0; goto out; @@ -836,13 +839,13 @@ static int scst_susp_wait(unsigned long timeout) if (timeout != SCST_SUSPEND_TIMEOUT_UNLIMITED) { res = wait_event_interruptible_timeout(scst_dev_cmd_waitQ, - (scst_get_cmd_counter() == 0), timeout - t); + percpu_ref_killed, timeout - t); if (res == 0) res = -EBUSY; else if (res > 0) res = 0; } else { - wait_event(scst_dev_cmd_waitQ, scst_get_cmd_counter() == 0); + wait_event(scst_dev_cmd_waitQ, percpu_ref_killed); res = 0; } @@ -855,17 +858,18 @@ out: } /* - * scst_suspend_activity() - globally suspend any activity + * scst_suspend_activity() - globally suspend activity * * Description: - * Globally suspends any activity and doesn't return, until there are any - * active commands (state after SCST_CMD_STATE_INIT). Timeout parameter sets - * max time this function will wait for suspending or interrupted by a - * signal with the corresponding error status < 0. If timeout is - * SCST_SUSPEND_TIMEOUT_UNLIMITED, then it will wait virtually forever. - * On success returns 0. + * Globally suspends SCSI command and SCSI management command processing and + * waits until all active commands have finished (state after + * SCST_CMD_STATE_INIT). The timeout parameter defines the maximum time this + * function will wait until activity has been suspended. If this function is + * interrupted by a signal, it returns a negative value. If the timeout value + * is SCST_SUSPEND_TIMEOUT_UNLIMITED, then it will wait virtually forever. + * Returns 0 upon success. * - * New arriving commands stay in the suspended state until + * Newly arriving commands remain in the suspended state until * scst_resume_activity() is called. */ int scst_suspend_activity(unsigned long timeout) @@ -892,14 +896,9 @@ int scst_suspend_activity(unsigned long timeout) if (suspend_count > 1) goto out_up; - set_bit(SCST_FLAG_SUSPENDING, &scst_flags); - set_bit(SCST_FLAG_SUSPENDED, &scst_flags); - /* - * Assignment of SCST_FLAG_SUSPENDING and SCST_FLAG_SUSPENDED must be - * ordered with cpu_cmd_count in scst_get(). Otherwise, lockless logic - * of scst_get() users won't work. - */ - smp_mb__after_set_bit(); + /* Cause scst_get_cmd() to fail. */ + percpu_ref_killed = false; + percpu_ref_kill(&scst_cmd_count); /* * See comment in scst_user.c::dev_user_task_mgmt_fn() for more @@ -921,12 +920,13 @@ int scst_suspend_activity(unsigned long timeout) } res = scst_susp_wait(timeout); - if (res != 0) - goto out_clear; - clear_bit(SCST_FLAG_SUSPENDING, &scst_flags); - /* See comment about smp_mb() above */ - smp_mb__after_clear_bit(); + /* Cause scst_get_mcmd() to fail. */ + percpu_ref_killed = false; + percpu_ref_kill(&scst_mcmd_count); + + if (res != 0) + goto out_resume; if (scst_get_cmd_counter() != 0) TRACE_MGMT_DBG("Waiting for %d active commands finally to " @@ -964,11 +964,6 @@ out: TRACE_EXIT_RES(res); return res; -out_clear: - clear_bit(SCST_FLAG_SUSPENDING, &scst_flags); - /* See comment about smp_mb() above */ - smp_mb__after_clear_bit(); - out_resume: __scst_resume_activity(); EXTRACHECKS_BUG_ON(suspend_count != 0); @@ -994,7 +989,8 @@ static void __scst_resume_activity(void) if (suspend_count > 0) goto out; - clear_bit(SCST_FLAG_SUSPENDED, &scst_flags); + percpu_ref_resurrect(&scst_mcmd_count); + percpu_ref_resurrect(&scst_cmd_count); mutex_lock(&scst_cmd_threads_mutex); list_for_each_entry(l, &scst_cmd_threads_list, lists_list_entry) { @@ -1004,7 +1000,7 @@ static void __scst_resume_activity(void) /* * Wait until scst_init_thread() either is waiting or has reexamined - * scst_flags. + * scst_cmd_count. */ spin_lock_irq(&scst_init_lock); spin_unlock_irq(&scst_init_lock); @@ -2318,6 +2314,13 @@ static void __init scst_print_config(void) PRINT_INFO("%s", buf); } +static void scst_suspended(struct percpu_ref *ref) +{ + WARN_ON_ONCE(ref != &scst_cmd_count && ref != &scst_mcmd_count); + percpu_ref_killed = true; + wake_up_all(&scst_dev_cmd_waitQ); +} + static int __init init_scst(void) { int res, i; @@ -2526,8 +2529,17 @@ static int __init init_scst(void) if (res != 0) goto out_destroy_sgv_pool; + res = percpu_ref_init(&scst_cmd_count, scst_suspended, + PERCPU_REF_ALLOW_REINIT, GFP_KERNEL); + if (res != 0) + goto out_unreg_interface; + + res = percpu_ref_init(&scst_mcmd_count, scst_suspended, + PERCPU_REF_ALLOW_REINIT, GFP_KERNEL); + if (res != 0) + goto out_cmd_count; + for (i = 0; i < ARRAY_SIZE(scst_percpu_infos); i++) { - atomic_set(&scst_percpu_infos[i].cpu_cmd_count, 0); spin_lock_init(&scst_percpu_infos[i].tasklet_lock); INIT_LIST_HEAD(&scst_percpu_infos[i].tasklet_cmd_list); tasklet_init(&scst_percpu_infos[i].tasklet, @@ -2565,10 +2577,14 @@ out: out_thread_free: scst_stop_global_threads(); + percpu_ref_exit(&scst_mcmd_count); +out_cmd_count: + percpu_ref_exit(&scst_cmd_count); + +out_unreg_interface: scsi_unregister_interface(&scst_interface); - out_destroy_sgv_pool: scst_sgv_pools_deinit(); scst_tg_cleanup(); @@ -2651,6 +2667,9 @@ static void __exit exit_scst(void) scst_deinit_threads(&scst_main_cmd_threads); + percpu_ref_exit(&scst_mcmd_count); + percpu_ref_exit(&scst_cmd_count); + scsi_unregister_interface(&scst_interface); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 21061c7a1..9f3437c3b 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -74,20 +74,6 @@ extern unsigned long scst_trace_flag; #endif -/** - ** Bits for scst_flags - **/ - -/* - * Set if new commands initialization is being suspended for a while. - * Used to let TM commands execute while preparing the suspend, since - * RESET or ABORT could be necessary to free SCSI commands. - */ -#define SCST_FLAG_SUSPENDING 0 - -/* Set if new commands initialization is suspended for a while */ -#define SCST_FLAG_SUSPENDED 1 - extern spinlock_t scst_measure_latency_lock; extern atomic_t scst_measure_latency; void scst_update_latency_stats(struct scst_cmd *cmd, int new_state); @@ -184,7 +170,6 @@ extern struct kmem_cache *scst_tgt_cachep; extern struct kmem_cache *scst_tgtd_cachep; extern struct kmem_cache *scst_acgd_cachep; -extern unsigned long scst_flags; extern struct list_head scst_template_list; extern struct list_head scst_dev_list; extern struct list_head scst_dev_type_list; @@ -217,8 +202,9 @@ extern struct list_head scst_active_mgmt_cmd_list; extern struct list_head scst_delayed_mgmt_cmd_list; extern wait_queue_head_t scst_mgmt_cmd_list_waitQ; +extern struct percpu_ref scst_cmd_count; +extern struct percpu_ref scst_mcmd_count; struct scst_percpu_info { - atomic_t cpu_cmd_count; spinlock_t tasklet_lock; struct list_head tasklet_cmd_list; struct tasklet_struct tasklet; @@ -671,51 +657,64 @@ void scst_ext_blocking_done(struct scst_device *dev); int scst_get_suspend_count(void); /* - * Increases global SCST ref counters which prevent from entering into suspended - * activities stage, so protects from any global management operations. + * Increase the global command count if it has not been 'killed'. Use this + * function to protect regular commands. */ -static inline atomic_t *scst_get(void) +static inline bool __must_check scst_get_cmd(struct scst_cmd *cmd) { - atomic_t *a; - - /* - * Avoid that a high I/O load prevents activity to be suspended. See - * also http://sourceforge.net/p/scst/mailman/message/34074831/. - */ - if (unlikely(test_bit(SCST_FLAG_SUSPENDING, &scst_flags))) - mdelay(100); - - /* - * We don't mind if we because of preemption inc counter from another - * CPU as soon in the majority cases we will the correct one. - */ - a = &scst_percpu_infos[raw_smp_processor_id()].cpu_cmd_count; - atomic_inc(a); - TRACE_DBG("Incrementing cpu_cmd_count %p (new value %d)", - a, atomic_read(a)); - /* See comment about smp_mb() in scst_suspend_activity() */ - smp_mb__after_atomic_inc(); - - return a; + if (!percpu_ref_tryget_live(&scst_cmd_count)) + return false; + cmd->counted = true; + return true; } /* - * Decreases global SCST ref counters which prevent from entering into suspended - * activities stage, so protects from any global management operations. On - * all them zero, if suspending activities is waiting, it will be proceed. + * Increase the global management command count if it is not zero. Use this + * function to protect management commands. */ -static inline void scst_put(atomic_t *a) +static inline bool __must_check scst_get_mcmd(struct scst_mgmt_cmd *mcmd) { - int f; + if (!percpu_ref_tryget_live(&scst_mcmd_count)) + return false; + mcmd->counted = true; + return true; +} - f = atomic_dec_and_test(a); - /* See comment about smp_mb() in scst_suspend_activity() */ - if (unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags)) && f) { - TRACE_MGMT_DBG("%s", "Waking up scst_dev_cmd_waitQ"); - wake_up_all(&scst_dev_cmd_waitQ); - } - TRACE_DBG("Decrementing cpu_cmd_count %p (new value %d)", - a, atomic_read(a)); +/* + * Increase the global command count. Use this function to protect internal + * commands. + */ +static inline void scst_get_icmd(struct scst_cmd *cmd) +{ + percpu_ref_get(&scst_cmd_count); + cmd->counted = true; +} + +/* Decrease the global SCST refcount which prevents suspending activity. */ +static inline void scst_put_cmd(struct scst_cmd *cmd) +{ + WARN_ON_ONCE(!cmd->counted); + cmd->counted = false; + percpu_ref_put(&scst_cmd_count); +} + +static inline void scst_put_mcmd(struct scst_mgmt_cmd *mcmd) +{ + WARN_ON_ONCE(!mcmd->counted); + mcmd->counted = false; + percpu_ref_put(&scst_mcmd_count); +} + +/* Whether or not activities are being suspended or have been suspended. */ +static inline bool scst_activity_suspended(void) +{ + return percpu_ref_is_dying(&scst_cmd_count); +} + +/* Returns true if and only if regular commands have already been suspended. */ +static inline bool scst_mcmd_suspended(void) +{ + return percpu_ref_is_dying(&scst_mcmd_count); } int scst_get_cmd_counter(void); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 494f6163d..a3ef29bd1 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -574,7 +574,7 @@ static void __scst_rx_cmd(struct scst_cmd *cmd, struct scst_session *sess, { TRACE_ENTRY(); - WARN_ON_ONCE(cmd->cpu_cmd_counter); + WARN_ON_ONCE(cmd->counted); cmd->sess = sess; scst_sess_get(sess); @@ -4159,7 +4159,7 @@ struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun) * scst_translate_lun() - Translate @cmd->lun into a tgt_dev pointer. * @cmd: SCSI command for which to translate the LUN number. * - * Initialize the following @cmd members: cpu_cmd_counter, cmd_threads, + * Initialize the following @cmd members: counted, cmd_threads, * tgt_dev, cur_order_data, dev and devt. * * The caller must not hold any locks. May be called from IRQ context. The data @@ -4177,9 +4177,7 @@ static int scst_translate_lun(struct scst_cmd *cmd) TRACE_ENTRY(); - cmd->cpu_cmd_counter = scst_get(); - - if (likely(!test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) { + if (likely(scst_get_cmd(cmd))) { TRACE_DBG("Finding tgt_dev for cmd %p (lun %lld)", cmd, (unsigned long long)cmd->lun); res = -1; @@ -4222,12 +4220,9 @@ static int scst_translate_lun(struct scst_cmd *cmd) cmd->sess->initiator_name, cmd->tgt->tgt_name); scst_event_queue_lun_not_found(cmd); } - scst_put(cmd->cpu_cmd_counter); - cmd->cpu_cmd_counter = NULL; + scst_put_cmd(cmd); } } else { - scst_put(cmd->cpu_cmd_counter); - cmd->cpu_cmd_counter = NULL; TRACE_MGMT_DBG("%s", "FLAG SUSPENDED set, skipping"); res = 1; } @@ -4436,7 +4431,8 @@ restart: * There is no need for read barrier here, because we don't care where * this check will be done. */ - susp = test_bit(SCST_FLAG_SUSPENDED, &scst_flags); + susp = scst_activity_suspended(); + if (scst_init_poll_cnt > 0) scst_init_poll_cnt--; @@ -4497,13 +4493,13 @@ restart: return; } -static inline int test_init_cmd_list(void) +/* Whether or not scst_init_thread() should stop waiting. */ +static inline bool test_init_cmd_list(void) { - int res = (!list_empty(&scst_init_cmd_list) && - !test_bit(SCST_FLAG_SUSPENDED, &scst_flags)) || - unlikely(kthread_should_stop()) || - (scst_init_poll_cnt > 0); - return res; + return (!list_empty(&scst_init_cmd_list) && + !scst_activity_suspended()) || + unlikely(kthread_should_stop()) || + (scst_init_poll_cnt > 0); } int scst_init_thread(void *arg) @@ -5024,9 +5020,8 @@ void scst_cmd_tasklet(long p) } /* - * Returns 0 on success, or > 0 if SCST_FLAG_SUSPENDED set and - * SCST_FLAG_SUSPENDING - not. No locks, protection is done by the - * suspended activity. + * Returns 0 on success, or > 0 upon failure. No locks, protection is done by + * suspending activity. */ static int scst_get_mgmt(struct scst_mgmt_cmd *mcmd) { @@ -5034,12 +5029,7 @@ static int scst_get_mgmt(struct scst_mgmt_cmd *mcmd) TRACE_ENTRY(); - mcmd->cpu_cmd_counter = scst_get(); - - if (unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags) && - !test_bit(SCST_FLAG_SUSPENDING, &scst_flags))) { - scst_put(mcmd->cpu_cmd_counter); - mcmd->cpu_cmd_counter = NULL; + if (unlikely(!scst_get_mcmd(mcmd))) { TRACE_MGMT_DBG("%s", "FLAG SUSPENDED set, skipping"); res = 1; goto out; @@ -5051,9 +5041,8 @@ out: } /* - * Returns 0 on success, < 0 if there is no device handler or - * > 0 if SCST_FLAG_SUSPENDED set and SCST_FLAG_SUSPENDING - not. - * No locks, protection is done by the suspended activity. + * Returns 0 on success, < 0 if there is no device handler or > 0 if activity + * has been suspended. No locks, protection is done by the suspended activity. */ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) { @@ -5078,8 +5067,7 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) mcmd->mcmd_tgt_dev = tgt_dev; res = 0; } else { - scst_put(mcmd->cpu_cmd_counter); - mcmd->cpu_cmd_counter = NULL; + scst_put_mcmd(mcmd); res = -1; } @@ -5911,10 +5899,14 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd) res = scst_set_mcmd_next_state(mcmd); goto out; } - __scst_cmd_get(cmd); tgt_dev = cmd->tgt_dev; - if (tgt_dev != NULL) - mcmd->cpu_cmd_counter = scst_get(); + if (tgt_dev && !scst_get_mcmd(mcmd)) { + TRACE_MGMT_DBG("Suspended; skipping mcmd"); + spin_unlock_irq(&sess->sess_list_lock); + res = 1; + goto ret; + } + __scst_cmd_get(cmd); spin_unlock_irq(&sess->sess_list_lock); TRACE_DBG("Cmd to abort %p for tag %llu found (tgt_dev %p)", cmd, (unsigned long long)mcmd->tag, tgt_dev); @@ -5972,6 +5964,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd) out: scst_event_queue_tm_fn_received(mcmd); +ret: TRACE_EXIT_RES(res); return res; } @@ -6851,9 +6844,7 @@ int scst_tm_thread(void *arg) rc = scst_process_mgmt_cmd(mcmd); spin_lock_irq(&scst_mcmd_lock); if (rc > 0) { - if (test_bit(SCST_FLAG_SUSPENDED, &scst_flags) && - !test_bit(SCST_FLAG_SUSPENDING, - &scst_flags)) { + if (scst_mcmd_suspended()) { TRACE_MGMT_DBG("Adding mgmt cmd %p to " "head of delayed mgmt cmd list", mcmd);