From 2f58d0e48dd7b47d993bdb6de327327b579a7ad1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 15:54:35 +0000 Subject: [PATCH 1/7] scst: Remove superfluous get_fs() and set_fs() calls Calling set_fs(KERNEL_DS) before calling path_lookup() or kern_path() is not necessary since the arguments of these functions point at kernel data. Hence remove the get_fs() / set_fs() calls from around these function calls. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9187 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 7 ------- scst/src/scst_lib.c | 5 ----- 2 files changed, 12 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 22c9bda8d..33672d14d 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -10081,12 +10081,9 @@ static int __init vdev_check_mode_pages_path(void) #else struct path path; #endif - mm_segment_t old_fs = get_fs(); TRACE_ENTRY(); - set_fs(KERNEL_DS); - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) res = path_lookup(VDEV_MODE_PAGES_DIR, 0, &nd); if (res == 0) @@ -10101,12 +10098,8 @@ static int __init vdev_check_mode_pages_path(void) "disabled. You should create this directory manually " "or reinstall SCST", VDEV_MODE_PAGES_DIR, res); vdev_saved_mode_pages_enabled = false; - goto out_setfs; } -out_setfs: - set_fs(old_fs); - res = 0; /* always succeed */ TRACE_EXIT_RES(res); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 2f969b669..7471e2edb 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -15235,12 +15235,9 @@ int scst_remove_file(const char *name) #else struct path path; #endif - mm_segment_t old_fs = get_fs(); TRACE_ENTRY(); - set_fs(KERNEL_DS); - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) res = path_lookup(name, 0, &nd); if (!res) @@ -15255,8 +15252,6 @@ int scst_remove_file(const char *name) TRACE_DBG("Unable to lookup file '%s' - error %d", name, res); #endif - set_fs(old_fs); - TRACE_EXIT_RES(res); return res; } From 9ac77f979ddae45d1142f96c0d8ee4e57bf68ef9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 15:56:18 +0000 Subject: [PATCH 2/7] scst: Simplify the kernel_write() backport Instead of duplicating some of the scst_writev() implementation, always call scst_writev(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9188 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_lib.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 7471e2edb..da7322837 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -5999,25 +5999,12 @@ static int scst_cmp_fs_ds(void) ssize_t kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) { - mm_segment_t old_fs = get_fs(); - ssize_t result; - - set_fs(KERNEL_DS); - { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) struct iovec iov = { .iov_base = (void __force __user *)buf, .iov_len = count }; - result = scst_writev(file, &iov, 1, pos); -#else - result = vfs_write(file, (void __force __user *)buf, count, pos); -#endif - } - set_fs(old_fs); - - return result; + return scst_writev(file, &iov, 1, pos); } EXPORT_SYMBOL(kernel_write); #endif From fd5b31888038ef2a7c37ca3d2651d11630177fbb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 15:58:00 +0000 Subject: [PATCH 3/7] iscsi-scst: Port to Linux kernel v5.10 mm_segment_t, get_fs() and set_fs() have been removed from Linux kernel v5.10. Instead of adding more #ifdef / #endif directives, provide backports for this typedef and these functions in iscsi_scst.h. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9189 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/include/iscsi_scst.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/iscsi-scst/include/iscsi_scst.h b/iscsi-scst/include/iscsi_scst.h index 124ff131d..d6b7acd33 100644 --- a/iscsi-scst/include/iscsi_scst.h +++ b/iscsi-scst/include/iscsi_scst.h @@ -16,6 +16,28 @@ #ifndef _ISCSI_SCST_U_H #define _ISCSI_SCST_U_H +#ifdef __KERNEL__ +#include /* mm_segment_t */ +#include + +/* */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) +/* + * With kernel 5.9 or older, certain kernel functions, e.g. setsockopt(), + * sock_recvmsg() only accept a pointer to a user space buffer. With kernel + * v5.10 these functions accept a sockptr_t, a data structure that includes + * information about the address space of a pointer. See also commit + * 47058bb54b57 ("x86: remove address space overrides using set_fs()"). See + * also https://lwn.net/Articles/832121/. The definitions below make it easy + * to write kernel code that is compatible with all kernel versions. + */ +#define KERNEL_DS ((mm_segment_t) { }) +static inline mm_segment_t get_fs(void) { return ((mm_segment_t) { }); } +static inline void set_fs(mm_segment_t seg) { } +#endif +#endif + #ifdef __KERNEL__ #include #else From e93e3cd2fb3da6c18d741cab19ff72f1c8537fa7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 15:59:23 +0000 Subject: [PATCH 4/7] scst/include/backport.h: Port READ_REF_COUNT() to Linux kernel v5.10 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9190 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/backport.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scst/include/backport.h b/scst/include/backport.h index 508fcf011..52e38e693 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -1184,7 +1184,11 @@ typedef unsigned percpu_count_t; #define READ_REF_COUNT(ref) atomic_read(&(ref)->count) #else typedef unsigned long percpu_count_t; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) #define READ_REF_COUNT(ref) atomic_long_read(&(ref)->count) +#else +#define READ_REF_COUNT(ref) atomic_long_read(&(ref)->data->count) +#endif #endif /* From a7214ad3d1fe7b7efe6ae54be37e4ade9d9ad2ec Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 16:07:09 +0000 Subject: [PATCH 5/7] scst: Port scst_readv() and scst_writev() to Linux kernel v5.10 Additionally, prevent that these functions trigger memory allocation if vlen > 8. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9191 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_lib.c | 87 +++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index da7322837..54aca49a3 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include /* struct kiocb for kernel v4.0 */ #include #include #include @@ -5987,6 +5988,7 @@ static void scst_complete_request_sense(struct scst_cmd *req_cmd) return; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) static int scst_cmp_fs_ds(void) { mm_segment_t fs = get_fs(); @@ -5994,6 +5996,7 @@ static int scst_cmp_fs_ds(void) return memcmp(&fs, &ds, sizeof(fs)); } +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) && !defined(RHEL_MAJOR) ssize_t kernel_write(struct file *file, const void *buf, size_t count, @@ -6012,38 +6015,35 @@ EXPORT_SYMBOL(kernel_write); ssize_t scst_readv(struct file *file, const struct iovec *vec, unsigned long vlen, loff_t *pos) { - mm_segment_t old_fs = get_fs(); ssize_t result; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) struct iov_iter iter; + struct kiocb kiocb; + size_t count = 0; + int i; - set_fs(KERNEL_DS); - WARN_ON_ONCE(scst_cmp_fs_ds() != 0); - - result = import_iovec(READ, (const struct iovec __force __user *)vec, - vlen, ARRAY_SIZE(iovstack), &iov, &iter); - if (result >= 0) { - result = vfs_iter_read(file, &iter, pos, 0); - BUG_ON(iov == iovstack); - kfree(iov); - } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) || \ - (defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) - set_fs(KERNEL_DS); - WARN_ON_ONCE(scst_cmp_fs_ds() != 0); - - result = vfs_readv(file, (const struct iovec __user *)vec, vlen, pos, - 0); + BUILD_BUG_ON(sizeof(struct kvec) != sizeof(struct iovec)); + BUILD_BUG_ON(offsetof(struct kvec, iov_base) != + offsetof(struct iovec, iov_base)); + BUILD_BUG_ON(offsetof(struct kvec, iov_len) != + offsetof(struct iovec, iov_len)); + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *pos; + for (i = 0; i < vlen; i++) + count += vec[i].iov_len; + iov_iter_kvec(&iter, READ, (struct kvec *)vec, vlen, count); + result = call_read_iter(file, &kiocb, &iter); + sBUG_ON(result == -EIOCBQUEUED); + if (result > 0) + *pos += result; #else + mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); WARN_ON_ONCE(scst_cmp_fs_ds() != 0); result = vfs_readv(file, (const struct iovec __user *)vec, vlen, pos); -#endif set_fs(old_fs); +#endif return result; } @@ -6062,38 +6062,31 @@ EXPORT_SYMBOL(scst_readv); ssize_t scst_writev(struct file *file, const struct iovec *vec, unsigned long vlen, loff_t *pos) { - mm_segment_t old_fs = get_fs(); ssize_t result; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) struct iov_iter iter; + struct kiocb kiocb; + size_t count = 0; + int i; - set_fs(KERNEL_DS); - WARN_ON_ONCE(scst_cmp_fs_ds() != 0); - - result = import_iovec(WRITE, (const struct iovec __force __user *)vec, - vlen, ARRAY_SIZE(iovstack), &iov, &iter); - if (result >= 0) { - file_start_write(file); - result = vfs_iter_write(file, &iter, pos, 0); - file_end_write(file); - BUG_ON(iov == iovstack); - kfree(iov); - } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) || \ - (defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) - set_fs(KERNEL_DS); - WARN_ON_ONCE(scst_cmp_fs_ds() != 0); - result = vfs_writev(file, (const struct iovec __user *)vec, vlen, pos, - 0); + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *pos; + for (i = 0; i < vlen; i++) + count += vec[i].iov_len; + iov_iter_kvec(&iter, WRITE, (struct kvec *)vec, vlen, count); + file_start_write(file); + result = call_write_iter(file, &kiocb, &iter); + file_end_write(file); + sBUG_ON(result == -EIOCBQUEUED); + if (result > 0) + *pos += result; #else + mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); WARN_ON_ONCE(scst_cmp_fs_ds() != 0); result = vfs_writev(file, (const struct iovec __user *)vec, vlen, pos); -#endif set_fs(old_fs); +#endif return result; } From e9299277fd5461348f78b1bcb31c388d3beb6d50 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 16:07:50 +0000 Subject: [PATCH 6/7] scst: Use kern_path() from kernel version v2.6.28 on See also commit d181146572c4 ("[PATCH] new helper - kern_path()"; v2.6.28). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9192 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 4 ++-- scst/src/scst_lib.c | 4 ++-- scst/src/scst_pres.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 33672d14d..351c53800 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -10076,7 +10076,7 @@ static void init_ops(vdisk_op_fn *ops, int count) static int __init vdev_check_mode_pages_path(void) { int res; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) struct nameidata nd; #else struct path path; @@ -10084,7 +10084,7 @@ static int __init vdev_check_mode_pages_path(void) TRACE_ENTRY(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) res = path_lookup(VDEV_MODE_PAGES_DIR, 0, &nd); if (res == 0) scst_path_put(&nd); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 54aca49a3..14629687c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -15210,7 +15210,7 @@ out: int scst_remove_file(const char *name) { int res = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) struct nameidata nd; #else struct path path; @@ -15218,7 +15218,7 @@ int scst_remove_file(const char *name) TRACE_ENTRY(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) res = path_lookup(name, 0, &nd); if (!res) scst_vfs_unlink_and_put(&nd); diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 12c44cfc3..5c1703374 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -1017,7 +1017,7 @@ write_error: write_error_close: filp_close(file, NULL); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) { struct nameidata nd; int rc; From 54545b43e5d016fcc24c359fb286248a74676204 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 23 Nov 2020 16:08:41 +0000 Subject: [PATCH 7/7] scst: Rename the old version of scst_vfs_unlink_and_put() See also commit c5e725f33b73 ("Move struct path into its own header"; v2.6.25). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9193 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_lib.c | 8 ++++---- scst/src/scst_pres.c | 2 +- scst/src/scst_priv.h | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 14629687c..aeafe2332 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -15077,7 +15077,7 @@ out_unlock: /* Abstract vfs_unlink() for different kernel versions (as possible) */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) -void scst_vfs_unlink_and_put(struct nameidata *nd) +void scst_vfs_unlink_and_put_nd(struct nameidata *nd) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) vfs_unlink(nd->dentry->d_parent->d_inode, nd->dentry); @@ -15089,7 +15089,8 @@ void scst_vfs_unlink_and_put(struct nameidata *nd) path_put(&nd->path); #endif } -#else +#endif + void scst_vfs_unlink_and_put(struct path *path) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) && \ @@ -15102,7 +15103,6 @@ void scst_vfs_unlink_and_put(struct path *path) #endif path_put(path); } -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) void scst_path_put(struct nameidata *nd) @@ -15221,7 +15221,7 @@ int scst_remove_file(const char *name) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) res = path_lookup(name, 0, &nd); if (!res) - scst_vfs_unlink_and_put(&nd); + scst_vfs_unlink_and_put_nd(&nd); else TRACE_DBG("Unable to lookup file '%s' - error %d", name, res); #else diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 5c1703374..d539d200d 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -1024,7 +1024,7 @@ write_error_close: rc = path_lookup(dev->pr_file_name, 0, &nd); if (!rc) - scst_vfs_unlink_and_put(&nd); + scst_vfs_unlink_and_put_nd(&nd); else TRACE_PR("Unable to lookup '%s' - error %d", dev->pr_file_name, rc); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 8a51f94d6..b2226fad8 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -766,10 +766,9 @@ int scst_pr_init(struct scst_device *dev); void scst_pr_cleanup(struct scst_device *dev); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) -void scst_vfs_unlink_and_put(struct nameidata *nd); -#else -void scst_vfs_unlink_and_put(struct path *path); +void scst_vfs_unlink_and_put_nd(struct nameidata *nd); #endif +void scst_vfs_unlink_and_put(struct path *path); int scst_copy_file(const char *src, const char *dest);