diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 24b481c6d..c8322d104 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -1372,9 +1372,7 @@ static int write_data(struct iscsi_conn *conn) retry: oldfs = get_fs(); set_fs(KERNEL_DS); - res = vfs_writev(file, - (struct iovec __force __user *)iop, - count, &off, 0); + res = scst_writev(file, iop, count, &off); set_fs(oldfs); TRACE_WRITE("sid %#Lx, cid %u, res %d, iov_len %zd", (unsigned long long int)conn->session->sid, diff --git a/scst/include/backport.h b/scst/include/backport.h index b3d057e62..4902611f5 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -247,27 +247,6 @@ static inline struct inode *file_inode(const struct file *f) } #endif -#if (!defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) || \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) -static inline ssize_t vfs_readv_backport(struct file *file, - const struct iovec __user *vec, - unsigned long vlen, loff_t *pos, - int flags) -{ - return vfs_readv(file, vec, vlen, pos); -} -static inline ssize_t vfs_writev_backport(struct file *file, - const struct iovec __user *vec, - unsigned long vlen, loff_t *pos, - int flags) -{ - return vfs_writev(file, vec, vlen, pos); -} -#define vfs_readv vfs_readv_backport -#define vfs_writev vfs_writev_backport -#endif - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) static inline int vfs_fsync_backport(struct file *file, int datasync) { diff --git a/scst/include/scst.h b/scst/include/scst.h index c4f15dfa1..329c62425 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -5712,6 +5712,13 @@ struct scst_data_descriptor { uint64_t sdd_blocks; }; +ssize_t scst_read(struct file *file, void *buf, size_t count, loff_t *pos); +ssize_t scst_write(struct file *file, const void *buf, size_t count, + loff_t *pos); +ssize_t scst_readv(struct file *file, const struct iovec *vec, + unsigned long vlen, loff_t *pos); +ssize_t scst_writev(struct file *file, const struct iovec *vec, + unsigned long vlen, loff_t *pos); void scst_write_same(struct scst_cmd *cmd, struct scst_data_descriptor *where); int scst_scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index ec68dbb67..137d2bafe 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -2112,8 +2112,7 @@ static int vdisk_format_dif(struct scst_cmd *cmd, uint64_t start_lba, full_len, (long long)loff); /* WRITE */ - err = vfs_writev(fd, (struct iovec __force __user *)iv, - iv_count, &loff, 0); + err = scst_writev(fd, iv, iv_count, &loff); if (err < 0) { PRINT_ERROR("Formatting DIF write() returned %lld from " "%zd", err, full_len); @@ -5962,8 +5961,7 @@ static int vdev_read_dif_tags(struct vdisk_cmd_params *p) iv_count, full_len, (long long)loff); /* READ */ - err = vfs_readv(fd, (struct iovec __force __user *)iv, iv_count, - &loff, 0); + err = scst_readv(fd, iv, iv_count, &loff); if ((err < 0) || (err < full_len)) { unsigned long flags; @@ -6091,8 +6089,7 @@ restart: TRACE_DBG("Writing DIF: eiv_count %d, full_len %zd", eiv_count, full_len); /* WRITE */ - err = vfs_writev(fd, (struct iovec __force __user *)eiv, - eiv_count, &loff, 0); + err = scst_writev(fd, eiv, eiv_count, &loff); if (err < 0) { unsigned long flags; @@ -6233,8 +6230,7 @@ static enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p) TRACE_DBG("Reading iv_count %d, full_len %zd", iv_count, full_len); /* READ */ - err = vfs_readv(fd, (struct iovec __force __user *)iv, iv_count, - &loff, 0); + err = scst_readv(fd, iv, iv_count, &loff); if ((err < 0) || (err < full_len)) { PRINT_ERROR("readv() returned %lld from %zd", (unsigned long long int)err, @@ -6427,8 +6423,7 @@ restart: TRACE_DBG("Writing: eiv_count %d, full_len %zd", eiv_count, full_len); /* WRITE */ - err = vfs_writev(fd, (struct iovec __force __user *)eiv, - eiv_count, &loff, 0); + err = scst_writev(fd, eiv, eiv_count, &loff); if (err < 0) { PRINT_ERROR("write() returned %lld from %zd", (unsigned long long int)err, @@ -7325,7 +7320,7 @@ static ssize_t fileio_read_sync(struct file *fd, void *buf, size_t len, old_fs = get_fs(); set_fs(get_ds()); - ret = vfs_read(fd, (char __force __user *)buf, len, loff); + ret = scst_read(fd, buf, len, loff); set_fs(old_fs); return ret; diff --git a/scst/src/scst_dlm.c b/scst/src/scst_dlm.c index 130e61522..26e64535a 100644 --- a/scst/src/scst_dlm.c +++ b/scst/src/scst_dlm.c @@ -511,7 +511,7 @@ static int scst_read_file(const char *path, char *buf, int buf_len) goto out; } pos = 0; - ret = vfs_read(f, (char __force __user *)buf, buf_len, &pos); + ret = scst_read(f, buf, buf_len, &pos); if (ret >= 0) buf[min(ret, buf_len - 1)] = '\0'; filp_close(f, NULL); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 04e39b4a7..88e4ebf7c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -5861,6 +5861,101 @@ static void scst_complete_request_sense(struct scst_cmd *req_cmd) return; } +ssize_t scst_read(struct file *file, void *buf, size_t count, loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + struct iovec iov = { + .iov_base = (void __force __user *)buf, + .iov_len = count + }; + + return scst_readv(file, &iov, 1, pos); +#else + return vfs_read(file, (void __force __user *)buf, count, pos); +#endif +} +EXPORT_SYMBOL(scst_read); + +ssize_t scst_write(struct file *file, const void *buf, size_t count, + loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + struct iovec iov = { + .iov_base = (void __force __user *)buf, + .iov_len = count + }; + + return scst_writev(file, &iov, 1, pos); +#else + return vfs_write(file, (void __force __user *)buf, count, pos); +#endif +} +EXPORT_SYMBOL(scst_write); + +ssize_t scst_readv(struct file *file, const struct iovec *vec, + unsigned long vlen, loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov = iovstack; + struct iov_iter iter; + ssize_t ret; + + ret = import_iovec(READ, (const struct iovec __force __user *)vec, vlen, + ARRAY_SIZE(iovstack), &iov, &iter); + if (ret < 0) + return ret; + ret = vfs_iter_read(file, &iter, pos, 0); + kfree(iov); + return ret; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) || \ + (defined(CONFIG_SUSE_KERNEL) && \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + return vfs_readv(file, (const struct iovec __user*)vec, vlen, pos, 0); +#else + return vfs_readv(file, (const struct iovec __user*)vec, vlen, pos); +#endif +} +EXPORT_SYMBOL(scst_readv); + +/** + * scst_writev - write a buffer to a file + * @file: File to write to. + * @vec: Pointer to first element of struct iovec array. + * @vlen: Number of elements of the iovec array. + * @pos: Position in @file where to start writing. + * + * Note: although @vec->iov_base has type void __user*, it points at kernel + * data and not at data in user space. + */ +ssize_t scst_writev(struct file *file, const struct iovec *vec, + unsigned long vlen, loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov = iovstack; + struct iov_iter iter; + ssize_t ret; + + ret = import_iovec(WRITE, (const struct iovec __force __user*)vec, vlen, + ARRAY_SIZE(iovstack), &iov, &iter); + if (ret < 0) + return ret; + file_start_write(file); + ret = vfs_iter_write(file, &iter, pos, 0); + file_end_write(file); + kfree(iov); + return ret; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) || \ + (defined(CONFIG_SUSE_KERNEL) && \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + return vfs_writev(file, (const struct iovec __user*)vec, vlen, pos, 0); +#else + return vfs_writev(file, (const struct iovec __user*)vec, vlen, pos); +#endif +} +EXPORT_SYMBOL(scst_writev); + struct scst_ws_sg_tail { struct scatterlist *sg; int sg_cnt; @@ -14872,14 +14967,14 @@ int scst_copy_file(const char *src, const char *dest) } pos = 0; - res = vfs_read(file_src, (void __force __user *)buf, file_size, &pos); + res = scst_read(file_src, buf, file_size, &pos); if (res != file_size) { PRINT_ERROR("Unable to read file '%s' - error %d", src, res); goto out_skip; } pos = 0; - res = vfs_write(file_dest, (void __force __user *)buf, file_size, &pos); + res = scst_write(file_dest, buf, file_size, &pos); if (res != file_size) { PRINT_ERROR("Unable to write to '%s' - error %d", dest, res); goto out_skip; @@ -14973,7 +15068,7 @@ int scst_write_file_transactional(const char *name, const char *name1, pos = signature_len+1; - res = vfs_write(file, (void const __force __user *)buf, size, &pos); + res = scst_write(file, buf, size, &pos); if (res != size) goto write_error; @@ -14984,11 +15079,11 @@ int scst_write_file_transactional(const char *name, const char *name1, } pos = 0; - res = vfs_write(file, (void const __force __user *)signature, signature_len, &pos); + res = scst_write(file, signature, signature_len, &pos); if (res != signature_len) goto write_error; - res = vfs_write(file, (void __force __user *)&n, sizeof(n), &pos); + res = scst_write(file, &n, sizeof(n), &pos); if (res != sizeof(n)) goto write_error; @@ -15070,7 +15165,7 @@ static int __scst_read_file_transactional(const char *file_name, } pos = 0; - res = vfs_read(file, (void __force __user *)buf, file_size, &pos); + res = scst_read(file, buf, file_size, &pos); if (res != file_size) { PRINT_ERROR("Unable to read file '%s' - error %d", file_name, res); if (res > 0) diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 02f4d68ff..467f5ec0e 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -720,7 +720,7 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, } pos = 0; - rc = vfs_read(file, (void __force __user *)buf, file_size, &pos); + rc = scst_read(file, buf, file_size, &pos); if (rc != file_size) { PRINT_ERROR("Unable to read file '%s' - error %d", file_name, rc); @@ -925,7 +925,7 @@ void scst_pr_sync_device_file(struct scst_device *dev) */ sign = 0; pos = 0; - res = vfs_write(file, (void __force __user *)&sign, sizeof(sign), &pos); + res = scst_write(file, &sign, sizeof(sign), &pos); if (res != sizeof(sign)) goto write_error; @@ -933,7 +933,7 @@ void scst_pr_sync_device_file(struct scst_device *dev) * version */ version = SCST_PR_FILE_VERSION; - res = vfs_write(file, (void __force __user *)&version, sizeof(version), &pos); + res = scst_write(file, &version, sizeof(version), &pos); if (res != sizeof(version)) goto write_error; @@ -941,7 +941,7 @@ void scst_pr_sync_device_file(struct scst_device *dev) * APTPL */ aptpl = dev->pr_aptpl; - res = vfs_write(file, (void __force __user *)&aptpl, sizeof(aptpl), &pos); + res = scst_write(file, &aptpl, sizeof(aptpl), &pos); if (res != sizeof(aptpl)) goto write_error; @@ -949,15 +949,15 @@ void scst_pr_sync_device_file(struct scst_device *dev) * reservation */ pr_is_set = dev->pr_is_set; - res = vfs_write(file, (void __force __user *)&pr_is_set, sizeof(pr_is_set), &pos); + res = scst_write(file, &pr_is_set, sizeof(pr_is_set), &pos); if (res != sizeof(pr_is_set)) goto write_error; - res = vfs_write(file, (void __force __user *)&dev->pr_type, sizeof(dev->pr_type), &pos); + res = scst_write(file, &dev->pr_type, sizeof(dev->pr_type), &pos); if (res != sizeof(dev->pr_type)) goto write_error; - res = vfs_write(file, (void __force __user *)&dev->pr_scope, sizeof(dev->pr_scope), &pos); + res = scst_write(file, &dev->pr_scope, sizeof(dev->pr_scope), &pos); if (res != sizeof(dev->pr_scope)) goto write_error; @@ -971,23 +971,23 @@ void scst_pr_sync_device_file(struct scst_device *dev) is_holder = (dev->pr_holder == reg); - res = vfs_write(file, (void __force __user *)&is_holder, + res = scst_write(file, &is_holder, sizeof(is_holder), &pos); if (res != sizeof(is_holder)) goto write_error; size = scst_tid_size(reg->transport_id); - res = vfs_write(file, (void __force __user *)reg->transport_id, + res = scst_write(file, reg->transport_id, size, &pos); if (res != size) goto write_error; - res = vfs_write(file, (void __force __user *)®->key, + res = scst_write(file, ®->key, sizeof(reg->key), &pos); if (res != sizeof(reg->key)) goto write_error; - res = vfs_write(file, (void __force __user *)®->rel_tgt_id, + res = scst_write(file, ®->rel_tgt_id, sizeof(reg->rel_tgt_id), &pos); if (res != sizeof(reg->rel_tgt_id)) goto write_error; @@ -1001,7 +1001,7 @@ void scst_pr_sync_device_file(struct scst_device *dev) sign = SCST_PR_FILE_SIGN; pos = 0; - res = vfs_write(file, (void __force __user *)&sign, sizeof(sign), &pos); + res = scst_write(file, &sign, sizeof(sign), &pos); if (res != sizeof(sign)) goto write_error;