Merged revisions 5510-5518,5520-5527,5532-5533 via svnmerge from

svn+ssh://yanb123@svn.code.sf.net/p/scst/svn/trunk

........
  r5510 | vlnb | 2014-05-09 06:51:10 +0300 (Fri, 09 May 2014) | 8 lines
  
  scst: Make pr path configurable
  
  Make the path of the file in which persistent reservation information
  is stored configurable via sysfs.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org> with some improvements and fixes
........
  r5511 | vlnb | 2014-05-09 06:57:20 +0300 (Fri, 09 May 2014) | 9 lines
  
  scst_vdisk: Introduce three helper functions
  
  Introduce the vdisk_bio_alloc(), vdisk_bio_set_failfast() and
  vdisk_bio_set_hoq() helper functions. This patch does not change any
  functionality.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5512 | vlnb | 2014-05-09 07:14:39 +0300 (Fri, 09 May 2014) | 3 lines
  
  Cleanup
........
  r5513 | vlnb | 2014-05-10 02:20:49 +0300 (Sat, 10 May 2014) | 7 lines
  
  Fix sense code for invalid service actions
  
  According to T10, multibyte opcode commands with not supported service
  actions must be refused with INVALID FIELD IN CDB instead of INVALID
  OPCODE
........
  r5514 | vlnb | 2014-05-10 02:25:13 +0300 (Sat, 10 May 2014) | 3 lines
  
  Cleanup
........
  r5515 | vlnb | 2014-05-10 05:10:22 +0300 (Sat, 10 May 2014) | 3 lines
  
  Improve tracing of Unit Attentions
........
  r5516 | vlnb | 2014-05-10 06:55:11 +0300 (Sat, 10 May 2014) | 3 lines
  
  Follow up for r5513
........
  r5517 | bvassche | 2014-05-10 09:20:01 +0300 (Sat, 10 May 2014) | 6 lines
  
  scst_pres: Fix a recently introduced checkpatch warning
  
  Avoid that checkpatch reports the following:
  
  WARNING: do {} while (0) macros should not be semicolon terminated
........
  r5518 | bvassche | 2014-05-12 18:56:45 +0300 (Mon, 12 May 2014) | 1 line
  
  ib_srpt: Source code comment spelling fix
........
  r5520 | vlnb | 2014-05-15 04:39:12 +0300 (Thu, 15 May 2014) | 11 lines
  
  iscsi-scst: One major number per thread pool
  
  Assign one major number per thread pool instead of as many major
  numbers as there are threads in a thread pool. Do not increment
  'major' if thread pool allocation fails. Micro-optimize
  iscsi_threads_pool_get() by eliminating the assignment to 'fn'
  and the write via snprintf() into name[].
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5521 | vlnb | 2014-05-16 05:05:38 +0300 (Fri, 16 May 2014) | 3 lines
  
  Cleanups
........
  r5522 | vlnb | 2014-05-16 05:37:29 +0300 (Fri, 16 May 2014) | 5 lines
  
  Cleanup
  
  Those functions might be called on some corner cases without pr_mutex held
........
  r5523 | vlnb | 2014-05-17 03:18:42 +0300 (Sat, 17 May 2014) | 8 lines
  
  scst_lib: Clarify scst_init_cmd() documentation
  
  The possible return values of scst_init_cmd() are -1, 0 and 1. Mention
  this in the comment header above that function.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5524 | vlnb | 2014-05-17 04:04:08 +0300 (Sat, 17 May 2014) | 29 lines
  
  scst_main: Fix race between scst_resume_activity() and scst_init_thread()
  
  After SCST_FLAG_SUSPENDED has been cleared it is essential that
  scst_do_job_init() reexamines scst_init_cmd_list to avoid that
  commands get stuck in the command init list. This patch fixes the
  following race condition that can occur if SCST_FLAG_SUSPENDED
  has been set and if scst_init_cmd_list is not empty:
  * scst_do_job_init() returns to scst_init_thread() and leaves the
    commands that were on the init list on that list.
  * scst_init_thread() invokes test_init_cmd_list().
  * test_init_cmd_list() returns false because SCST_FLAG_SUSPENDED
    has been set.
  * scst_resume_activity() clears SCST_FLAG_SUSPENDED and invokes
    wake_up_all(&scst_init_cmd_list_waitQ). However, since
    scst_init_thread() has not yet added the init thread back to
    scst_init_cmd_list_waitQ this wake_up_all() call doesn't do
    anything.
  * scst_init_thread() adds the init thread to scst_init_cmd_list_waitQ
    and unlocks scst_init_lock.
  
  Additionally, remove an unneeded smp_mb__after_clear_bit() call.
  wake_up_all() guarantees that if it wakes up a thread that that
  thread sees all store operations that were performed by the thread
  that invoked wake_up_all() and that preceeded the wake_up_all()
  invocation.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5525 | vlnb | 2014-05-17 04:16:33 +0300 (Sat, 17 May 2014) | 7 lines
  
  scst_vdisk: Introduce vdisk_reexamine() and vdisk_close_fd()
  
  This patch does not change any functionality
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5526 | bvassche | 2014-05-18 14:26:42 +0300 (Sun, 18 May 2014) | 1 line
  
  scst_vdisk: Handle attach failures properly (follow-up for r5525)
........
  r5527 | bvassche | 2014-05-18 19:27:01 +0300 (Sun, 18 May 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5532 | vlnb | 2014-05-21 02:39:57 +0300 (Wed, 21 May 2014) | 3 lines
  
  Prevent potential deadlock between scst_del_threads() and commands taking scst_mutex
........
  r5533 | vlnb | 2014-05-22 05:56:20 +0300 (Thu, 22 May 2014) | 3 lines
  
  Improve handling of aborted internal commands
........


git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5554 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Yan Burman
2014-05-27 11:49:21 +00:00
parent 9bcf7bf616
commit adf364ca2e
15 changed files with 674 additions and 331 deletions
+8 -29
View File
@@ -4141,6 +4141,7 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
struct iscsi_thread_pool *p;
struct iscsi_thread *t;
int i, j, count;
static int major; /* Protected by iscsi_threads_pool_mutex */
TRACE_ENTRY();
@@ -4203,44 +4204,21 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
list_add_tail(&p->thread_pools_list_entry, &iscsi_thread_pools_list);
for (j = 0; j < 2; j++) {
int (*fn)(void *);
char name[25];
static int major;
if (j == 0)
fn = istrd;
else
fn = istwr;
for (i = 0; i < count; i++) {
if (j == 0) {
major++;
if (cpu_mask == NULL)
snprintf(name, sizeof(name), "iscsird%d", i);
else
snprintf(name, sizeof(name), "iscsird%d_%d",
major, i);
} else {
if (cpu_mask == NULL)
snprintf(name, sizeof(name), "iscsiwr%d", i);
else
snprintf(name, sizeof(name), "iscsiwr%d_%d",
major, i);
}
t = kmalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL) {
res = -ENOMEM;
PRINT_ERROR("Failed to allocate thread %s "
"(size %zd)", name, sizeof(*t));
PRINT_ERROR("Failed to allocate thread "
"(size %zd)", sizeof(*t));
goto out_free;
}
t->thr = kthread_run(fn, p, name);
t->thr = kthread_run(j ? istwr : istrd, p,
"iscsi%s%d_%d", j ? "wr" : "rd",
major, i);
if (IS_ERR(t->thr)) {
res = PTR_ERR(t->thr);
PRINT_ERROR("kthread_run() for thread %s failed: %d",
name, res);
PRINT_ERROR("kthread_run() failed: %d", res);
kfree(t);
goto out_free;
}
@@ -4248,6 +4226,7 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
}
}
major++;
res = 0;
TRACE_DBG("Created iSCSI thread pool %p", p);
+8 -8
View File
@@ -3,19 +3,19 @@
ABT_DETAILS="x86_64"
ABT_JOBS=5
ABT_KERNELS=" \
3.14.3 \
3.13.10 \
3.12.17-nc \
3.14.4 \
3.13.11 \
3.12.20-nc \
3.11.10-nc \
3.10.39-nc \
3.10.40-nc \
3.9.11-nc \
3.8.14-nc \
3.8.13.14-nc \
3.7.10-nc \
3.6.11-nc \
3.6.11.9-nc \
3.5.7-nc \
3.4.89-nc \
3.4.91-nc \
3.3.8-nc \
3.2.57-nc \
3.2.59-nc \
3.1.10-nc \
3.0.101-nc \
2.6.39.4-nc \
+6
View File
@@ -1043,6 +1043,12 @@ Each vdisk_fileio's device has the following attributes in
- size_mb - contains size of this virtual device in MB.
- pr_file_name - Full path of the file or block device in which to store
persistent reservation information. The default value for this attribute is
/var/lib/scst/pr/${device_name}. Writing a new value into this sysfs
attribute is only allowed if the device is not exported. Modifying this
sysfs attribute causes the persistent reservation state to be reloaded.
- t10_dev_id - contains and allows to set T10 vendor specific
identifier for Device Identification VPD page (0x83) of INQUIRY data.
By default VDISK handler always generates t10_dev_id for every new
+26 -2
View File
@@ -2533,6 +2533,9 @@ struct scst_device {
/* True if persist through power loss is activated. */
unsigned short pr_aptpl:1;
/* Whether or not pr_file_name has been modified via sysfs. */
unsigned int pr_file_name_is_set:1;
/* Persistent reservation type */
uint8_t pr_type;
@@ -2562,7 +2565,10 @@ struct scst_device {
struct scst_order_data dev_order_data;
/* Persist through power loss files */
/*
* Where to save persistent reservation information. Protected by
* dev_pr_mutex.
*/
char *pr_file_name;
char *pr_file_name1;
@@ -4700,7 +4706,10 @@ struct scst_sysfs_work_item {
};
struct {
struct scst_device *dev;
int new_threads_num;
union {
int new_threads_num;
bool default_val;
};
enum scst_dev_type_threads_pool_type new_threads_pool_type;
};
struct scst_session *sess;
@@ -4743,6 +4752,21 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
void (*done)(void *data, char *sense, int result, int resid));
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) && !defined(RHEL_MAJOR)
/*
* See also patch "mm: add vzalloc() and vzalloc_node() helpers" (commit
* e1ca7788dec6773b1a2bce51b7141948f2b8bccf).
*/
static inline void *vzalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
PAGE_KERNEL);
}
#endif
int scst_get_file_mode(const char *path);
bool scst_parent_dir_exists(const char *path);
struct scst_data_descriptor {
uint64_t sdd_lba;
uint64_t sdd_blocks;
+2 -1
View File
@@ -628,7 +628,8 @@ enum scst_tg_sup {
*************************************************************/
#define SCST_SYSFS_BLOCK_SIZE PAGE_SIZE
#define SCST_PR_DIR "/var/lib/scst/pr"
#define SCST_VAR_DIR "/var/lib/scst"
#define SCST_PR_DIR (SCST_VAR_DIR "/pr")
#define TID_COMMON_SIZE 24
+152 -109
View File
@@ -964,7 +964,7 @@ static struct scst_vdisk_dev *vdev_find(const char *name)
#define VDEV_WT_LABEL "WRITE_THROUGH"
#define VDEV_MODE_PAGES_BUF_SIZE (64*1024)
#define VDEV_MODE_PAGES_DIR "/var/lib/scst/vdev_mode_pages"
#define VDEV_MODE_PAGES_DIR (SCST_VAR_DIR "/vdev_mode_pages")
static int __vdev_save_mode_pages(const struct scst_vdisk_dev *virt_dev,
uint8_t *buf, int size)
@@ -990,18 +990,6 @@ out_overflow:
goto out;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) && !defined(RHEL_MAJOR)
/*
* See also patch "mm: add vzalloc() and vzalloc_node() helpers" (commit
* e1ca7788dec6773b1a2bce51b7141948f2b8bccf).
*/
static void *vzalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
PAGE_KERNEL);
}
#endif
static int vdev_save_mode_pages(const struct scst_vdisk_dev *virt_dev)
{
int res, rc, offs;
@@ -1230,10 +1218,38 @@ out:
return res;
}
/*
* Reexamine size, flush support and thin provisioning support for
* vdisk_fileio, vdisk_blockio and vdisk_cdrom devices. Do not modify the size
* of vdisk_nullio devices.
*/
static int vdisk_reexamine(struct scst_vdisk_dev *virt_dev)
{
int res = 0;
if (!virt_dev->nullio && !virt_dev->cdrom_empty) {
loff_t file_size;
res = vdisk_get_file_size(virt_dev->filename, virt_dev->blockio,
&file_size);
if (res < 0)
goto out;
virt_dev->file_size = file_size;
vdisk_blockio_check_flush_support(virt_dev);
vdisk_check_tp_support(virt_dev);
} else if (virt_dev->cdrom_empty) {
virt_dev->file_size = 0;
}
virt_dev->nblocks = virt_dev->file_size >> virt_dev->blk_shift;
out:
return res;
}
static int vdisk_attach(struct scst_device *dev)
{
int res = 0;
loff_t err;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
@@ -1271,23 +1287,9 @@ static int vdisk_attach(struct scst_device *dev)
dev->dev_rd_only = virt_dev->rd_only;
if (!virt_dev->cdrom_empty) {
if (!virt_dev->nullio) {
res = vdisk_get_file_size(virt_dev->filename,
virt_dev->blockio, &err);
if (res != 0)
goto out;
virt_dev->file_size = err;
TRACE_DBG("size of file: %lld", err);
}
vdisk_blockio_check_flush_support(virt_dev);
vdisk_check_tp_support(virt_dev);
} else
virt_dev->file_size = 0;
virt_dev->nblocks = virt_dev->file_size >> dev->block_shift;
res = vdisk_reexamine(virt_dev);
if (res < 0)
goto out;
if (!virt_dev->cdrom_empty) {
PRINT_INFO("Attached SCSI target virtual %s %s "
@@ -1386,6 +1388,19 @@ out:
return res;
}
static void vdisk_close_fd(struct scst_vdisk_dev *virt_dev)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
lockdep_assert_held(&scst_mutex);
#endif
if (virt_dev->fd) {
filp_close(virt_dev->fd, NULL);
virt_dev->fd = NULL;
virt_dev->bdev = NULL;
}
}
/* Invoked with scst_mutex held, so no further locking is necessary here. */
static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev)
{
@@ -1426,16 +1441,9 @@ static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev)
lockdep_assert_held(&scst_mutex);
#endif
if (--virt_dev->tgt_dev_cnt > 0)
goto out;
if (--virt_dev->tgt_dev_cnt == 0)
vdisk_close_fd(virt_dev);
virt_dev->bdev = NULL;
if (virt_dev->fd) {
filp_close(virt_dev->fd, NULL);
virt_dev->fd = NULL;
}
out:
TRACE_EXIT();
return;
}
@@ -1509,7 +1517,9 @@ static enum compl_status_e vdisk_exec_srv_action_in(struct vdisk_cmd_params *p)
case SAI_GET_LBA_STATUS:
return vdisk_exec_get_lba_status(p);
}
return INVALID_OPCODE;
scst_set_invalid_field_in_cdb(p->cmd, 1,
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return CMD_SUCCEEDED;
}
static enum compl_status_e vdisk_exec_maintenance_in(struct vdisk_cmd_params *p)
@@ -1519,7 +1529,9 @@ static enum compl_status_e vdisk_exec_maintenance_in(struct vdisk_cmd_params *p)
vdisk_exec_report_tpgs(p);
return CMD_SUCCEEDED;
}
return INVALID_OPCODE;
scst_set_invalid_field_in_cdb(p->cmd, 1,
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return CMD_SUCCEEDED;
}
static enum compl_status_e vdisk_exec_send_diagnostic(struct vdisk_cmd_params *p)
@@ -2919,6 +2931,38 @@ static uint64_t vdisk_gen_dev_id_num(const char *virt_dev_name)
#endif
}
static int vdisk_unmap_file_range(struct scst_cmd *cmd,
struct scst_vdisk_dev *virt_dev, loff_t off, loff_t len,
struct file *fd)
{
int res;
TRACE_ENTRY();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
TRACE_DBG("Fallocating range %lld, len %lld",
(unsigned long long)off, (unsigned long long)len);
res = fd->f_op->fallocate(fd,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, off, len);
if (unlikely(res != 0)) {
PRINT_ERROR("fallocate() for %lld, len %lld "
"failed: %d", (unsigned long long)off,
(unsigned long long)len, res);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
res = -EIO;
goto out;
}
#else
res = 0;
#endif
out:
TRACE_EXIT_RES(res);
return res;
}
static int vdisk_unmap_range(struct scst_cmd *cmd,
struct scst_vdisk_dev *virt_dev, uint64_t start_lba, uint32_t blocks)
{
@@ -2977,29 +3021,12 @@ static int vdisk_unmap_range(struct scst_cmd *cmd,
goto out;
#endif
} else {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
struct scst_device *dev = cmd->dev;
const int block_shift = dev->block_shift;
const loff_t s = start_lba << block_shift;
const loff_t l = blocks << block_shift;
loff_t off = start_lba << cmd->dev->block_shift;
loff_t len = blocks << cmd->dev->block_shift;
TRACE_DBG("Fallocating range %lld, len %lld",
(unsigned long long)s, (unsigned long long)l);
err = fd->f_op->fallocate(fd,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, s, l);
if (unlikely(err != 0)) {
PRINT_ERROR("fallocate() for LBA %lld len %lld "
"failed: %d", (unsigned long long)start_lba,
(unsigned long long)blocks, err);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
res = -EIO;
res = vdisk_unmap_file_range(cmd, virt_dev, off, len, fd);
if (unlikely(res != 0))
goto out;
}
#else
sBUG();
#endif
}
success:
@@ -4435,7 +4462,9 @@ out:
static enum compl_status_e vdisk_exec_get_lba_status(struct vdisk_cmd_params *p)
{
/* Changing it don't forget to add it to vdisk_opcode_descriptors! */
return INVALID_OPCODE;
scst_set_invalid_field_in_cdb(p->cmd, 1,
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return CMD_SUCCEEDED;
}
/* SPC-4 REPORT TARGET PORT GROUPS command */
@@ -5064,6 +5093,59 @@ static void blockio_endio(struct bio *bio, int error)
#endif
}
static struct bio *vdisk_bio_alloc(gfp_t gfp_mask, int max_nr_vecs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
return bio_kmalloc(gfp_mask, max_nr_vecs);
#else
return bio_alloc(gfp_mask, max_nr_vecs);
#endif
}
static void vdisk_bio_set_failfast(struct bio *bio)
{
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
bio->bi_rw |= (1 << BIO_RW_FAILFAST);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
bio->bi_rw |= (1 << BIO_RW_FAILFAST_DEV) |
(1 << BIO_RW_FAILFAST_TRANSPORT) |
(1 << BIO_RW_FAILFAST_DRIVER);
#else
bio->bi_rw |= REQ_FAILFAST_DEV |
REQ_FAILFAST_TRANSPORT |
REQ_FAILFAST_DRIVER;
#endif
}
static void vdisk_bio_set_hoq(struct bio *bio)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) || \
defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6
bio->bi_rw |= REQ_SYNC;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
bio->bi_rw |= 1 << BIO_RW_SYNCIO;
#else
bio->bi_rw |= 1 << BIO_RW_SYNC;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) || \
defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6
bio->bi_rw |= REQ_META;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
/*
* Priority boosting was separated from REQ_META in commit 65299a3b
* (kernel 3.1.0).
*/
bio->bi_rw |= REQ_PRIO;
#endif
#elif !defined(RHEL_MAJOR) || RHEL_MAJOR -0 >= 6
/*
* BIO_* and REQ_* flags were unified in commit 7b6d91da (kernel
* 2.6.36).
*/
bio->bi_rw |= BIO_RW_META;
#endif
}
static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
{
struct scst_cmd *cmd = p->cmd;
@@ -5127,11 +5209,7 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
int rc;
if (need_new_bio) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
bio = bio_kmalloc(gfp_mask, max_nr_vecs);
#else
bio = bio_alloc(gfp_mask, max_nr_vecs);
#endif
bio = vdisk_bio_alloc(gfp_mask, max_nr_vecs);
if (!bio) {
PRINT_ERROR("Failed to create bio "
"for data segment %d (cmd %p)",
@@ -5153,51 +5231,16 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
* Better to fail fast w/o any local recovery
* and retries.
*/
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
bio->bi_rw |= (1 << BIO_RW_FAILFAST);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
bio->bi_rw |= (1 << BIO_RW_FAILFAST_DEV) |
(1 << BIO_RW_FAILFAST_TRANSPORT) |
(1 << BIO_RW_FAILFAST_DRIVER);
#else
bio->bi_rw |= REQ_FAILFAST_DEV |
REQ_FAILFAST_TRANSPORT |
REQ_FAILFAST_DRIVER;
#endif
vdisk_bio_set_failfast(bio);
#if 0 /* It could be win, but could be not, so a performance study is needed */
bio->bi_rw |= REQ_SYNC;
#endif
if (fua)
bio->bi_rw |= REQ_FUA;
if (cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) || \
defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6
bio->bi_rw |= REQ_SYNC;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
bio->bi_rw |= 1 << BIO_RW_SYNCIO;
#else
bio->bi_rw |= 1 << BIO_RW_SYNC;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) || \
defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6
bio->bi_rw |= REQ_META;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
/*
* Priority boosting was separated
* from REQ_META in commit 65299a3b
* (kernel 3.1.0).
*/
bio->bi_rw |= REQ_PRIO;
#endif
#elif !defined(RHEL_MAJOR) || RHEL_MAJOR -0 >= 6
/*
* BIO_* and REQ_* flags were unified
* in commit 7b6d91da (kernel 2.6.36).
*/
bio->bi_rw |= BIO_RW_META;
#endif
}
if (cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE)
vdisk_bio_set_hoq(bio);
if (!hbio)
hbio = tbio = bio;
@@ -5209,7 +5252,7 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
rc = bio_add_page(bio, pg, bytes, off);
if (rc < bytes) {
sBUG_ON(rc != 0);
WARN_ON(rc != 0);
need_new_bio = 1;
lba_start0 += thislen >> block_shift;
thislen = 0;
+93 -80
View File
@@ -3759,6 +3759,17 @@ void scst_free_device(struct scst_device *dev)
return;
}
bool scst_device_is_exported(struct scst_device *dev)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
lockdep_assert_held(&scst_mutex);
#endif
WARN_ON_ONCE(!dev->dev_tgt_dev_list.next);
return !list_empty(&dev->dev_tgt_dev_list);
}
/**
* scst_init_mem_lim - initialize memory limits structure
*
@@ -4855,24 +4866,6 @@ out:
return res;
}
static void scst_prelim_finish_internal_cmd(struct scst_cmd *cmd)
{
unsigned long flags;
TRACE_ENTRY();
sBUG_ON(!cmd->internal);
spin_lock_irqsave(&cmd->sess->sess_list_lock, flags);
list_del(&cmd->sess_cmd_list_entry);
spin_unlock_irqrestore(&cmd->sess->sess_list_lock, flags);
__scst_cmd_put(cmd);
TRACE_EXIT();
return;
}
int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
{
int res = 0;
@@ -4933,15 +4926,22 @@ static void scst_complete_request_sense(struct scst_cmd *req_cmd)
if (scsi_status_is_good(req_cmd->status) && (len > 0) &&
scst_sense_valid(buf) && !scst_no_sense(buf)) {
TRACE(TRACE_SCSI, "REQUEST SENSE %p returned valid sense",
req_cmd);
TRACE(TRACE_SCSI|TRACE_MGMT_DEBUG, "REQUEST SENSE %p returned "
"valid sense", req_cmd);
PRINT_BUFF_FLAG(TRACE_SCSI|TRACE_MGMT_DEBUG, "Sense", buf, len);
scst_alloc_set_sense(orig_cmd, scst_cmd_atomic(req_cmd),
buf, len);
} else {
PRINT_ERROR("%s", "Unable to get the sense via "
"REQUEST SENSE, returning HARDWARE ERROR");
scst_set_cmd_error(orig_cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
if (test_bit(SCST_CMD_ABORTED, &req_cmd->cmd_flags) &&
!test_bit(SCST_CMD_ABORTED, &orig_cmd->cmd_flags)) {
TRACE_MGMT_DBG("REQUEST SENSE %p was aborted, but "
"orig_cmd %p - not, retry", req_cmd, orig_cmd);
} else {
PRINT_ERROR("%s", "Unable to get the sense via "
"REQUEST SENSE, returning HARDWARE ERROR");
scst_set_cmd_error(orig_cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
}
}
if (len > 0)
@@ -4983,16 +4983,15 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp,
struct scst_cmd *ws_cmd = wsp->ws_orig_cmd;
struct scatterlist *ws_sg = wsp->ws_sg;
int ws_sg_cnt = wsp->ws_sg_cnt;
int res, i;
int res;
uint8_t write16_cdb[16];
struct scatterlist *sg;
int sg_cnt, len = blocks << ws_cmd->dev->block_shift;
struct sgv_pool_obj *sgv = NULL;
int len = blocks << ws_cmd->dev->block_shift;
struct scst_cmd *cmd;
int64_t cur_lba;
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(blocks > ws_sg_cnt);
if (unlikely(test_bit(SCST_CMD_ABORTED, &ws_cmd->cmd_flags)) ||
unlikely(ws_cmd->completed)) {
TRACE_DBG("ws cmd %p aborted or completed (%d), aborting "
@@ -5020,44 +5019,8 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp,
cmd->tgt_i_priv = wsp;
if ((ws_cmd->cdb[1] & 0x6) == 0) {
TRACE_DBG("Using direct ws_sg %p (cnt %d)", ws_sg, ws_sg_cnt);
sg = ws_sg;
EXTRACHECKS_BUG_ON(blocks > ws_sg_cnt);
sg_cnt = blocks;
goto set_add;
}
sg = sgv_pool_alloc(ws_cmd->tgt_dev->pool, len, GFP_KERNEL, 0,
&sg_cnt, &sgv, &cmd->dev->dev_mem_lim, NULL);
if (sg == NULL) {
PRINT_ERROR("Unable to alloc sg for %d blocks", blocks);
res = -ENOMEM;
goto out_free_cmd;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
sg_copy(sg, ws_sg, ws_sg_cnt, len, KM_USER0, KM_USER1);
#else
sg_copy(sg, ws_sg, ws_sg_cnt, len);
#endif
cur_lba = lba;
for (i = 0; i < sg_cnt; i++) {
int cur_offs = 0;
while (cur_offs < sg[i].length) {
uint8_t *q;
q = &((int8_t *)(page_address(sg_page(&sg[i]))))[cur_offs];
*((uint64_t *)q) = cur_lba;
cur_offs += ws_cmd->dev->block_size;
cur_lba++;
}
}
set_add:
cmd->tgt_i_sg = sg;
cmd->tgt_i_sg_cnt = sg_cnt;
cmd->out_sgv = sgv; /* hacky, but it isn't used for WRITE(16) */
cmd->tgt_i_sg = ws_sg;
cmd->tgt_i_sg_cnt = blocks;
cmd->tgt_i_data_buf_alloced = 1;
wsp->ws_cur_lba += blocks;
@@ -5075,9 +5038,6 @@ out:
TRACE_EXIT_RES(res);
return res;
out_free_cmd:
scst_prelim_finish_internal_cmd(cmd);
out_busy:
scst_set_busy(ws_cmd);
goto out;
@@ -5115,9 +5075,6 @@ static void scst_ws_write_cmd_finished(struct scst_cmd *cmd)
TRACE_DBG("Write cmd %p finished (ws cmd %p, ws_cur_in_flight %d)",
cmd, ws_cmd, wsp->ws_cur_in_flight);
if ((ws_cmd->cdb[1] & 0x6) != 0)
sgv_pool_free(cmd->out_sgv, &cmd->dev->dev_mem_lim);
cmd->sg = NULL;
cmd->sg_cnt = 0;
@@ -5237,8 +5194,11 @@ void scst_write_same(struct scst_cmd *cmd)
goto out_done;
}
if (((cmd->cdb[1] & 0x6) == 0x6) || ((cmd->cdb[1] & 0xE0) != 0)) {
scst_set_invalid_field_in_cdb(cmd, 1, 0);
if (unlikely((cmd->cdb[1] & 0x6) != 0)) {
TRACE(TRACE_MINOR, "LBDATA and/or PBDATA (ctrl %x) are not "
"supported", cmd->cdb[1]);
scst_set_invalid_field_in_cdb(cmd, 1,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 1);
goto out_done;
}
@@ -8172,6 +8132,8 @@ again:
UA_entry = list_first_entry(&cmd->tgt_dev->UA_list, typeof(*UA_entry),
UA_list_entry);
TRACE_MGMT_DBG("Setting pending UA %p to cmd %p", UA_entry, cmd);
TRACE_DBG("next %p UA_entry %p",
cmd->tgt_dev->UA_list.next, UA_entry);
@@ -8301,8 +8263,13 @@ static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
memset(UA_entry, 0, sizeof(*UA_entry));
UA_entry->global_UA = (flags & SCST_SET_UA_FLAG_GLOBAL) != 0;
if (UA_entry->global_UA)
TRACE_MGMT_DBG("Queueing global UA %p", UA_entry);
TRACE(TRACE_MGMT_DEBUG|TRACE_SCSI, "Queuing new %sUA %p (%x:%x:%x, "
"d_sense %d) to tgt_dev %p (dev %s, initiator %s)",
UA_entry->global_UA ? "global " : "", UA_entry, sense[2],
sense[12], sense[13], tgt_dev->dev->d_sense, tgt_dev,
tgt_dev->dev->virt_name, tgt_dev->sess->initiator_name);
TRACE_BUFF_FLAG(TRACE_DEBUG, "UA sense", sense, sense_len);
if (sense_len > (int)sizeof(UA_entry->UA_sense_buffer)) {
PRINT_WARNING("Sense truncated (needed %d), shall you increase "
@@ -8314,9 +8281,6 @@ static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
set_bit(SCST_TGT_DEV_UA_PENDING, &tgt_dev->tgt_dev_flags);
TRACE_MGMT_DBG("Adding new UA to tgt_dev %p (dev %s, initiator %s)",
tgt_dev, tgt_dev->dev->virt_name, tgt_dev->sess->initiator_name);
if (flags & SCST_SET_UA_FLAG_AT_HEAD)
list_add(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
else
@@ -10143,6 +10107,55 @@ int scst_read_file_transactional(const char *name, const char *name1,
}
EXPORT_SYMBOL_GPL(scst_read_file_transactional);
/*
* Return the file mode if @path exists or an error code if opening @path via
* filp_open() in read-only mode failed.
*/
int scst_get_file_mode(const char *path)
{
struct file *file;
int res;
file = filp_open(path, O_RDONLY, 0400);
if (IS_ERR(file)) {
res = PTR_ERR(file);
goto out;
}
res = file->f_dentry->d_inode->i_mode;
filp_close(file, NULL);
out:
return res;
}
EXPORT_SYMBOL(scst_get_file_mode);
/*
* Return true if either @path does not contain a slash or if the directory
* specified in @path exists.
*/
bool scst_parent_dir_exists(const char *path)
{
const char *last_slash = strrchr(path, '/');
const char *dir;
int dir_mode;
bool res = true;
if (last_slash && last_slash > path) {
dir = kasprintf(GFP_KERNEL, "%.*s", (int)(last_slash - path),
path);
if (dir) {
dir_mode = scst_get_file_mode(dir);
kfree(dir);
res = dir_mode >= 0 && S_ISDIR(dir_mode);
} else {
res = false;
}
}
return res;
}
EXPORT_SYMBOL(scst_parent_dir_exists);
static void __init scst_scsi_op_list_init(void)
{
int i;
+17 -9
View File
@@ -1060,17 +1060,20 @@ static void __scst_resume_activity(void)
goto out;
clear_bit(SCST_FLAG_SUSPENDED, &scst_flags);
/*
* The barrier is needed to make sure all woken up threads see the
* cleared flag. Not sure if it's really needed, but let's be safe.
*/
smp_mb__after_clear_bit();
mutex_lock(&scst_cmd_threads_mutex);
list_for_each_entry(l, &scst_cmd_threads_list, lists_list_entry) {
wake_up_all(&l->cmd_list_waitQ);
}
mutex_unlock(&scst_cmd_threads_mutex);
/*
* Wait until scst_init_thread() either is waiting or has reexamined
* scst_flags.
*/
spin_lock_irq(&scst_init_lock);
spin_unlock_irq(&scst_init_lock);
wake_up_all(&scst_init_cmd_list_waitQ);
spin_lock_irq(&scst_mcmd_lock);
@@ -1198,13 +1201,13 @@ out:
#ifndef CONFIG_SCST_PROC
out_del_unlocked:
mutex_lock(&scst_mutex);
list_del(&dev->dev_list_entry);
list_del_init(&dev->dev_list_entry);
mutex_unlock(&scst_mutex);
scst_free_device(dev);
goto out;
#else
out_del_locked:
list_del(&dev->dev_list_entry);
list_del_init(&dev->dev_list_entry);
#endif
out_free_dev:
@@ -1266,7 +1269,7 @@ static void scst_unregister_device(struct scsi_device *scsidp)
dev->dev_unregistering = 1;
list_del(&dev->dev_list_entry);
list_del_init(&dev->dev_list_entry);
scst_dg_dev_remove_by_dev(dev);
@@ -1418,6 +1421,11 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
scst_virt_dev_last_id = 1;
}
res = scst_pr_set_file_name(dev, NULL, "%s/%s", SCST_PR_DIR,
dev->virt_name);
if (res != 0)
goto out_free_dev;
res = scst_pr_init_dev(dev);
if (res != 0)
goto out_free_dev;
@@ -1516,7 +1524,7 @@ void scst_unregister_virtual_device(int id)
dev->dev_unregistering = 1;
list_del(&dev->dev_list_entry);
list_del_init(&dev->dev_list_entry);
scst_pr_clear_dev(dev);
+177 -75
View File
@@ -45,6 +45,7 @@
#endif
#include <linux/vmalloc.h>
#include <asm/unaligned.h>
#include <stdarg.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
#include <linux/mount.h>
@@ -74,6 +75,19 @@
#define isblank(c) ((c) == ' ' || (c) == '\t')
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && defined(CONFIG_LOCKDEP)
#define scst_assert_pr_mutex_held(dev) \
do { \
if (dev->dev_list_entry.next && \
!list_empty(&dev->dev_list_entry)) \
lockdep_assert_held(&dev->dev_pr_mutex); \
} while (0)
#else
static inline void scst_assert_pr_mutex_held(struct scst_device *dev)
{
}
#endif
static inline int tid_size(const uint8_t *tid)
{
sBUG_ON(tid == NULL);
@@ -174,6 +188,8 @@ out_error:
static inline void scst_pr_set_holder(struct scst_device *dev,
struct scst_dev_registrant *holder, uint8_t scope, uint8_t type)
{
scst_assert_pr_mutex_held(dev);
dev->pr_is_set = 1;
dev->pr_scope = scope;
dev->pr_type = type;
@@ -190,6 +206,8 @@ static bool scst_pr_is_holder(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if (!dev->pr_is_set)
goto out;
@@ -209,6 +227,8 @@ out:
/* Must be called under dev_pr_mutex */
void scst_pr_dump_prs(struct scst_device *dev, bool force)
{
scst_assert_pr_mutex_held(dev);
if (!force) {
#if defined(CONFIG_SCST_DEBUG)
if ((trace_flag & TRACE_PRES) == 0)
@@ -265,6 +285,8 @@ static void scst_pr_find_registrants_list_all(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
TRACE_PR("Finding all registered records for device '%s' "
"with exclude reg key %016llx",
dev->virt_name, be64_to_cpu(exclude_reg->key));
@@ -291,6 +313,8 @@ static void scst_pr_find_registrants_list_key(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
TRACE_PR("Finding registrants for device '%s' with key %016llx",
dev->virt_name, be64_to_cpu(key));
@@ -320,6 +344,8 @@ static struct scst_dev_registrant *scst_pr_find_reg(
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
list_for_each_entry(reg, &dev->dev_registrants_list,
dev_registrants_list_entry) {
if ((reg->rel_tgt_id == rel_tgt_id) &&
@@ -338,6 +364,8 @@ static void scst_pr_clear_reservation(struct scst_device *dev)
{
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
WARN_ON(!dev->pr_is_set);
dev->pr_is_set = 0;
@@ -355,6 +383,8 @@ static void scst_pr_clear_holder(struct scst_device *dev)
{
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
WARN_ON(!dev->pr_is_set);
if (dev->pr_type == TYPE_WRITE_EXCLUSIVE_ALL_REG ||
@@ -382,6 +412,8 @@ static struct scst_dev_registrant *scst_pr_add_registrant(
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
sBUG_ON(dev == NULL);
sBUG_ON(transport_id == NULL);
@@ -465,6 +497,8 @@ static void scst_pr_remove_registrant(struct scst_device *dev,
{
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
TRACE_PR("Removing registrant %s/%d (reg %p, tgt_dev %p, key %016llx, "
"dev %s)", debug_transport_id_to_initiator_name(reg->transport_id),
reg->rel_tgt_id, reg, reg->tgt_dev, be64_to_cpu(reg->key),
@@ -485,6 +519,16 @@ static void scst_pr_remove_registrant(struct scst_device *dev,
return;
}
static void scst_pr_remove_registrants(struct scst_device *dev)
{
struct scst_dev_registrant *reg, *tmp_reg;
list_for_each_entry_safe(reg, tmp_reg, &dev->dev_registrants_list,
dev_registrants_list_entry) {
scst_pr_remove_registrant(dev, reg);
}
}
/* Must be called under dev_pr_mutex */
static void scst_pr_send_ua_reg(struct scst_device *dev,
struct scst_dev_registrant *reg,
@@ -494,6 +538,8 @@ static void scst_pr_send_ua_reg(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
scst_set_sense(ua, sizeof(ua), dev->d_sense, key, asc, ascq);
TRACE_PR("Queueing UA [%x %x %x]: registrant %s/%d (%p), tgt_dev %p, "
@@ -517,6 +563,8 @@ static void scst_pr_send_ua_all(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
list_for_each_entry(reg, &dev->dev_registrants_list,
dev_registrants_list_entry) {
if (reg != exclude_reg)
@@ -537,6 +585,8 @@ static void scst_pr_abort_reg(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if (reg->tgt_dev == NULL) {
TRACE_PR("Registrant %s/%d (%p, key 0x%016llx) has no session",
debug_transport_id_to_initiator_name(reg->transport_id),
@@ -612,6 +662,10 @@ static int scst_pr_do_load_device_file(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
scst_pr_remove_registrants(dev);
old_fs = get_fs();
set_fs(KERNEL_DS);
@@ -767,10 +821,12 @@ out:
static int scst_pr_load_device_file(struct scst_device *dev)
{
int res;
int res, rc;
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if (dev->pr_file_name == NULL || dev->pr_file_name1 == NULL) {
PRINT_ERROR("Invalid file paths for '%s'", dev->virt_name);
res = -EINVAL;
@@ -779,12 +835,20 @@ static int scst_pr_load_device_file(struct scst_device *dev)
res = scst_pr_do_load_device_file(dev, dev->pr_file_name);
if (res == 0)
goto out;
goto out_dump;
else if (res == -ENOMEM)
goto out;
res = scst_pr_do_load_device_file(dev, dev->pr_file_name1);
rc = res;
res = scst_pr_do_load_device_file(dev, dev->pr_file_name1);
if (res != 0) {
if (res == -ENOENT)
res = rc;
goto out;
}
out_dump:
scst_pr_dump_prs(dev, false);
out:
@@ -799,6 +863,8 @@ static void scst_pr_remove_device_files(struct scst_tgt_dev *tgt_dev)
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
res = dev->pr_file_name ? scst_remove_file(dev->pr_file_name) : -ENOENT;
res = dev->pr_file_name1 ? scst_remove_file(dev->pr_file_name1) : -ENOENT;
@@ -821,6 +887,8 @@ void scst_pr_sync_device_file(struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if ((dev->pr_aptpl == 0) || list_empty(&dev->dev_registrants_list)) {
scst_pr_remove_device_files(tgt_dev);
goto out;
@@ -1003,107 +1071,105 @@ write_error_close:
goto out_set_fs;
}
static int scst_pr_check_pr_path(void)
#endif /* CONFIG_SCST_PROC */
/**
* scst_pr_set_file_name - set name of file in which to save PR information
* @dev: SCST device.
* @prev: If not NULL, the current path will be stored in *@prev. It is the
* responsibility of the caller to invoke kfree(*@prev) at an
* appropriate time.
* @fmt: Full path of the file in which to save PR info.
*
* This function must be called either while @dev is not on the device list
* or with scst_mutex held.
*/
int scst_pr_set_file_name(struct scst_device *dev, char **prev,
const char *fmt, ...)
{
int res;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
struct nameidata nd;
#else
struct path path;
#endif
va_list args;
char *pr_file_name = NULL, *bkp = NULL;
int file_mode, res = -EINVAL;
mm_segment_t old_fs = get_fs();
scst_assert_pr_mutex_held(dev);
TRACE_ENTRY();
sBUG_ON(!fmt);
set_fs(KERNEL_DS);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
res = path_lookup(SCST_PR_DIR, 0, &nd);
if (res == 0)
scst_path_put(&nd);
#else
res = kern_path(SCST_PR_DIR, 0, &path);
if (res == 0)
path_put(&path);
#endif
if (res != 0) {
PRINT_ERROR("Unable to find %s (err %d), you should create "
"this directory manually or reinstall SCST",
SCST_PR_DIR, res);
goto out_setfs;
res = -ENOMEM;
va_start(args, fmt);
pr_file_name = kvasprintf(GFP_KERNEL, fmt, args);
va_end(args);
if (!pr_file_name) {
PRINT_ERROR("Unable to kvasprintf() new PR file name");
goto out;
}
out_setfs:
set_fs(old_fs);
res = -EINVAL;
if (pr_file_name[0] != '/') {
PRINT_ERROR("PR file name must be absolute!");
goto out;
}
TRACE_EXIT_RES(res);
file_mode = scst_get_file_mode(pr_file_name);
if (file_mode >= 0 && !S_ISREG(file_mode) && !S_ISBLK(file_mode)) {
PRINT_ERROR("PR file name must be file or block device!");
goto out;
}
res = -ENOENT;
if (!scst_parent_dir_exists(pr_file_name)) {
PRINT_ERROR("PR file name parent directory doesn't exist");
goto out;
}
res = -ENOMEM;
bkp = kasprintf(GFP_KERNEL, "%s.1", pr_file_name);
if (!bkp) {
PRINT_ERROR("Unable to kasprintf() backup PR file name");
goto out;
}
if (prev) {
*prev = dev->pr_file_name;
dev->pr_file_name = pr_file_name;
pr_file_name = NULL;
} else
swap(dev->pr_file_name, pr_file_name);
swap(dev->pr_file_name1, bkp);
res = 0;
out:
kfree(pr_file_name);
kfree(bkp);
return res;
}
#endif /* CONFIG_SCST_PROC */
/* Called under scst_mutex */
/* Must be called under dev_pr_mutex or before dev is on the device list. */
int scst_pr_init_dev(struct scst_device *dev)
{
int res = 0;
TRACE_ENTRY();
dev->pr_file_name = kasprintf(GFP_KERNEL, "%s/%s", SCST_PR_DIR,
dev->virt_name);
if (dev->pr_file_name == NULL) {
PRINT_ERROR("Allocation of device '%s' file path failed",
dev->virt_name);
res = -ENOMEM;
goto out;
}
dev->pr_file_name1 = kasprintf(GFP_KERNEL, "%s/%s.1", SCST_PR_DIR,
dev->virt_name);
if (dev->pr_file_name1 == NULL) {
PRINT_ERROR("Allocation of device '%s' backup file path failed",
dev->virt_name);
res = -ENOMEM;
goto out_free_name;
}
scst_assert_pr_mutex_held(dev);
sBUG_ON(!dev->pr_file_name || !dev->pr_file_name1);
#ifndef CONFIG_SCST_PROC
res = scst_pr_check_pr_path();
if (res == 0) {
res = scst_pr_load_device_file(dev);
if (res == -ENOENT)
res = 0;
}
res = scst_pr_load_device_file(dev);
if (res == -ENOENT)
res = 0;
#endif
if (res != 0)
goto out_free_name1;
out:
TRACE_EXIT_RES(res);
return res;
out_free_name1:
kfree(dev->pr_file_name1);
dev->pr_file_name1 = NULL;
out_free_name:
kfree(dev->pr_file_name);
dev->pr_file_name = NULL;
goto out;
}
/* Called under scst_mutex */
void scst_pr_clear_dev(struct scst_device *dev)
{
struct scst_dev_registrant *reg, *tmp_reg;
TRACE_ENTRY();
list_for_each_entry_safe(reg, tmp_reg, &dev->dev_registrants_list,
dev_registrants_list_entry) {
scst_pr_remove_registrant(dev, reg);
}
scst_pr_remove_registrants(dev);
kfree(dev->pr_file_name);
kfree(dev->pr_file_name1);
@@ -1198,6 +1264,8 @@ static int scst_pr_register_with_spec_i_pt(struct scst_cmd *cmd,
struct scst_dev_registrant *reg;
uint8_t *transport_id;
scst_assert_pr_mutex_held(cmd->dev);
action_key = get_unaligned((__be64 *)&buffer[8]);
ext_size = get_unaligned_be32(&buffer[24]);
@@ -1315,6 +1383,8 @@ static void scst_pr_unregister(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
TRACE_PR("Unregistering key %0llx", reg->key);
is_holder = scst_pr_is_holder(dev, reg);
@@ -1346,6 +1416,8 @@ static void scst_pr_unregister_all_tg_pt(struct scst_device *dev,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
/*
* We can't use scst_mutex here since the caller already holds
* dev_pr_mutex.
@@ -1388,6 +1460,8 @@ static int scst_pr_register_on_tgt_id(struct scst_cmd *cmd,
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
TRACE_PR("rel_tgt_id %d, spec_i_pt %d", rel_tgt_id, spec_i_pt);
if (spec_i_pt) {
@@ -1433,6 +1507,8 @@ static int scst_pr_register_all_tg_pt(struct scst_cmd *cmd, uint8_t *buffer,
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
/*
* We can't use scst_mutex here because the caller already holds
* dev_pr_mutex.
@@ -1478,6 +1554,8 @@ static int __scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer,
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
if (all_tg_pt) {
res = scst_pr_register_all_tg_pt(cmd, buffer, buffer_size,
spec_i_pt, &rollback_list);
@@ -1524,6 +1602,8 @@ void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
aptpl = buffer[20] & 0x01;
spec_i_pt = (buffer[20] >> 3) & 0x01;
all_tg_pt = (buffer[20] >> 2) & 0x01;
@@ -1618,6 +1698,8 @@ void scst_pr_register_and_ignore(struct scst_cmd *cmd, uint8_t *buffer,
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
aptpl = buffer[20] & 0x01;
all_tg_pt = (buffer[20] >> 2) & 0x01;
action_key = get_unaligned((__be64 *)&buffer[8]);
@@ -1696,6 +1778,8 @@ void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer,
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
aptpl = buffer[17] & 0x01;
key = get_unaligned((__be64 *)&buffer[0]);
action_key = get_unaligned((__be64 *)&buffer[8]);
@@ -1839,6 +1923,8 @@ void scst_pr_reserve(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
key = get_unaligned((__be64 *)&buffer[0]);
scope = cmd->cdb[2] >> 4;
type = cmd->cdb[2] & 0x0f;
@@ -1926,6 +2012,8 @@ void scst_pr_release(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
key = get_unaligned((__be64 *)&buffer[0]);
scope = cmd->cdb[2] >> 4;
type = cmd->cdb[2] & 0x0f;
@@ -2001,6 +2089,8 @@ void scst_pr_clear(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
key = get_unaligned((__be64 *)&buffer[0]);
if (buffer_size != 24) {
@@ -2211,6 +2301,8 @@ void scst_pr_preempt(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
{
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
scst_pr_do_preempt(cmd, buffer, buffer_size, false);
TRACE_EXIT();
@@ -2248,6 +2340,8 @@ void scst_pr_preempt_and_abort(struct scst_cmd *cmd, uint8_t *buffer,
{
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
cmd->pr_abort_counter = kzalloc(sizeof(*cmd->pr_abort_counter),
GFP_KERNEL);
if (cmd->pr_abort_counter == NULL) {
@@ -2424,6 +2518,8 @@ void scst_pr_read_keys(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if (buffer_size < 8) {
TRACE_PR("buffer_size too small: %d. expected >= 8 "
"(buffer %p)", buffer_size, buffer);
@@ -2475,6 +2571,8 @@ void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer,
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if (buffer_size < 8) {
TRACE_PR("buffer_size too small: %d. expected >= 8 "
"(buffer %p)", buffer_size, buffer);
@@ -2538,6 +2636,8 @@ void scst_pr_report_caps(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
TRACE_ENTRY();
scst_assert_pr_mutex_held(dev);
if (buffer_size < 8) {
TRACE_PR("buffer_size too small: %d. expected >= 8 "
"(buffer %p)", buffer_size, buffer);
@@ -2577,6 +2677,8 @@ void scst_pr_read_full_status(struct scst_cmd *cmd, uint8_t *buffer,
TRACE_ENTRY();
scst_assert_pr_mutex_held(cmd->dev);
if (buffer_size < 8)
goto skip;
+3
View File
@@ -89,6 +89,9 @@ static inline void scst_pr_write_unlock(struct scst_device *dev)
mutex_unlock(&dev->dev_pr_mutex);
}
int scst_pr_set_file_name(struct scst_device *dev, char **prev,
const char *fmt, ...) __printf(3, 4);
int scst_pr_init_dev(struct scst_device *dev);
void scst_pr_clear_dev(struct scst_device *dev);
+1
View File
@@ -335,6 +335,7 @@ void scst_free_tgt(struct scst_tgt *tgt);
int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev);
void scst_free_device(struct scst_device *dev);
bool scst_device_is_exported(struct scst_device *dev);
struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
const char *acg_name, bool tgt_acg);
+152 -1
View File
@@ -2756,6 +2756,135 @@ static ssize_t scst_dev_sysfs_type_show(struct kobject *kobj,
static struct kobj_attribute dev_type_attr =
__ATTR(type, S_IRUGO, scst_dev_sysfs_type_show, NULL);
static ssize_t scst_dev_sysfs_pr_file_name_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
struct scst_device *dev;
int res;
dev = container_of(kobj, struct scst_device, dev_kobj);
res = mutex_lock_interruptible(&dev->dev_pr_mutex);
if (res != 0)
goto out;
/* pr_file_name is NULL for SCSI pass-through devices */
WARN_ON_ONCE(!dev->pr_file_name);
res = scnprintf(buf, PAGE_SIZE, "%s\n%s", dev->pr_file_name ? : "",
dev->pr_file_name_is_set ? SCST_SYSFS_KEY_MARK "\n" :
"");
mutex_unlock(&dev->dev_pr_mutex);
out:
return res;
}
static int
scst_dev_sysfs_pr_file_name_process_store(struct scst_sysfs_work_item *work)
{
struct scst_device *dev = work->dev;
char *pr_file_name = work->buf, *prev = NULL;
int res;
res = mutex_lock_interruptible(&scst_mutex);
if (res != 0)
goto out;
res = -EBUSY;
if (scst_device_is_exported(dev)) {
PRINT_ERROR("%s: not changing pr_file_name because the device"
" has already been exported", dev->virt_name);
goto unlock_scst;
}
res = mutex_lock_interruptible(&dev->dev_pr_mutex);
if (res)
goto unlock_scst;
if (strcmp(dev->pr_file_name, pr_file_name) == 0)
goto unlock_dev_pr;
res = scst_pr_set_file_name(dev, &prev, "%s", pr_file_name);
if (res != 0)
goto unlock_dev_pr;
res = scst_pr_init_dev(dev);
if (res != 0) {
PRINT_ERROR("%s: loading PR from %s failed (%d) - restoring %s",
dev->virt_name, dev->pr_file_name, res,
prev ? : "");
scst_pr_set_file_name(dev, NULL, "%s", prev);
scst_pr_init_dev(dev);
goto unlock_dev_pr;
}
dev->pr_file_name_is_set = !work->default_val;
unlock_dev_pr:
mutex_unlock(&dev->dev_pr_mutex);
unlock_scst:
mutex_unlock(&scst_mutex);
out:
kobject_put(&dev->dev_kobj);
kfree(prev);
return res;
}
static ssize_t scst_dev_sysfs_pr_file_name_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
struct scst_sysfs_work_item *work;
struct scst_device *dev;
char *pr_file_name, *p;
int res = -ENOMEM;
bool def = false;
dev = container_of(kobj, struct scst_device, dev_kobj);
pr_file_name = kasprintf(GFP_KERNEL, "%.*s", (int)count, buf);
if (!pr_file_name) {
PRINT_ERROR("Unable to kasprintf() PR file name");
goto out;
}
p = pr_file_name;
strsep(&p, "\n"); /* strip trailing whitespace */
if (pr_file_name[0] == '\0') {
kfree(pr_file_name);
pr_file_name = kasprintf(GFP_KERNEL, "%s/%s", SCST_PR_DIR,
dev->virt_name);
if (!pr_file_name) {
PRINT_ERROR("Unable to kasprintf() PR file name");
goto out;
}
def = true;
}
res = scst_alloc_sysfs_work(scst_dev_sysfs_pr_file_name_process_store,
false, &work);
if (res != 0)
goto out;
kobject_get(&dev->dev_kobj);
work->dev = dev;
work->default_val = def;
swap(work->buf, pr_file_name);
res = scst_sysfs_queue_wait_work(work);
if (res == 0)
res = count;
out:
kfree(pr_file_name);
return res;
}
static struct kobj_attribute dev_pr_file_name_attr =
__ATTR(pr_file_name, S_IWUSR|S_IRUGO,
scst_dev_sysfs_pr_file_name_show,
scst_dev_sysfs_pr_file_name_store);
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
static ssize_t scst_dev_sysfs_dump_prs(struct kobject *kobj,
@@ -3205,6 +3334,15 @@ int scst_dev_sysfs_create(struct scst_device *dev)
dev->virt_name);
goto out_del;
}
} else {
res = sysfs_create_file(&dev->dev_kobj,
&dev_pr_file_name_attr.attr);
if (res != 0) {
PRINT_ERROR("Can't create attr %s for dev %s",
dev_pr_file_name_attr.attr.name,
dev->virt_name);
goto out_del;
}
}
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
@@ -5922,10 +6060,20 @@ static int scst_process_threads_store(int newtn)
TRACE_DBG("newtn %d", newtn);
res = mutex_lock_interruptible(&scst_mutex);
/*
* Some commands are taking scst_mutex on commands processing path,
* so we need to drain them, because otherwise we can fall into a
* deadlock with kthread_stop() in scst_del_threads() waiting for
* those commands to finish.
*/
res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER);
if (res != 0)
goto out;
res = mutex_lock_interruptible(&scst_mutex);
if (res != 0)
goto out_resume;
oldtn = scst_main_cmd_threads.nr_threads;
delta = newtn - oldtn;
@@ -5942,6 +6090,9 @@ static int scst_process_threads_store(int newtn)
out_up:
mutex_unlock(&scst_mutex);
out_resume:
scst_resume_activity();
out:
TRACE_EXIT_RES(res);
return res;
+21 -13
View File
@@ -294,8 +294,9 @@ out:
EXPORT_SYMBOL(scst_rx_cmd);
/*
* No locks, but might be on IRQ. Returns 0 on success, <0 if processing of
* this command should be stopped.
* No locks, but might be on IRQ. Returns:
* - < 0 if the caller must not perform any further processing of @cmd;
* - >= 0 if the caller must continue processing @cmd.
*/
static int scst_init_cmd(struct scst_cmd *cmd, enum scst_exec_context *context)
{
@@ -2744,6 +2745,11 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
TRACE_ENTRY();
if (unlikely(cmd->internal)) {
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("ABORTED set, aborting internal "
"cmd %p", cmd);
goto out_uncomplete;
}
/*
* The original command passed all checks and not finished yet
*/
@@ -3463,11 +3469,14 @@ static bool scst_check_auto_sense(struct scst_cmd *cmd)
if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) &&
(!scst_sense_valid(cmd->sense) || scst_no_sense(cmd->sense))) {
TRACE(TRACE_SCSI|TRACE_MINOR_AND_MGMT_DBG, "CHECK_CONDITION, "
"but no sense: cmd->status=%x, cmd->msg_status=%x, "
"cmd->host_status=%x, cmd->driver_status=%x (cmd %p)",
cmd->status, cmd->msg_status, cmd->host_status,
cmd->driver_status, cmd);
if (!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
TRACE(TRACE_SCSI|TRACE_MINOR_AND_MGMT_DBG,
"CHECK_CONDITION, but no sense: cmd->status=%x, "
"cmd->msg_status=%x, cmd->host_status=%x, "
"cmd->driver_status=%x (cmd %p)",
cmd->status, cmd->msg_status, cmd->host_status,
cmd->driver_status, cmd);
}
res = true;
} else if (unlikely(cmd->host_status)) {
if ((cmd->host_status == DID_REQUEUE) ||
@@ -3498,9 +3507,11 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
rc = scst_check_auto_sense(cmd);
if (unlikely(rc)) {
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))
goto next;
PRINT_INFO("Command finished with CHECK CONDITION, but "
"without sense data (opcode %s), issuing "
"REQUEST SENSE", scst_get_opcode_name(cmd));
"without sense data (opcode %s), issuing "
"REQUEST SENSE", scst_get_opcode_name(cmd));
rc = scst_prepare_request_sense(cmd);
if (rc == 0)
res = SCST_CMD_STATE_RES_CONT_NEXT;
@@ -3513,6 +3524,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
goto out;
}
next:
rc = scst_check_sense(cmd);
if (unlikely(rc)) {
/*
@@ -4546,10 +4558,6 @@ restart:
goto restart;
}
/* It isn't really needed, but let's keep it */
if (susp != test_bit(SCST_FLAG_SUSPENDED, &scst_flags))
goto restart;
TRACE_EXIT();
return;
}
+1 -1
View File
@@ -317,7 +317,7 @@ enum rdma_ch_state {
* @kref: Per-channel reference count.
* @rq_size: IB receive queue size.
* @max_sge: Maximum length of RDMA scatter list.
* @max_rsp_size: Maximum size of an SRP response messages in bytes.
* @max_rsp_size: Maximum size of an SRP response message in bytes.
* @sq_wr_avail: number of work requests available in the send queue.
* @sport: pointer to the information of the HCA port used by this
* channel.
+7 -3
View File
@@ -391,11 +391,15 @@ static int do_exec(struct vdisk_cmd *vcmd)
exec_read_capacity(vcmd);
break;
case SERVICE_ACTION_IN:
if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) {
if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)
exec_read_capacity16(vcmd);
break;
else {
TRACE_DBG("Invalid service action %d for SERVICE "
"ACTION IN", cmd->cdb[1] & 0x1f);
set_cmd_error(vcmd,
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
}
/* else go through */
break;
case REPORT_LUNS:
default:
TRACE_DBG("Invalid opcode %d", opcode);