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/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"
/*
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/backport.h b/scst/include/backport.h
index 49bc48f66..1752c6e2f 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
+
/* */
/*
@@ -1206,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)
diff --git a/scst/include/scst.h b/scst/include/scst.h
index a36053e43..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;
@@ -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/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..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)
@@ -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)
@@ -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)
@@ -514,41 +515,34 @@ 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();
- 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);
- 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();
@@ -557,39 +551,44 @@ 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();
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);
- 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)
+#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)
@@ -633,7 +632,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)
@@ -666,8 +665,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;
@@ -677,56 +680,31 @@ 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();
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;
}
- *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);
@@ -1006,28 +984,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;
@@ -1099,7 +1069,7 @@ out_no_bi:
res = 0;
out_close:
- filp_close(fd, NULL);
+ blkdev_put(bdev, FMODE_READ);
out:
TRACE_EXIT_RES(res);
@@ -1352,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
@@ -1386,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);
@@ -1414,6 +1405,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)
{
@@ -1426,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) {
@@ -1442,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;
}
@@ -1831,7 +1833,6 @@ static int vdisk_unmap_range(struct scst_cmd *cmd,
#else
int res;
#endif
- struct file *fd = virt_dev->fd;
TRACE_ENTRY();
@@ -1852,24 +1853,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 "
@@ -1888,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))
@@ -3410,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
@@ -4538,7 +4541,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();
@@ -4550,42 +4552,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 (vdisk_is_open(virt_dev)) {
+ 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;
@@ -7660,24 +7640,20 @@ 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, *pp;
+ 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;
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);
-
- sBUG_ON(virt_dev->dif_fd); /* DIF is not supported for CDROMs */
+ 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);
if (virt_dev->prevent_allow_medium_removal) {
PRINT_ERROR("Prevent medium removal for "
@@ -7688,16 +7664,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)
@@ -7707,8 +7683,6 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev,
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') {
@@ -7735,24 +7709,17 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev,
res = vdisk_get_file_size(virt_dev, &err);
if (res != 0)
goto out_free_fn;
- if (virt_dev->fd == NULL) {
- res = vdisk_open_fd(virt_dev, true);
+ if (!vdisk_is_open(virt_dev)) {
+ 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;
virt_dev->filename = NULL;
virt_dev->fd = NULL;
+ virt_dev->bdev = NULL;
}
virt_dev->file_size = err;
@@ -7790,7 +7757,6 @@ out:
return res;
out_free_fn:
- virt_dev->fd = old_fd;
kfree(virt_dev->filename);
virt_dev->filename = old_fn;
@@ -7910,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;
diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c
index e8329d841..61eb4e789 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
@@ -5821,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));
@@ -6012,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.
@@ -7471,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);
@@ -7714,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);
@@ -15130,7 +15189,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;
@@ -15146,6 +15204,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);
@@ -15161,20 +15225,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;
@@ -15329,13 +15379,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);
@@ -15343,20 +15398,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_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_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);
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 c9c3255f8..a3ef29bd1 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);
@@ -565,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);
@@ -4150,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
@@ -4168,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;
@@ -4213,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;
}
@@ -4427,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--;
@@ -4488,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)
@@ -5015,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)
{
@@ -5025,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;
@@ -5042,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)
{
@@ -5069,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;
}
@@ -5902,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);
@@ -5963,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;
}
@@ -6842,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);
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 */