Adding blockio mode support to scst_vdisk

Signed-of-by: Vu Pham <huongvp@yahoo.com>

Merged by me.

Don't use it, currently it corrupts transferred data


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@95 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-02-21 18:15:19 +00:00
parent 683431eb89
commit d175ce127d
3 changed files with 226 additions and 25 deletions

View File

@@ -1,6 +1,9 @@
Summary of changes between versions 0.9.5 and 0.9.6
---------------------------------------------------
- FILEIO was renamed to VDISK. BLOCK IO added to it, thanks to Ross S. W.
Walker and Vu Pham.
- Internal locking and execution context were reimplemnted. Particularly,
implemented full support for SCSI task attributes (SIMPLE, ORDERED,
etc.).

View File

@@ -486,6 +486,14 @@ Thanks to:
* Calvin Morrow <calvin.morrow@comcast.net> for testing and usful
suggestions.
* Erik Habbinga <erikhabbinga@inphase-tech.com> for fixes.
* Hu Gang <hugang@soulinfo.com> for the original version of the
LSI target driver.
* Erik Habbinga <erikhabbinga@inphase-tech.com> for fixes and support
of the LSI target driver.
* Ross S. W. Walker <rswwalker@hotmail.com> for the original block IO
code and Vu Pham <huongvp@yahoo.com> who updated it for the VDISK dev
handler.
Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net

View File

@@ -3,9 +3,11 @@
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
* (C) 2007 Ming Zhang <blackmagic02881 at gmail dot com>
* (C) 2007 Ross Walker <rswwalker at hotmail dot com>
*
* SCSI disk (type 0) and CDROM (type 5) dev handler using files
* on file systems (VDISK)
* on file systems or block devices (VDISK)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -57,9 +59,10 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
#define VDISK_SLAB_FLAGS 0L
#endif
/* 8 byte ASCII Vendor of the FILE IO target */
/* 8 byte ASCII Vendor */
#define SCST_FIO_VENDOR "SCST_FIO"
/* 4 byte ASCII Product Revision Level of the FILE IO target - left aligned */
#define SCST_BIO_VENDOR "SCST_BIO"
/* 4 byte ASCII Product Revision Level - left aligned */
#define SCST_FIO_REV " 096"
#define READ_CAP_LEN 8
@@ -112,6 +115,7 @@ struct scst_vdisk_dev {
unsigned int media_changed:1;
unsigned int prevent_allow_medium_removal:1;
unsigned int nullio:1;
unsigned int blockio:1;
unsigned int cdrom_empty:1;
int virt_id;
char name[16+1]; /* Name of virtual device,
@@ -129,6 +133,7 @@ struct scst_vdisk_tgt_dev {
struct scst_vdisk_thr {
struct scst_thr_data_hdr hdr;
struct file *fd;
struct block_device *bdev;
struct iovec *iv;
int iv_count;
struct scst_vdisk_dev *virt_dev;
@@ -148,6 +153,8 @@ static void vdisk_exec_read(struct scst_cmd *cmd,
struct scst_vdisk_thr *thr, loff_t loff);
static void vdisk_exec_write(struct scst_cmd *cmd,
struct scst_vdisk_thr *thr, loff_t loff);
static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
u64 lba_start, int write);
static void vdisk_exec_verify(struct scst_cmd *cmd,
struct scst_vdisk_thr *thr, loff_t loff);
static void vdisk_exec_read_capacity(struct scst_cmd *cmd);
@@ -209,7 +216,7 @@ static struct scst_dev_type cdrom_devtype_vdisk = VCDROM_TYPE;
static char *vdisk_proc_help_string =
"echo \"open|close NAME [FILE_NAME [BLOCK_SIZE] [WRITE_THROUGH "
"READ_ONLY O_DIRECT NULLIO NV_CACHE]]\" >/proc/scsi_tgt/"
"READ_ONLY O_DIRECT NULLIO NV_CACHE BLOCKIO]]\" >/proc/scsi_tgt/"
VDISK_NAME "/" VDISK_NAME "\n";
static char *vcdrom_proc_help_string =
@@ -260,7 +267,6 @@ static int vdisk_attach(struct scst_device *dev)
{
int res = 0;
loff_t err;
mm_segment_t old_fs;
struct file *fd;
struct scst_vdisk_dev *virt_dev = NULL, *vv;
struct list_head *vd;
@@ -305,6 +311,8 @@ static int vdisk_attach(struct scst_device *dev)
if (virt_dev->nullio)
err = 3LL*1024*1024*1024*1024/2;
else {
struct inode *inode;
fd = vdisk_open(virt_dev);
if (IS_ERR(fd)) {
res = PTR_ERR(fd);
@@ -328,22 +336,28 @@ static int vdisk_attach(struct scst_device *dev)
goto out;
}
/* seek to end */
old_fs = get_fs();
set_fs(get_ds());
if (fd->f_op->llseek) {
err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/);
} else {
err = default_llseek(fd, 0, 2/*SEEK_END*/);
}
set_fs(old_fs);
filp_close(fd, NULL);
if (err < 0) {
res = err;
PRINT_ERROR_PR("llseek %s returned an error %d",
virt_dev->file_name, res);
inode = fd->f_dentry->d_inode;
if (virt_dev->blockio && !S_ISBLK(inode->i_mode)) {
PRINT_ERROR_PR("File %s is NOT a block device",
virt_dev->file_name);
res = -EINVAL;
filp_close(fd, NULL);
goto out;
}
if (S_ISREG(inode->i_mode))
;
else if (S_ISBLK(inode->i_mode))
inode = inode->i_bdev->bd_inode;
else {
res = -EINVAL;
filp_close(fd, NULL);
goto out;
}
err = inode->i_size;
filp_close(fd, NULL);
}
virt_dev->file_size = err;
TRACE_DBG("size of file: %Ld", (uint64_t)err);
@@ -456,6 +470,10 @@ static struct scst_vdisk_thr *vdisk_init_thr_data(
virt_dev->file_name, PTR_ERR(res->fd));
goto out_free;
}
if (virt_dev->blockio)
res->bdev = res->fd->f_dentry->d_inode->i_bdev;
else
res->bdev = NULL;
} else
res->fd = NULL;
@@ -647,7 +665,10 @@ static int vdisk_do_job(struct scst_cmd *cmd)
case READ_10:
case READ_12:
case READ_16:
vdisk_exec_read(cmd, thr, loff);
if (virt_dev->blockio)
blockio_exec_rw(cmd, thr, lba_start, 0);
else
vdisk_exec_read(cmd, thr, loff);
break;
case WRITE_6:
case WRITE_10:
@@ -671,7 +692,10 @@ static int vdisk_do_job(struct scst_cmd *cmd)
if (vdisk_fsync(thr, 0, 0, cmd) != 0)
goto done;
}
vdisk_exec_write(cmd, thr, loff);
if (virt_dev->blockio)
blockio_exec_rw(cmd, thr, lba_start, 1);
else
vdisk_exec_write(cmd, thr, loff);
/* O_SYNC flag is used for wt_flag devices */
if (do_fsync || fua)
vdisk_fsync(thr, loff, data_len, cmd);
@@ -702,6 +726,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
if (vdisk_fsync(thr, 0, 0, cmd) != 0)
goto done;
}
/* ToDo: BLOCKIO VERIFY */
vdisk_exec_write(cmd, thr, loff);
/* O_SYNC flag is used for wt_flag devices */
if (cmd->status == 0)
@@ -1083,7 +1108,10 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
buf[num + 0] = 0x2; /* ASCII */
buf[num + 1] = 0x1;
buf[num + 2] = 0x0;
memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8);
if (virt_dev->blockio)
memcpy(&buf[num + 4], SCST_BIO_VENDOR, 8);
else
memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8);
memset(&buf[num + 12], ' ', 16);
i = strlen(virt_dev->name);
i = i < 16 ? i : 16;
@@ -1130,7 +1158,10 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
buf[6] = 0; buf[7] = 2; /* BQue = 0, CMDQUE = 1 commands queuing supported */
/* 8 byte ASCII Vendor Identification of the target - left aligned */
memcpy(&buf[8], SCST_FIO_VENDOR, 8);
if (virt_dev->blockio)
memcpy(&buf[8], SCST_BIO_VENDOR, 8);
else
memcpy(&buf[8], SCST_FIO_VENDOR, 8);
/* 16 byte ASCII Product Identification of the target - left aligned */
memset(&buf[16], ' ', 16);
@@ -1727,7 +1758,8 @@ static int vdisk_fsync(struct scst_vdisk_thr *thr,
TRACE_ENTRY();
if (thr->virt_dev->nv_cache)
/* ToDo: BLOCKIO fsync() */
if (thr->virt_dev->nv_cache || thr->virt_dev->blockio)
goto out;
res = sync_page_range(inode, mapping, loff, len);
@@ -2022,6 +2054,156 @@ out:
return;
}
struct blockio_work {
atomic_t bios_inflight;
struct scst_cmd *cmd;
struct completion complete;
};
static int blockio_endio(struct bio *bio, unsigned int bytes_done, int error)
{
struct blockio_work *blockio_work = bio->bi_private;
if (bio->bi_size)
return 1;
error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? error : -EIO;
if (unlikely(error != 0)) {
PRINT_ERROR_PR("cmd %p returned error %d", blockio_work->cmd,
error);
if (bio->bi_rw & WRITE)
scst_set_cmd_error(blockio_work->cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
else
scst_set_cmd_error(blockio_work->cmd,
SCST_LOAD_SENSE(scst_sense_read_error));
}
/* Decrement the bios in processing, and if zero signal completion */
if (atomic_dec_and_test(&blockio_work->bios_inflight))
complete(&blockio_work->complete);
bio_put(bio);
return 0;
}
static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
u64 lba_start, int write)
{
struct scst_vdisk_dev *virt_dev = thr->virt_dev;
struct block_device *bdev = thr->bdev;
struct request_queue *q = bdev_get_queue(bdev);
int j, max_nr_vecs = 0;
struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
int need_new_bio;
struct scatterlist *sgl = cmd->sg;
struct blockio_work *blockio_work;
TRACE_ENTRY();
if (virt_dev->nullio)
goto out;
/* Allocate and initialize blockio_work struct */
blockio_work = kmalloc(sizeof (*blockio_work), GFP_KERNEL);
if (blockio_work == NULL)
goto out_no_mem;
atomic_set(&blockio_work->bios_inflight, 0);
blockio_work->cmd = cmd;
init_completion(&blockio_work->complete);
if (q)
max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES);
else
max_nr_vecs = 1;
need_new_bio = 1;
for (j = 0; j < cmd->sg_cnt; ++j) {
unsigned int len, bytes, off, thislen;
struct page *page;
page = sgl[j].page;
off = sgl[j].offset;
len = sgl[j].length;
thislen = 0;
while (len > 0) {
if (need_new_bio) {
bio = bio_alloc(GFP_KERNEL, max_nr_vecs);
if (!bio) {
PRINT_ERROR_PR("Failed to create bio"
"for data segment= %d"
" cmd %p", j, cmd);
goto out_no_bio;
}
atomic_inc(&blockio_work->bios_inflight);
need_new_bio = 0;
bio->bi_end_io = blockio_endio;
bio->bi_sector = lba_start;
bio->bi_bdev = bdev;
bio->bi_private = blockio_work;
bio->bi_rw |= write;
if (write && virt_dev->wt_flag)
bio->bi_rw |= 1 << BIO_RW_SYNC;
if (!hbio)
hbio = tbio = bio;
else
tbio = tbio->bi_next = bio;
}
bytes = min_t(unsigned int, len, PAGE_SIZE - off);
if (bio_add_page(bio, page, bytes, off) < bytes) {
need_new_bio = 1;
lba_start += thislen >> virt_dev->block_shift;
continue;
}
page++;
thislen += bytes;
len -= bytes;
off = 0;
}
lba_start += sgl[j].length >> virt_dev->block_shift;
}
while (hbio) {
bio = hbio;
hbio = hbio->bi_next;
bio->bi_next = NULL;
generic_make_request(bio);
}
if (q && q->unplug_fn)
q->unplug_fn(q);
wait_for_completion(&blockio_work->complete);
kfree(blockio_work);
out:
TRACE_EXIT();
return;
out_no_bio:
while (hbio) {
bio = hbio;
hbio = hbio->bi_next;
bio_put(bio);
}
kfree(blockio_work);
out_no_mem:
scst_set_busy(cmd);
goto out;
}
static void vdisk_exec_verify(struct scst_cmd *cmd,
struct scst_vdisk_thr *thr, loff_t loff)
{
@@ -2195,6 +2377,10 @@ static int vdisk_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type)
seq_printf(seq, "NIO ");
c += 4;
}
if (virt_dev->blockio) {
seq_printf(seq, "BIO ");
c += 4;
}
while (c < 16) {
seq_printf(seq, " ");
c++;
@@ -2363,6 +2549,10 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
p += 6;
virt_dev->nullio = 1;
TRACE_DBG("%s", "NULLIO");
} else if (!strncmp("BLOCKIO", p, 7)) {
p += 7;
virt_dev->blockio = 1;
TRACE_DBG("%s", "BLOCKIO");
} else {
PRINT_ERROR_PR("Unknown flag \"%s\"", p);
res = -EINVAL;