From 7610407e49bb958d33b14f60d5147037b327894b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 23 Feb 2019 16:46:45 +0000 Subject: [PATCH] scst_vdisk: Reduce the number of forward declarations git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7981 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 610 ++++++++++++++--------------- 1 file changed, 304 insertions(+), 306 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index c31c3cd5c..5a2c38011 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -308,12 +308,10 @@ MODULE_PARM_DESC(num_threads, "vdisk threads count"); */ static spinlock_t vdev_err_lock; -static enum compl_status_e vdev_verify(struct scst_cmd *cmd, loff_t loff); +#ifndef CONFIG_SCST_PROC /** SYSFS **/ -#ifndef CONFIG_SCST_PROC - static ssize_t vdisk_sysfs_gen_tp_soft_threshold_reached_UA(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdev_dif_filename_show(struct kobject *kobj, @@ -2855,6 +2853,309 @@ static enum scst_exec_res fileio_exec(struct scst_cmd *cmd) return vdev_do_job(cmd, ops); } +struct bio_priv_sync { + struct completion c; + int error; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) + struct bio_set *bs; + struct completion c1; +#endif +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) +static void blockio_bio_destructor_sync(struct bio *bio) +{ + struct bio_priv_sync *s = bio->bi_private; + + bio_free(bio, s->bs); + complete(&s->c1); +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +static int blockio_end_sync_io(struct bio *bio, unsigned int bytes_done, + int error) +{ +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) +static void blockio_end_sync_io(struct bio *bio, int error) +{ +#else +static void blockio_end_sync_io(struct bio *bio) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) + int error = bio->bi_error; +#else + int error = blk_status_to_errno(bio->bi_status); +#endif +#endif + struct bio_priv_sync *s = bio->bi_private; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) + if (bio->bi_size) + return 1; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) + if (!bio_flagged(bio, BIO_UPTODATE) && error == 0) { + PRINT_ERROR("Not up to date bio with error 0; returning -EIO"); + error = -EIO; + } +#endif + + s->error = error; + complete(&s->c); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) + return 0; +#else + return; +#endif +} + +/* + * blockio_read_sync() - read up to @len bytes from a block I/O device + * + * Returns: + * - A negative value if an error occurred. + * - Zero if len == 0. + * - A positive value <= len if I/O succeeded. + * + * Note: + * Increments *@loff with the number of bytes transferred upon success. + */ +static ssize_t blockio_read_sync(struct scst_vdisk_dev *virt_dev, void *buf, + size_t len, loff_t *loff) +{ + struct bio_priv_sync s = { + COMPLETION_INITIALIZER_ONSTACK(s.c), 0, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) + virt_dev->vdisk_bioset, + COMPLETION_INITIALIZER_ONSTACK(s.c1) +#endif + }; + struct block_device *bdev = virt_dev->bdev; + const bool is_vmalloc = is_vmalloc_addr(buf); + struct bio *bio; + void *p; + struct page *q; + int max_nr_vecs, rc; + unsigned int bytes, off; + ssize_t ret = -ENOMEM; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) + bool submitted = false; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) + max_nr_vecs = BIO_MAX_PAGES; +#else + max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) + bio = bio_alloc_bioset(GFP_KERNEL, max_nr_vecs, virt_dev->vdisk_bioset); +#else + bio = bio_alloc(GFP_KERNEL, max_nr_vecs); +#endif + + if (!bio) + goto out; + +#if (!defined(CONFIG_SUSE_KERNEL) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) || \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) + bio->bi_rw = READ_SYNC; +#else + bio_set_op_attrs(bio, REQ_OP_READ, REQ_SYNC); +#endif + bio_set_dev(bio, bdev); + bio->bi_end_io = blockio_end_sync_io; + bio->bi_private = &s; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) + bio->bi_destructor = blockio_bio_destructor_sync; +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) + bio->bi_sector = *loff >> 9; +#else + bio->bi_iter.bi_sector = *loff >> 9; +#endif + for (p = buf; p < buf + len; p += bytes) { + off = offset_in_page(p); + bytes = min_t(size_t, PAGE_SIZE - off, buf + len - p); + q = is_vmalloc ? vmalloc_to_page(p) : virt_to_page(p); + rc = bio_add_page(bio, q, bytes, off); + if (rc < bytes) { + if (rc <= 0 && p == buf) { + goto free; + } else { + if (rc > 0) + p += rc; + break; + } + } + } +#if (!defined(CONFIG_SUSE_KERNEL) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) || \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) + submit_bio(bio->bi_rw, bio); +#else + submit_bio(bio); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) + submitted = true; +#endif + wait_for_completion(&s.c); + ret = (unsigned long)s.error; + if (likely(ret == 0)) { + ret = p - buf; + *loff += ret; + } + +free: + bio_put(bio); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) + if (submitted) + wait_for_completion(&s.c1); +#endif + +out: + return ret; +} + +/* Note: Updates *@loff if reading succeeded. */ +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()); + ret = scst_read(fd, buf, len, loff); + set_fs(old_fs); + + return ret; +} + +/* Note: Updates *@loff if reading succeeded except for NULLIO devices. */ +static ssize_t vdev_read_sync(struct scst_vdisk_dev *virt_dev, void *buf, + size_t len, loff_t *loff) +{ + ssize_t read, res; + + if (virt_dev->nullio) { + return len; + } else if (virt_dev->blockio) { + for (read = 0; read < len; read += res) { + res = blockio_read_sync(virt_dev, buf + read, + len - read, loff); + if (res < 0) + return res; + } + return read; + } else { + return fileio_read_sync(virt_dev->fd, buf, len, loff); + } +} + +static enum compl_status_e vdev_verify(struct scst_cmd *cmd, loff_t loff) +{ + 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; + uint8_t *mem_verify = NULL; + int64_t data_len = scst_cmd_get_data_len(cmd); + enum scst_dif_actions checks = scst_get_dif_checks(cmd->cmd_dif_actions); + + TRACE_ENTRY(); + + if (vdisk_fsync(loff, data_len, cmd->dev, + cmd->cmd_gfp_mask, cmd, false) != 0) + goto out; + + /* + * 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. + */ + + compare = scst_cmd_get_data_direction(cmd) == SCST_DATA_WRITE; + TRACE_DBG("VERIFY with compare %d at offset %lld and len %lld\n", + compare, loff, (long long)data_len); + + 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; + } + + if (compare) { + length = scst_get_buf_first(cmd, &address); + address_sav = address; + } else + length = data_len; + + while (length > 0) { + len_mem = (length > LEN_MEM) ? LEN_MEM : length; + TRACE_DBG("Verify: length %zd - len_mem %zd", length, 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", + (unsigned long long)err, len_mem); + if (err == -EAGAIN) + scst_set_busy(cmd); + else { + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_read_error)); + } + if (compare) + scst_put_buf(cmd, address_sav); + 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_free; + } + + if (checks != 0) { + /* ToDo: check DIF tags as well */ + } + + length -= len_mem; + if (compare) + address += len_mem; + if (compare && length <= 0) { + scst_put_buf(cmd, address_sav); + length = scst_get_buf_next(cmd, &address); + address_sav = address; + } + } + + if (length < 0) { + PRINT_ERROR("scst_get_buf_() failed: %zd", length); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_internal_failure)); + } + +out_free: + if (mem_verify) + vfree(mem_verify); + +out: + TRACE_EXIT(); + return CMD_SUCCEEDED; +} + struct scst_verify_work { struct work_struct work; struct scst_cmd *cmd; @@ -6241,309 +6542,6 @@ out: return res; } -struct bio_priv_sync { - struct completion c; - int error; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) - struct bio_set *bs; - struct completion c1; -#endif -}; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) -static void blockio_bio_destructor_sync(struct bio *bio) -{ - struct bio_priv_sync *s = bio->bi_private; - - bio_free(bio, s->bs); - complete(&s->c1); -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -static int blockio_end_sync_io(struct bio *bio, unsigned int bytes_done, - int error) -{ -#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) -static void blockio_end_sync_io(struct bio *bio, int error) -{ -#else -static void blockio_end_sync_io(struct bio *bio) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) - int error = bio->bi_error; -#else - int error = blk_status_to_errno(bio->bi_status); -#endif -#endif - struct bio_priv_sync *s = bio->bi_private; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - if (bio->bi_size) - return 1; -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) - if (!bio_flagged(bio, BIO_UPTODATE) && error == 0) { - PRINT_ERROR("Not up to date bio with error 0; returning -EIO"); - error = -EIO; - } -#endif - - s->error = error; - complete(&s->c); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - return 0; -#else - return; -#endif -} - -/* - * blockio_read_sync() - read up to @len bytes from a block I/O device - * - * Returns: - * - A negative value if an error occurred. - * - Zero if len == 0. - * - A positive value <= len if I/O succeeded. - * - * Note: - * Increments *@loff with the number of bytes transferred upon success. - */ -static ssize_t blockio_read_sync(struct scst_vdisk_dev *virt_dev, void *buf, - size_t len, loff_t *loff) -{ - struct bio_priv_sync s = { - COMPLETION_INITIALIZER_ONSTACK(s.c), 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) - virt_dev->vdisk_bioset, - COMPLETION_INITIALIZER_ONSTACK(s.c1) -#endif - }; - struct block_device *bdev = virt_dev->bdev; - const bool is_vmalloc = is_vmalloc_addr(buf); - struct bio *bio; - void *p; - struct page *q; - int max_nr_vecs, rc; - unsigned int bytes, off; - ssize_t ret = -ENOMEM; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) - bool submitted = false; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) - max_nr_vecs = BIO_MAX_PAGES; -#else - max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES); -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) - bio = bio_alloc_bioset(GFP_KERNEL, max_nr_vecs, virt_dev->vdisk_bioset); -#else - bio = bio_alloc(GFP_KERNEL, max_nr_vecs); -#endif - - if (!bio) - goto out; - -#if (!defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) || \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) - bio->bi_rw = READ_SYNC; -#else - bio_set_op_attrs(bio, REQ_OP_READ, REQ_SYNC); -#endif - bio_set_dev(bio, bdev); - bio->bi_end_io = blockio_end_sync_io; - bio->bi_private = &s; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) - bio->bi_destructor = blockio_bio_destructor_sync; -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) - bio->bi_sector = *loff >> 9; -#else - bio->bi_iter.bi_sector = *loff >> 9; -#endif - for (p = buf; p < buf + len; p += bytes) { - off = offset_in_page(p); - bytes = min_t(size_t, PAGE_SIZE - off, buf + len - p); - q = is_vmalloc ? vmalloc_to_page(p) : virt_to_page(p); - rc = bio_add_page(bio, q, bytes, off); - if (rc < bytes) { - if (rc <= 0 && p == buf) { - goto free; - } else { - if (rc > 0) - p += rc; - break; - } - } - } -#if (!defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) || \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) - submit_bio(bio->bi_rw, bio); -#else - submit_bio(bio); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) - submitted = true; -#endif - wait_for_completion(&s.c); - ret = (unsigned long)s.error; - if (likely(ret == 0)) { - ret = p - buf; - *loff += ret; - } - -free: - bio_put(bio); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0)) - if (submitted) - wait_for_completion(&s.c1); -#endif - -out: - return ret; -} - -/* Note: Updates *@loff if reading succeeded. */ -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()); - ret = scst_read(fd, buf, len, loff); - set_fs(old_fs); - - return ret; -} - -/* Note: Updates *@loff if reading succeeded except for NULLIO devices. */ -static ssize_t vdev_read_sync(struct scst_vdisk_dev *virt_dev, void *buf, - size_t len, loff_t *loff) -{ - ssize_t read, res; - - if (virt_dev->nullio) { - return len; - } else if (virt_dev->blockio) { - for (read = 0; read < len; read += res) { - res = blockio_read_sync(virt_dev, buf + read, - len - read, loff); - if (res < 0) - return res; - } - return read; - } else { - return fileio_read_sync(virt_dev->fd, buf, len, loff); - } -} - -static enum compl_status_e vdev_verify(struct scst_cmd *cmd, loff_t loff) -{ - 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; - uint8_t *mem_verify = NULL; - int64_t data_len = scst_cmd_get_data_len(cmd); - enum scst_dif_actions checks = scst_get_dif_checks(cmd->cmd_dif_actions); - - TRACE_ENTRY(); - - if (vdisk_fsync(loff, data_len, cmd->dev, - cmd->cmd_gfp_mask, cmd, false) != 0) - goto out; - - /* - * 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. - */ - - compare = scst_cmd_get_data_direction(cmd) == SCST_DATA_WRITE; - TRACE_DBG("VERIFY with compare %d at offset %lld and len %lld\n", - compare, loff, (long long)data_len); - - 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; - } - - if (compare) { - length = scst_get_buf_first(cmd, &address); - address_sav = address; - } else - length = data_len; - - while (length > 0) { - len_mem = (length > LEN_MEM) ? LEN_MEM : length; - TRACE_DBG("Verify: length %zd - len_mem %zd", length, 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", - (unsigned long long)err, len_mem); - if (err == -EAGAIN) - scst_set_busy(cmd); - else { - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_read_error)); - } - if (compare) - scst_put_buf(cmd, address_sav); - 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_free; - } - - if (checks != 0) { - /* ToDo: check DIF tags as well */ - } - - length -= len_mem; - if (compare) - address += len_mem; - if (compare && length <= 0) { - scst_put_buf(cmd, address_sav); - length = scst_get_buf_next(cmd, &address); - address_sav = address; - } - } - - if (length < 0) { - PRINT_ERROR("scst_get_buf_() failed: %zd", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_internal_failure)); - } - -out_free: - if (mem_verify) - vfree(mem_verify); - -out: - TRACE_EXIT(); - return CMD_SUCCEEDED; -} - static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p) { return vdev_verify(p->cmd, p->loff);