Merge branch 'svn-trunk'

This commit is contained in:
Bart Van Assche
2021-01-02 18:59:41 -08:00
26 changed files with 436 additions and 379 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ SCST user space device handler interface description
<name>Vladislav Bolkhovitin</name>
</author>
<date>Version 3.5.0</date>
<date>Version 3.6.0-pre</date>
<toc>
+1 -1
View File
@@ -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 */
+6
View File
@@ -14,10 +14,16 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <scsi/libfc.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
#include <scsi/fc_encode.h>
#else
#include <scsi/fc/fc_ms.h>
#endif
#include "fcst.h"
/*
+6
View File
@@ -19,10 +19,16 @@
* You should have received a copy of the GNU General Public License along with
* this program.
*/
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <scsi/libfc.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
#include <scsi/fc_encode.h>
#else
#include <scsi/fc/fc_ms.h>
#endif
#include "fcst.h"
/*
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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);
@@ -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
+1 -1
View File
@@ -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.
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+25
View File
@@ -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
/* <linux/bsg-lib.h> */
/*
@@ -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)
+5 -2
View File
@@ -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,
+1 -1
View File
@@ -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
+139 -173
View File
@@ -6,7 +6,7 @@
* Copyright (C) 2007 Ming Zhang <blackmagic02881 at gmail dot com>
* Copyright (C) 2007 Ross Walker <rswwalker at hotmail dot com>
* Copyright (C) 2007 - 2018 Western Digital Corporation
* Copyright (C) 2008 - 2018 Bart Van Assche <bvanassche@acm.org>
* Copyright (C) 2008 - 2020 Bart Van Assche <bvanassche@acm.org>
*
* 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;
+80 -39
View File
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*/
#include <linux/version.h>
#include <linux/aio.h> /* struct kiocb for kernel v4.0 */
#include <linux/init.h>
#include <linux/kernel.h>
@@ -31,7 +32,9 @@
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
#include <asm/kmap_types.h>
#endif
#include <asm/unaligned.h>
#include <asm/checksum.h>
#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);
+59 -40
View File
@@ -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);
+6 -14
View File
@@ -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);
+52 -53
View File
@@ -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);
+39 -39
View File
@@ -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);
+1 -1
View File
@@ -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 */
+1 -1
View File
@@ -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
#
+2 -2
View File
@@ -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 \
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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' */
+1 -1
View File
@@ -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 */