vdisk_blockio: Add VERIFY implementation

There is already an implementation of the VERIFY command for vdisk_fileio
devices. Add an implementation for vdisk_blockio devices.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5333 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2014-03-15 01:44:35 +00:00
parent f9ad2fcf8c
commit 1dca2eb45a

View File

@@ -259,8 +259,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p);
static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua);
static int vdisk_blockio_flush(struct block_device *bdev, gfp_t gfp_mask,
bool report_error, struct scst_cmd *cmd, bool async);
static enum compl_status_e blockio_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e blockio_exec_write_verify(struct vdisk_cmd_params *p);
static enum compl_status_e fileio_exec_write_verify(struct vdisk_cmd_params *p);
static enum compl_status_e nullio_exec_write_verify(struct vdisk_cmd_params *p);
@@ -1423,9 +1422,9 @@ static vdisk_op_fn blockio_ops[256] = {
[WRITE_VERIFY] = blockio_exec_write_verify,
[WRITE_VERIFY_12] = blockio_exec_write_verify,
[WRITE_VERIFY_16] = blockio_exec_write_verify,
[VERIFY] = blockio_exec_verify,
[VERIFY_12] = blockio_exec_verify,
[VERIFY_16] = blockio_exec_verify,
[VERIFY] = vdev_exec_verify,
[VERIFY_12] = vdev_exec_verify,
[VERIFY_16] = vdev_exec_verify,
SHARED_OPS
};
@@ -1441,9 +1440,9 @@ static vdisk_op_fn fileio_ops[256] = {
[WRITE_VERIFY] = fileio_exec_write_verify,
[WRITE_VERIFY_12] = fileio_exec_write_verify,
[WRITE_VERIFY_16] = fileio_exec_write_verify,
[VERIFY] = fileio_exec_verify,
[VERIFY_12] = fileio_exec_verify,
[VERIFY_16] = fileio_exec_verify,
[VERIFY] = vdev_exec_verify,
[VERIFY_12] = vdev_exec_verify,
[VERIFY_16] = vdev_exec_verify,
SHARED_OPS
};
@@ -4400,31 +4399,141 @@ out:
return res;
}
static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
static int blockio_end_sync_io(struct bio *bio, unsigned int bytes_done,
int error)
#else
static void blockio_end_sync_io(struct bio *bio, int error)
#endif
{
struct completion *c = bio->bi_private;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
if (bio->bi_size)
return 1;
#endif
if (!bio_flagged(bio, BIO_UPTODATE) && error == 0) {
PRINT_ERROR("Not up to date bio with error 0; returning -EIO");
error = -EIO;
}
bio->bi_private = (void *)(unsigned long)error;
complete(c);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
return 0;
#else
return;
#endif
}
static ssize_t blockio_rw_sync(struct scst_vdisk_dev *virt_dev, void *buf,
size_t len, loff_t *loff, unsigned rw)
{
DECLARE_COMPLETION_ONSTACK(c);
int block_shift = virt_dev->dev->block_shift;
struct block_device *bdev = virt_dev->bdev;
struct bio *bio;
void *p;
int max_nr_vecs, rc;
unsigned bytes, off;
ssize_t ret = -ENOMEM;
max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
bio = bio_kmalloc(GFP_KERNEL, max_nr_vecs);
#else
bio = bio_alloc(GFP_KERNEL, max_nr_vecs);
#endif
if (!bio)
goto out;
bio->bi_rw = rw;
bio->bi_bdev = bdev;
bio->bi_end_io = blockio_end_sync_io;
bio->bi_private = &c;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
bio->bi_sector = *loff << (block_shift - 9);
#else
bio->bi_iter.bi_sector = *loff << (block_shift - 9);
#endif
for (p = buf; p < buf + len; p += bytes) {
off = offset_in_page(p);
bytes = PAGE_SIZE - off;
rc = bio_add_page(bio, virt_to_page(p), bytes, off);
if (WARN_ON_ONCE(rc < bytes))
goto free;
}
submit_bio(rw, bio);
wait_for_completion(&c);
ret = (unsigned long)bio->bi_private ? : len;
free:
bio_put(bio);
out:
return ret;
}
static ssize_t fileio_read_sync(struct file *fd, void *buf, size_t len,
loff_t *loff)
{
mm_segment_t old_fs;
ssize_t ret;
old_fs = get_fs();
set_fs(get_ds());
if (fd->f_op->llseek)
ret = fd->f_op->llseek(fd, *loff, 0/*SEEK_SET*/);
else
ret = default_llseek(fd, *loff, 0/*SEEK_SET*/);
if (ret < 0)
goto out;
ret = vfs_read(fd, (char __force __user *)buf, len, loff);
out:
set_fs(old_fs);
return ret;
}
static ssize_t vdev_read_sync(struct scst_vdisk_dev *virt_dev, void *buf,
size_t len, loff_t *loff)
{
if (virt_dev->nullio)
return len;
else if (virt_dev->blockio)
return blockio_rw_sync(virt_dev, buf, len, loff, 0/*read*/);
else
return fileio_read_sync(virt_dev->fd, buf, len, loff);
}
static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p)
{
struct scst_cmd *cmd = p->cmd;
loff_t loff = p->loff;
mm_segment_t old_fs;
loff_t err;
ssize_t length, len_mem = 0;
uint8_t *address_sav, *address = NULL;
int compare;
struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv;
struct file *fd = virt_dev->fd;
uint8_t *mem_verify = NULL;
int64_t data_len = scst_cmd_get_data_len(cmd);
TRACE_ENTRY();
sBUG_ON(virt_dev->blockio);
if (vdisk_fsync(loff, data_len, cmd->dev,
cmd->cmd_gfp_mask, cmd, false) != 0)
goto out;
/*
* Until the cache is cleared prior the verifying, there is not
* much point in this code. ToDo.
* For file I/O, unless the cache is cleared prior the verifying,
* there is not much point in this code. ToDo.
*
* Nevertherless, this code is valuable if the data have not been read
* from the file/disk yet.
@@ -4434,31 +4543,12 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
TRACE_DBG("VERIFY with BYTCHK=%d at offset %lld and len %lld\n",
compare, loff, (long long)data_len);
/* SEEK */
old_fs = get_fs();
set_fs(get_ds());
if (!virt_dev->nullio) {
if (fd->f_op->llseek)
err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/);
else
err = default_llseek(fd, loff, 0/*SEEK_SET*/);
if (err != loff) {
PRINT_ERROR("lseek trouble %lld != %lld",
(long long unsigned int)err,
(long long unsigned int)loff);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_read_error));
goto out_set_fs;
}
}
mem_verify = vmalloc(LEN_MEM);
if (mem_verify == NULL) {
PRINT_ERROR("Unable to allocate memory %d for verify",
LEN_MEM);
scst_set_busy(cmd);
goto out_set_fs;
goto out;
}
if (compare) {
@@ -4471,11 +4561,7 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
len_mem = (length > LEN_MEM) ? LEN_MEM : length;
TRACE_DBG("Verify: length %zd - len_mem %zd", length, len_mem);
if (!virt_dev->nullio)
err = vfs_read(fd, (char __force __user *)mem_verify,
len_mem, &loff);
else
err = len_mem;
err = vdev_read_sync(virt_dev, mem_verify, len_mem, &loff);
if ((err < 0) || (err < len_mem)) {
PRINT_ERROR("verify() returned %lld from %zd",
(long long unsigned int)err, len_mem);
@@ -4487,14 +4573,14 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
}
if (compare)
scst_put_buf(cmd, address_sav);
goto out_set_fs;
goto out_free;
}
if (compare && memcmp(address, mem_verify, len_mem) != 0) {
TRACE_DBG("Verify: error memcmp length %zd", length);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_miscompare_error));
scst_put_buf(cmd, address_sav);
goto out_set_fs;
goto out_free;
}
length -= len_mem;
if (compare)
@@ -4512,8 +4598,7 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
SCST_LOAD_SENSE(scst_sense_hardw_error));
}
out_set_fs:
set_fs(old_fs);
out_free:
if (mem_verify)
vfree(mem_verify);
@@ -4529,18 +4614,12 @@ static enum compl_status_e blockio_exec_write_verify(struct vdisk_cmd_params *p)
return blockio_exec_write(p);
}
static enum compl_status_e blockio_exec_verify(struct vdisk_cmd_params *p)
{
/* Not yet implemented */
return CMD_SUCCEEDED;
}
static enum compl_status_e fileio_exec_write_verify(struct vdisk_cmd_params *p)
{
fileio_exec_write(p);
/* O_DSYNC flag is used for WT devices */
if (scsi_status_is_good(p->cmd->status))
fileio_exec_verify(p);
vdev_exec_verify(p);
return CMD_SUCCEEDED;
}