From 32c0dbce0992e328f990ef9be5d8fb23102b3571 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:00:43 -0400 Subject: [PATCH 01/46] Include kernel.h and fs.h at the top of kernelcompat.h Because we `-include src/kernelcompat.h` from the command line, this header gets included before any of the kernel includes in most .c and .h files. We should at least make sure we pull in and since they're required. Signed-off-by: Auke Kok --- kmod/src/kernelcompat.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 12e16a10..7aed2d5a 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -1,8 +1,10 @@ #ifndef _SCOUTFS_KERNELCOMPAT_H_ #define _SCOUTFS_KERNELCOMPAT_H_ -#ifndef KC_ITERATE_DIR_CONTEXT +#include #include + +#ifndef KC_ITERATE_DIR_CONTEXT typedef filldir_t kc_readdir_ctx_t; #define KC_DECLARE_READDIR(name, file, dirent, ctx) name(file, dirent, ctx) #define KC_FOP_READDIR readdir From 8e458f92309c65fd9ccf17144359f10d2137401d Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 15 May 2023 14:20:48 -0400 Subject: [PATCH 02/46] PAGE_CACHE_SIZE was removed, replace with PAGE_SIZE. PAGE_CACHE_SIZE was previously defined to be equivalent to PAGE_SIZE. This symbol was removed in v4.6-rc1-32-g1fa64f198b9f. Signed-off-by: Auke Kok --- kmod/src/data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index 48aae57a..d3a9e0e2 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -704,7 +704,7 @@ static int scoutfs_readpage(struct file *file, struct page *page) if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) { ret = scoutfs_data_wait_check(inode, page_offset(page), - PAGE_CACHE_SIZE, SEF_OFFLINE, + PAGE_SIZE, SEF_OFFLINE, SCOUTFS_IOC_DWO_READ, &dw, inode_lock); if (ret != 0) { @@ -754,7 +754,7 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping, list_for_each_entry_safe(page, tmp, pages, lru) { ret = scoutfs_data_wait_check(inode, page_offset(page), - PAGE_CACHE_SIZE, SEF_OFFLINE, + PAGE_SIZE, SEF_OFFLINE, SCOUTFS_IOC_DWO_READ, NULL, inode_lock); if (ret < 0) From 006555d42aab210a05d1a45b25045d39c06e1434 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 15 May 2023 14:55:19 -0400 Subject: [PATCH 03/46] READ_ONCE() replaces ACCESS_ONCE() v3.18-rc3-2-g230fa253df63 forces us to remove ACCESS_ONCE() with READ_ONCE(), but it is probably the better interface and works with non-scalar types. Signed-off-by: Auke Kok --- kmod/src/dir.c | 2 +- kmod/src/lock.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmod/src/dir.c b/kmod/src/dir.c index d3a6e031..aa1272af 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -272,7 +272,7 @@ static void set_dentry_fsdata(struct dentry *dentry, struct scoutfs_lock *lock) static bool test_dentry_fsdata(struct dentry *dentry, u64 refresh) { - u64 fsd = (unsigned long)ACCESS_ONCE(dentry->d_fsdata); + u64 fsd = (unsigned long)READ_ONCE(dentry->d_fsdata); return fsd == refresh; } diff --git a/kmod/src/lock.c b/kmod/src/lock.c index bd726cec..5be16d3c 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -1346,7 +1346,7 @@ void scoutfs_lock_del_coverage(struct super_block *sb, bool scoutfs_lock_protected(struct scoutfs_lock *lock, struct scoutfs_key *key, enum scoutfs_lock_mode mode) { - signed char lock_mode = ACCESS_ONCE(lock->mode); + signed char lock_mode = READ_ONCE(lock->mode); return lock_modes_match(lock_mode, mode) && scoutfs_key_compare_ranges(key, key, From eafb8621da64aab47b4ffc79534ddf275ff56099 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 15 May 2023 18:24:30 -0400 Subject: [PATCH 04/46] d_materialise_unique replaced with d_splice_alias. Note argument order reversal. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/kernelcompat.h | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index d7995cc5..fab13456 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -26,6 +26,16 @@ ifneq (,$(shell grep 'dir_emit_dots' include/linux/fs.h)) ccflags-y += -DKC_DIR_EMIT_DOTS endif +# +# v3.18-rc2-19-gb5ae6b15bd73 +# +# Folds d_materialise_unique into d_splice_alias. Note reversal +# of arguments (Also note Documentation/filesystems/porting.rst) +# +ifneq (,$(shell grep 'd_materialise_unique' include/linux/dcache.h)) +ccflags-y += -DKC_D_MATERIALISE_UNIQUE=1 +endif + # # RHEL extended the fop struct so to use it we have to set # a flag to indicate that the struct is large enough and diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 7aed2d5a..1514a6f0 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -54,4 +54,14 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define kc_posix_acl_valid(user_ns, acl) posix_acl_valid(acl) #endif +/* + * v3.18-rc2-19-gb5ae6b15bd73 + * + * Folds d_materialise_unique into d_splice_alias. Note reversal + * of arguments (Also note Documentation/filesystems/porting.rst) + */ +#ifndef KC_D_MATERIALISE_UNIQUE +#define d_materialise_unique(dentry, inode) d_splice_alias(inode, dentry) +#endif + #endif From 7006a84d96a3a6e6ecce48d8f50a0d035705c969 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 15 May 2023 18:32:24 -0400 Subject: [PATCH 05/46] flush_work_sync is equivalent to flush_work. v3.15-rc1-6-g1a56f2aa4752 removes flush_work_sync entirely, but ever since v3.6-rc1-25-g606a5020b9bd which made all workqueues non-reentrant, it has been equivalent to flush_work. This is safe because in all cases only one server->work can be in flight at a time. Signed-off-by: Auke Kok --- kmod/src/kernelcompat.h | 10 ++++++++++ kmod/src/server.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 1514a6f0..cd5ff1de 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -54,6 +54,16 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define kc_posix_acl_valid(user_ns, acl) posix_acl_valid(acl) #endif +/* + * v3.6-rc1-24-gdbf2576e37da + * + * All workqueues are now non-reentrant, and the bit flag is removed + * shortly after its uses were removed. + */ +#ifndef WQ_NON_REENTRANT +#define WQ_NON_REENTRANT 0 +#endif + /* * v3.18-rc2-19-gb5ae6b15bd73 * diff --git a/kmod/src/server.c b/kmod/src/server.c index e00d1bca..c8f9be8d 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -4464,7 +4464,7 @@ void scoutfs_server_stop_wait(struct super_block *sb) DECLARE_SERVER_INFO(sb, server); stop_server(server); - flush_work_sync(&server->work); + flush_work(&server->work); } int scoutfs_server_setup(struct super_block *sb) From 430960ef3cf1667916ab49356670480a3bf495f6 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 19:26:06 -0400 Subject: [PATCH 06/46] page_cache_release() is removed. put_page() instead. Even in 3.x, this already was equivalent. Signed-off-by: Auke Kok --- kmod/src/data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index d3a9e0e2..c93d7cf8 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -761,7 +761,7 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping, goto out; if (ret > 0) { list_del(&page->lru); - page_cache_release(page); + put_page(page); if (--nr_pages == 0) { ret = 0; goto out; From 28c3cee9955f46751e7dace5d4a7a9d6c8bab6ab Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 9 May 2023 15:18:47 -0400 Subject: [PATCH 07/46] preempt_mask.h is removed entirely. v4.1-rc4-22-g92cf211874e9 merges this into preempt.h, and on rhel7 kernels we don't need this include anymore either. Signed-off-by: Auke Kok --- kmod/src/lock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kmod/src/lock.c b/kmod/src/lock.c index 5be16d3c..2ed75b9f 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -12,7 +12,6 @@ */ #include #include -#include /* a rhel shed.h needed preempt_offset? */ #include #include #include From f27431b3ae6ab21bcea05227319760b72183cabd Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:26:22 -0400 Subject: [PATCH 08/46] Add include . MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: Error: implicit declaration of function ‘blkdev_put’ Previously this was an `extern` in and included implicitly, hence the need to hard include it now. Signed-off-by: Auke Kok --- kmod/src/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kmod/src/super.c b/kmod/src/super.c index 10016a74..fecd2132 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include From c683ded0e639efeabb12610ab263c9336dc1a74f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 19:30:29 -0400 Subject: [PATCH 09/46] Adjust for new augmented rbtree compute callback function signature The new variant of the code that recomputes the augmented value is designed to handle non-scalar types and to facilitate that, it has new semantics for the _compute callback. It is now passed a boolean flag `exit` that indicates that if the value isn't changed, it should exit and halt propagation. The callback function now shall return whether that propagation should stop or not, and not the computed new value. The callback can now directly update the new computed value in the node. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/tseq.c | 20 +++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index fab13456..896b7117 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -53,3 +53,13 @@ endif ifneq (,$(shell grep 'posix_acl_valid.*user_ns,' include/linux/posix_acl.h)) ccflags-y += -DKC_POSIX_ACL_VALID_USER_NS endif + +# +# v5.3-12296-g6d2052d188d9 +# +# The RBCOMPUTE function is now passed an extra flag, and should return a bool +# to indicate whether the propagated callback should stop or not. +# +ifneq (,$(shell grep 'static inline bool RBNAME.*_compute_max' include/linux/rbtree_augmented.h)) +ccflags-y += -DKC_RB_TREE_AUGMENTED_COMPUTE_MAX +endif diff --git a/kmod/src/tseq.c b/kmod/src/tseq.c index 781d00f3..b4b07f34 100644 --- a/kmod/src/tseq.c +++ b/kmod/src/tseq.c @@ -46,6 +46,23 @@ static struct scoutfs_tseq_entry *tseq_rb_next(struct scoutfs_tseq_entry *ent) return rb_entry(node, struct scoutfs_tseq_entry, node); } +#ifdef KC_RB_TREE_AUGMENTED_COMPUTE_MAX +static bool tseq_compute_total(struct scoutfs_tseq_entry *ent, bool exit) +{ + loff_t total = 1 + tseq_node_total(ent->node.rb_left) + + tseq_node_total(ent->node.rb_right); + + if (exit && ent->total == total) + return true; + + ent->total = total; + return false; +} + +RB_DECLARE_CALLBACKS(static, tseq_rb_callbacks, struct scoutfs_tseq_entry, + node, total, tseq_compute_total); +#else + static loff_t tseq_compute_total(struct scoutfs_tseq_entry *ent) { return 1 + tseq_node_total(ent->node.rb_left) + @@ -53,7 +70,8 @@ static loff_t tseq_compute_total(struct scoutfs_tseq_entry *ent) } RB_DECLARE_CALLBACKS(static, tseq_rb_callbacks, struct scoutfs_tseq_entry, - node, loff_t, total, tseq_compute_total) + node, loff_t, total, tseq_compute_total); +#endif void scoutfs_tseq_tree_init(struct scoutfs_tseq_tree *tree, scoutfs_tseq_show_t show) From 81aa58253ef8aa076222d7b75003f00ee3a8a4ef Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 9 May 2023 15:53:23 -0400 Subject: [PATCH 10/46] module_init/_exit should have a semicolon at eol. In the past this was not needed but since el7 onwards these macros should require the semicolon. Signed-off-by: Auke Kok --- kmod/src/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmod/src/super.c b/kmod/src/super.c index fecd2132..bcbf9ebd 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -675,14 +675,14 @@ out: teardown_module(); return ret; } -module_init(scoutfs_module_init) +module_init(scoutfs_module_init); static void __exit scoutfs_module_exit(void) { unregister_filesystem(&scoutfs_fs_type); teardown_module(); } -module_exit(scoutfs_module_exit) +module_exit(scoutfs_module_exit); MODULE_AUTHOR("Zach Brown "); MODULE_LICENSE("GPL"); From cf4df0ef9f46d41c6d4028bcc6c5205f4d8fc792 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 9 May 2023 15:11:34 -0400 Subject: [PATCH 11/46] use $(MAKE) to allow passing jobserver flags. With this, we can `make -jX` to speed up compiles a bit from the kmod folder. Signed-off-by: Auke Kok --- kmod/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kmod/Makefile b/kmod/Makefile index 58963acf..9a210509 100644 --- a/kmod/Makefile +++ b/kmod/Makefile @@ -31,12 +31,12 @@ TARFILE = scoutfs-kmod-$(RPM_VERSION).tar all: module module: - make $(SCOUTFS_ARGS) - $(SP) make C=2 CF="-D__CHECK_ENDIAN__" $(SCOUTFS_ARGS) + $(MAKE) $(SCOUTFS_ARGS) + $(SP) $(MAKE) C=2 CF="-D__CHECK_ENDIAN__" $(SCOUTFS_ARGS) modules_install: - make $(SCOUTFS_ARGS) modules_install + $(MAKE) $(SCOUTFS_ARGS) modules_install %.spec: %.spec.in .FORCE @@ -50,4 +50,4 @@ dist: scoutfs-kmod.spec @ tar rf $(TARFILE) --transform="s@\(.*\)@scoutfs-kmod-$(RPM_VERSION)/\1@" scoutfs-kmod.spec clean: - make $(SCOUTFS_ARGS) clean + $(MAKE) $(SCOUTFS_ARGS) clean From af868aad9bbeeefc240261035a8d719a4fa23e25 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 9 May 2023 14:30:46 -0400 Subject: [PATCH 12/46] New inode->i_version API requires Since v4.15-rc3-4-gae5e165d855d, contains a new inode->i_version API and it is not included by default. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/kernelcompat.h | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 896b7117..1880905e 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -63,3 +63,13 @@ endif ifneq (,$(shell grep 'static inline bool RBNAME.*_compute_max' include/linux/rbtree_augmented.h)) ccflags-y += -DKC_RB_TREE_AUGMENTED_COMPUTE_MAX endif + +# +# v4.15-rc3-4-gae5e165d855d +# +# linux/iversion.h needs to manually be included for code that +# manipulates this field. +# +ifneq (,$(shell grep -s 'define _LINUX_IVERSION_H' include/linux/iversion.h)) +ccflags-y += -DKC_NEED_LINUX_IVERSION_H=1 +endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index cd5ff1de..0a1b8d56 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -4,6 +4,17 @@ #include #include +/* + * v4.15-rc3-4-gae5e165d855d + * + * new API for handling inode->i_version. This forces us to + * include this API where we need. We include it here for + * convenience instead of where it's needed. + */ +#ifdef KC_NEED_LINUX_IVERSION_H +#include +#endif + #ifndef KC_ITERATE_DIR_CONTEXT typedef filldir_t kc_readdir_ctx_t; #define KC_DECLARE_READDIR(name, file, dirent, ctx) name(file, dirent, ctx) From dac3f056a5ac350f0128973c5efcb6f217fab2ee Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 9 May 2023 15:47:19 -0400 Subject: [PATCH 13/46] inode->i_mutex has been replaced with inode->i_rwsem. Since v4.6-rc3-27-g9902af79c01a, inode->i_mutex has been replaced with ->i_rwsem. However, long since whenever, inode_lock() and related functions already worked as intended and provided fully exclusive locking to the inode. To avoid a name clash on pre-rhel8 kernels, we have to rename a stack variable in `src/file.c`. Signed-off-by: Auke Kok --- kmod/src/data.c | 12 ++++++------ kmod/src/file.c | 30 +++++++++++++++--------------- kmod/src/inode.c | 4 ++-- kmod/src/ioctl.c | 16 ++++++++-------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index c93d7cf8..54009404 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -307,7 +307,7 @@ int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode, LIST_HEAD(ind_locks); s64 ret = 0; - WARN_ON_ONCE(inode && !mutex_is_locked(&inode->i_mutex)); + WARN_ON_ONCE(inode && !inode_is_locked(inode)); /* clamp last to the last possible block? */ if (last > SCOUTFS_BLOCK_SM_MAX) @@ -558,7 +558,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock, u64 offset; int ret; - WARN_ON_ONCE(create && !mutex_is_locked(&inode->i_mutex)); + WARN_ON_ONCE(create && !inode_is_locked(inode)); /* make sure caller holds a cluster lock */ lock = scoutfs_per_task_get(&si->pt_data_lock); @@ -1057,7 +1057,7 @@ long scoutfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) goto out; } - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, SCOUTFS_LKF_REFRESH_INODE, inode, &lock); @@ -1118,7 +1118,7 @@ out_extent: up_write(&si->extent_sem); out_mutex: scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); out: trace_scoutfs_data_fallocate(sb, ino, mode, offset, len, ret); @@ -1529,7 +1529,7 @@ int scoutfs_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, if (ret) goto out; - mutex_lock(&inode->i_mutex); + inode_lock(inode); down_read(&si->extent_sem); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, 0, inode, &lock); @@ -1583,7 +1583,7 @@ int scoutfs_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, unlock: scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ); up_read(&si->extent_sem); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); out: if (ret == 1) diff --git a/kmod/src/file.c b/kmod/src/file.c index 586d77fd..08058592 100644 --- a/kmod/src/file.c +++ b/kmod/src/file.c @@ -42,27 +42,27 @@ ssize_t scoutfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, struct inode *inode = file_inode(file); struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; - struct scoutfs_lock *inode_lock = NULL; + struct scoutfs_lock *scoutfs_inode_lock = NULL; SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); DECLARE_DATA_WAIT(dw); int ret; retry: /* protect checked extents from release */ - mutex_lock(&inode->i_mutex); + inode_lock(inode); atomic_inc(&inode->i_dio_count); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, - SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock); + SCOUTFS_LKF_REFRESH_INODE, inode, &scoutfs_inode_lock); if (ret) goto out; - if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) { + if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, scoutfs_inode_lock)) { ret = scoutfs_data_wait_check_iov(inode, iov, nr_segs, pos, SEF_OFFLINE, SCOUTFS_IOC_DWO_READ, - &dw, inode_lock); + &dw, scoutfs_inode_lock); if (ret != 0) goto out; } else { @@ -74,7 +74,7 @@ retry: out: inode_dio_done(inode); scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); - scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); + scoutfs_unlock(sb, scoutfs_inode_lock, SCOUTFS_LOCK_READ); if (scoutfs_data_wait_found(&dw)) { ret = scoutfs_data_wait(inode, &dw); @@ -92,7 +92,7 @@ ssize_t scoutfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, struct inode *inode = file_inode(file); struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; - struct scoutfs_lock *inode_lock = NULL; + struct scoutfs_lock *scoutfs_inode_lock = NULL; SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); DECLARE_DATA_WAIT(dw); int ret; @@ -101,22 +101,22 @@ ssize_t scoutfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, return 0; retry: - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, - SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock); + SCOUTFS_LKF_REFRESH_INODE, inode, &scoutfs_inode_lock); if (ret) goto out; - ret = scoutfs_complete_truncate(inode, inode_lock); + ret = scoutfs_complete_truncate(inode, scoutfs_inode_lock); if (ret) goto out; - if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) { + if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, scoutfs_inode_lock)) { /* data_version is per inode, whole file must be online */ ret = scoutfs_data_wait_check(inode, 0, i_size_read(inode), SEF_OFFLINE, SCOUTFS_IOC_DWO_WRITE, - &dw, inode_lock); + &dw, scoutfs_inode_lock); if (ret != 0) goto out; } @@ -127,8 +127,8 @@ retry: out: scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); - scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_WRITE); - mutex_unlock(&inode->i_mutex); + scoutfs_unlock(sb, scoutfs_inode_lock, SCOUTFS_LOCK_WRITE); + inode_unlock(inode); if (scoutfs_data_wait_found(&dw)) { ret = scoutfs_data_wait(inode, &dw); diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 6741bda7..0149602a 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -496,9 +496,9 @@ retry: scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); /* XXX callee locks instead? */ - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); ret = scoutfs_data_wait(inode, &dw); - mutex_lock(&inode->i_mutex); + inode_lock(inode); if (ret == 0) goto retry; diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index 3bc9c546..964db6f4 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -302,7 +302,7 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) if (ret) return ret; - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, SCOUTFS_LKF_REFRESH_INODE, inode, &lock); @@ -351,7 +351,7 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) out: scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); mnt_drop_write_file(file); trace_scoutfs_ioc_release_ret(sb, scoutfs_ino(inode), ret); @@ -393,7 +393,7 @@ static long scoutfs_ioc_data_wait_err(struct file *file, unsigned long arg) goto out; } - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, SCOUTFS_LKF_REFRESH_INODE, inode, &lock); @@ -411,7 +411,7 @@ static long scoutfs_ioc_data_wait_err(struct file *file, unsigned long arg) scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ); unlock: - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); iput(inode); out: return ret; @@ -489,7 +489,7 @@ static long scoutfs_ioc_stage(struct file *file, unsigned long arg) if (ret) return ret; - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, SCOUTFS_LKF_REFRESH_INODE, inode, &lock); @@ -533,7 +533,7 @@ static long scoutfs_ioc_stage(struct file *file, unsigned long arg) out: scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); mnt_drop_write_file(file); trace_scoutfs_ioc_stage_ret(sb, scoutfs_ino(inode), ret); @@ -652,7 +652,7 @@ static long scoutfs_ioc_setattr_more(struct file *file, unsigned long arg) if (ret) goto out; - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, SCOUTFS_LKF_REFRESH_INODE, inode, &lock); @@ -696,7 +696,7 @@ static long scoutfs_ioc_setattr_more(struct file *file, unsigned long arg) unlock: scoutfs_inode_index_unlock(sb, &ind_locks); scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); mnt_drop_write_file(file); out: From 1f0a08eacb3d4a02249e1c0dbc9cefe56d9eb021 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 14:36:39 -0400 Subject: [PATCH 14/46] Use the new inode->i_version manipulation methods. Provide fallback in degraded mode for kernels pre-v4.15-rc3 by directly manipulating the member as needed. Signed-off-by: Auke Kok --- kmod/src/inode.c | 6 +++--- kmod/src/kernelcompat.h | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 0149602a..414be4a5 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -247,7 +247,7 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode) struct scoutfs_inode_info *si = SCOUTFS_I(inode); i_size_write(inode, le64_to_cpu(cinode->size)); - inode->i_version = le64_to_cpu(cinode->version); + inode_set_iversion_queried(inode, le64_to_cpu(cinode->version)); set_nlink(inode, le32_to_cpu(cinode->nlink)); i_uid_write(inode, le32_to_cpu(cinode->uid)); i_gid_write(inode, le32_to_cpu(cinode->gid)); @@ -750,7 +750,7 @@ struct inode *scoutfs_iget(struct super_block *sb, u64 ino, int lkf, int igf) /* XXX ensure refresh, instead clear in drop_inode? */ si = SCOUTFS_I(inode); atomic64_set(&si->last_refreshed, 0); - inode->i_version = 0; + inode_set_iversion_queried(inode, 0); } ret = scoutfs_inode_refresh(inode, lock); @@ -798,7 +798,7 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode) scoutfs_inode_get_onoff(inode, &online_blocks, &offline_blocks); cinode->size = cpu_to_le64(i_size_read(inode)); - cinode->version = cpu_to_le64(inode->i_version); + cinode->version = cpu_to_le64(inode_peek_iversion(inode)); cinode->nlink = cpu_to_le32(inode->i_nlink); cinode->uid = cpu_to_le32(i_uid_read(inode)); cinode->gid = cpu_to_le32(i_gid_read(inode)); diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 0a1b8d56..8b9a1c3b 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -13,6 +13,20 @@ */ #ifdef KC_NEED_LINUX_IVERSION_H #include +#else +/* + * Kernels before above version will need to fall back to + * manipulating inode->i_version as previous with degraded + * methods. + */ +#define inode_set_iversion_queried(inode, val) \ +do { \ + (inode)->i_version = val; \ +} while (0) +#define inode_peek_iversion(inode) \ +({ \ + (inode)->i_version; \ +}) #endif #ifndef KC_ITERATE_DIR_CONTEXT From f0de59a9a3dee5845ce11b3e27df051edc174ae6 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 19:23:40 -0400 Subject: [PATCH 15/46] Use setattr_preapre() as inode_change_ok() was removed in v4.8-rc1 Instead, we can call setattr_prepare() directly. We provide a fallback for older kernels. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/inode.c | 3 +-- kmod/src/kernelcompat.h | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 1880905e..570be1e5 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -64,6 +64,15 @@ ifneq (,$(shell grep 'static inline bool RBNAME.*_compute_max' include/linux/rbt ccflags-y += -DKC_RB_TREE_AUGMENTED_COMPUTE_MAX endif +# +# v4.8-rc1-29-g31051c85b5e2 +# +# inode_change_ok() removed - replace with setattr_prepare() +# +ifneq (,$(shell grep 'extern int setattr_prepare' include/linux/fs.h)) +ccflags-y += -DKC_SETATTR_PREPARE +endif + # # v4.15-rc3-4-gae5e165d855d # diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 414be4a5..6016c0d2 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -467,8 +467,7 @@ retry: SCOUTFS_LKF_REFRESH_INODE, inode, &lock); if (ret) return ret; - - ret = inode_change_ok(inode, attr); + ret = setattr_prepare(dentry, attr); if (ret) goto out; diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 8b9a1c3b..1f6072e3 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -99,4 +99,13 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define d_materialise_unique(dentry, inode) d_splice_alias(inode, dentry) #endif +/* + * v4.8-rc1-29-g31051c85b5e2 + * + * fall back to inode_change_ok() if setattr_prepare() isn't available + */ +#ifndef KC_SETATTR_PREPARE +#define setattr_prepare(dentry, attr) inode_change_ok(d_inode(dentry), attr) +#endif + #endif From 4293816764a2929a7f8dec8d3179b0479d3d8311 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 16:46:14 -0400 Subject: [PATCH 16/46] Fix argument test for __posix_acl_valid. The argument is fixed to be user_namespace, instead of user_ns. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 570be1e5..f1e0b8bb 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -50,7 +50,7 @@ endif # # Added user_ns argument to posix_acl_valid # -ifneq (,$(shell grep 'posix_acl_valid.*user_ns,' include/linux/posix_acl.h)) +ifneq (,$(shell grep 'posix_acl_valid.*user_namespace' include/linux/posix_acl.h)) ccflags-y += -DKC_POSIX_ACL_VALID_USER_NS endif From b89ecd47b409ff5bc2d7d263deb62719a8de420f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 26 May 2023 16:18:55 -0400 Subject: [PATCH 17/46] Use __posix_acl_create/_chmod and add backwards compatibility There are new interfaces available but the old one has been retained for us to use. In case of older kernels, we will need to fall back to the previous name of these functions. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/acl.c | 4 ++-- kmod/src/kernelcompat.h | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index f1e0b8bb..fde9b31a 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -64,6 +64,16 @@ ifneq (,$(shell grep 'static inline bool RBNAME.*_compute_max' include/linux/rbt ccflags-y += -DKC_RB_TREE_AUGMENTED_COMPUTE_MAX endif +# +# v3.13-25-g37bc15392a23 +# +# Renames posix_acl_create to __posix_acl_create and provide some +# new interfaces for creating ACLs +# +ifneq (,$(shell grep '__posix_acl_create' include/linux/posix_acl.h)) +ccflags-y += -DKC___POSIX_ACL_CREATE +endif + # # v4.8-rc1-29-g31051c85b5e2 # diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 11a83266..6b43d8cc 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -301,7 +301,7 @@ int scoutfs_init_acl_locked(struct inode *inode, struct inode *dir, if (ret) goto out; } - ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + ret = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (ret < 0) return ret; if (ret > 0) @@ -345,7 +345,7 @@ int scoutfs_acl_chmod_locked(struct inode *inode, struct iattr *attr, if (IS_ERR_OR_NULL(acl)) return PTR_ERR(acl); - ret = posix_acl_chmod(&acl, GFP_KERNEL, attr->ia_mode); + ret = __posix_acl_chmod(&acl, GFP_KERNEL, attr->ia_mode); if (ret) return ret; diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 1f6072e3..7c831648 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -108,4 +108,9 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define setattr_prepare(dentry, attr) inode_change_ok(d_inode(dentry), attr) #endif +#ifndef KC___POSIX_ACL_CREATE +#define __posix_acl_create posix_acl_create +#define __posix_acl_chmod posix_acl_chmod +#endif + #endif From 70a5b6ffe2895427954fcca08cb04fb153e89044 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 21 Jul 2022 11:23:02 -0700 Subject: [PATCH 18/46] Use percpu_counter_add_batch __percpu_counter_add_batch was renamed to make it clear that the __ doesn't mean it's less safe, as it means in other calls in the API, but just that it takes an additional parameter. Signed-off-by: Zach Brown Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/counters.h | 8 ++++---- kmod/src/kernelcompat.h | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index fde9b31a..3e129eed 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -92,3 +92,12 @@ endif ifneq (,$(shell grep -s 'define _LINUX_IVERSION_H' include/linux/iversion.h)) ccflags-y += -DKC_NEED_LINUX_IVERSION_H=1 endif + +# v4.11-12447-g104b4e5139fe +# +# Renamed __percpu_counter_add to percpu_counter_add_batch to clarify +# that the __ wasn't less safe, just took an extra parameter. +# +ifneq (,$(shell grep 'percpu_counter_add_batch' include/linux/percpu_counter.h)) +ccflags-y += -DKC_PERCPU_COUNTER_ADD_BATCH +endif diff --git a/kmod/src/counters.h b/kmod/src/counters.h index e681e07a..ccfa1f6f 100644 --- a/kmod/src/counters.h +++ b/kmod/src/counters.h @@ -232,12 +232,12 @@ struct scoutfs_counters { #define SCOUTFS_PCPU_COUNTER_BATCH (1 << 30) #define scoutfs_inc_counter(sb, which) \ - __percpu_counter_add(&SCOUTFS_SB(sb)->counters->which, 1, \ - SCOUTFS_PCPU_COUNTER_BATCH) + percpu_counter_add_batch(&SCOUTFS_SB(sb)->counters->which, 1, \ + SCOUTFS_PCPU_COUNTER_BATCH) #define scoutfs_add_counter(sb, which, cnt) \ - __percpu_counter_add(&SCOUTFS_SB(sb)->counters->which, cnt, \ - SCOUTFS_PCPU_COUNTER_BATCH) + percpu_counter_add_batch(&SCOUTFS_SB(sb)->counters->which, cnt, \ + SCOUTFS_PCPU_COUNTER_BATCH) void __init scoutfs_init_counters(void); int scoutfs_setup_counters(struct super_block *sb); diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 7c831648..b22b265f 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -113,4 +113,8 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define __posix_acl_chmod posix_acl_chmod #endif +#ifndef KC_PERCPU_COUNTER_ADD_BATCH +#define percpu_counter_add_batch __percpu_counter_add +#endif + #endif From 4275f6e6e56437d41d021833437add74ec22db87 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 1 Aug 2022 09:25:17 -0700 Subject: [PATCH 19/46] Use memalloc_nofs_save memalloc_nofs_save() was introduced as preferential to trying to use GFP flags to indicate that a task should not recurse during reclaim. We use it instead of the _noio_ we were using before. Signed-off-by: Zach Brown --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/block.c | 7 ++++--- kmod/src/kernelcompat.h | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 3e129eed..fb802bf2 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -101,3 +101,12 @@ endif ifneq (,$(shell grep 'percpu_counter_add_batch' include/linux/percpu_counter.h)) ccflags-y += -DKC_PERCPU_COUNTER_ADD_BATCH endif + +# +# v4.11-4550-g7dea19f9ee63 +# +# Introduced memalloc_nofs_{save,restore} preferred instead of _noio_. +# +ifneq (,$(shell grep 'memalloc_nofs_save' include/linux/sched/mm.h)) +ccflags-y += -DKC_MEMALLOC_NOFS_SAVE +endif diff --git a/kmod/src/block.c b/kmod/src/block.c index 89cda9c0..14686f15 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "format.h" #include "super.h" @@ -128,7 +129,7 @@ static __le32 block_calc_crc(struct scoutfs_block_header *hdr, u32 size) static struct block_private *block_alloc(struct super_block *sb, u64 blkno) { struct block_private *bp; - unsigned int noio_flags; + unsigned int nofs_flags; /* * If we had multiple blocks per page we'd need to be a little @@ -156,9 +157,9 @@ static struct block_private *block_alloc(struct super_block *sb, u64 blkno) * spurious reclaim-on dependencies and warnings. */ lockdep_off(); - noio_flags = memalloc_noio_save(); + nofs_flags = memalloc_nofs_save(); bp->virt = __vmalloc(SCOUTFS_BLOCK_LG_SIZE, GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL); - memalloc_noio_restore(noio_flags); + memalloc_nofs_restore(nofs_flags); lockdep_on(); if (!bp->virt) { diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index b22b265f..4923730e 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -117,4 +117,9 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define percpu_counter_add_batch __percpu_counter_add #endif +#ifndef KC_MEMALLOC_NOFS_SAVE +#define memalloc_nofs_save memalloc_noio_save +#define memalloc_nofs_restore memalloc_noio_restore +#endif + #endif From 28f03d355867b1069d3a4822a99c7668d33c974f Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 1 Aug 2022 14:10:40 -0700 Subject: [PATCH 20/46] Use more modern bio interfaces Move towards modern bio intefaces, while unfortunately carrying along a bunch of compat functions that let us still work with the old incompatible interfaces. Signed-off-by: Zach Brown Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 20 +++++++++++++ kmod/src/block.c | 52 +++++++++++++++++----------------- kmod/src/kernelcompat.h | 45 +++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 26 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index fb802bf2..99615f18 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -110,3 +110,23 @@ endif ifneq (,$(shell grep 'memalloc_nofs_save' include/linux/sched/mm.h)) ccflags-y += -DKC_MEMALLOC_NOFS_SAVE endif + +# +# v4.7-12414-g1eff9d322a44 +# +# Renamed bi_rw to bi_opf to force old code to catch up. We use it as a +# single switch between old and new bio structures. +# +ifneq (,$(shell grep 'bi_opf' include/linux/blk_types.h)) +ccflags-y += -DKC_BIO_BI_OPF +endif + +# +# v4.12-rc2-201-g4e4cbee93d56 +# +# Moves to bi_status BLK_STS_ API instead of having a mix of error +# end_io args or bi_error. +# +ifneq (,$(shell grep 'bi_status' include/linux/blk_types.h)) +ccflags-y += -DKC_BIO_BI_STATUS +endif diff --git a/kmod/src/block.c b/kmod/src/block.c index 14686f15..7016a4b4 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -437,11 +437,10 @@ static void block_remove_all(struct super_block *sb) * possible. Final freeing, verifying checksums, and unlinking errored * blocks are all done by future users of the blocks. */ -static void block_end_io(struct super_block *sb, int rw, +static void block_end_io(struct super_block *sb, unsigned int opf, struct block_private *bp, int err) { DECLARE_BLOCK_INFO(sb, binf); - bool is_read = !(rw & WRITE); if (err) { scoutfs_inc_counter(sb, block_cache_end_io_error); @@ -451,7 +450,7 @@ static void block_end_io(struct super_block *sb, int rw, if (!atomic_dec_and_test(&bp->io_count)) return; - if (is_read && !test_bit(BLOCK_BIT_ERROR, &bp->bits)) + if (!op_is_write(opf) && !test_bit(BLOCK_BIT_ERROR, &bp->bits)) set_bit(BLOCK_BIT_UPTODATE, &bp->bits); clear_bit(BLOCK_BIT_IO_BUSY, &bp->bits); @@ -464,13 +463,13 @@ static void block_end_io(struct super_block *sb, int rw, wake_up(&binf->waitq); } -static void block_bio_end_io(struct bio *bio, int err) +static void KC_DECLARE_BIO_END_IO(block_bio_end_io, struct bio *bio) { struct block_private *bp = bio->bi_private; struct super_block *sb = bp->sb; TRACE_BLOCK(end_io, bp); - block_end_io(sb, bio->bi_rw, bp, err); + block_end_io(sb, kc_bio_get_opf(bio), bp, kc_bio_get_errno(bio)); bio_put(bio); } @@ -478,7 +477,7 @@ static void block_bio_end_io(struct bio *bio, int err) * Kick off IO for a single block. */ static int block_submit_bio(struct super_block *sb, struct block_private *bp, - int rw) + unsigned int opf) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); struct bio *bio = NULL; @@ -511,8 +510,9 @@ static int block_submit_bio(struct super_block *sb, struct block_private *bp, break; } - bio->bi_sector = sector + (off >> 9); - bio->bi_bdev = sbi->meta_bdev; + kc_bio_set_opf(bio, opf); + kc_bio_set_sector(bio, sector + (off >> 9)); + bio_set_dev(bio, sbi->meta_bdev); bio->bi_end_io = block_bio_end_io; bio->bi_private = bp; @@ -529,18 +529,18 @@ static int block_submit_bio(struct super_block *sb, struct block_private *bp, BUG(); if (!bio_add_page(bio, page, PAGE_SIZE, 0)) { - submit_bio(rw, bio); + kc_submit_bio(bio); bio = NULL; } } if (bio) - submit_bio(rw, bio); + kc_submit_bio(bio); blk_finish_plug(&plug); /* let racing end_io know we're done */ - block_end_io(sb, rw, bp, ret); + block_end_io(sb, opf, bp, ret); return ret; } @@ -641,7 +641,7 @@ static struct block_private *block_read(struct super_block *sb, u64 blkno) if (!test_bit(BLOCK_BIT_UPTODATE, &bp->bits) && test_and_clear_bit(BLOCK_BIT_NEW, &bp->bits)) { - ret = block_submit_bio(sb, bp, READ); + ret = block_submit_bio(sb, bp, REQ_OP_READ); if (ret < 0) goto out; } @@ -970,7 +970,7 @@ int scoutfs_block_writer_write(struct super_block *sb, /* retry previous write errors */ clear_bit(BLOCK_BIT_ERROR, &bp->bits); - ret = block_submit_bio(sb, bp, WRITE); + ret = block_submit_bio(sb, bp, REQ_OP_WRITE); if (ret < 0) break; } @@ -1173,11 +1173,11 @@ struct sm_block_completion { int err; }; -static void sm_block_bio_end_io(struct bio *bio, int err) +static void KC_DECLARE_BIO_END_IO(sm_block_bio_end_io, struct bio *bio) { struct sm_block_completion *sbc = bio->bi_private; - sbc->err = err; + sbc->err = kc_bio_get_errno(bio); complete(&sbc->comp); bio_put(bio); } @@ -1192,9 +1192,8 @@ static void sm_block_bio_end_io(struct bio *bio, int err) * only layer that sees the full block buffer so we pass the calculated * crc to the caller for them to check in their context. */ -static int sm_block_io(struct super_block *sb, struct block_device *bdev, int rw, u64 blkno, - struct scoutfs_block_header *hdr, size_t len, - __le32 *blk_crc) +static int sm_block_io(struct super_block *sb, struct block_device *bdev, unsigned int opf, + u64 blkno, struct scoutfs_block_header *hdr, size_t len, __le32 *blk_crc) { struct scoutfs_block_header *pg_hdr; struct sm_block_completion sbc; @@ -1208,7 +1207,7 @@ static int sm_block_io(struct super_block *sb, struct block_device *bdev, int rw return -EIO; if (WARN_ON_ONCE(len > SCOUTFS_BLOCK_SM_SIZE) || - WARN_ON_ONCE(!(rw & WRITE) && !blk_crc)) + WARN_ON_ONCE(!op_is_write(opf) && !blk_crc)) return -EINVAL; page = alloc_page(GFP_NOFS); @@ -1217,7 +1216,7 @@ static int sm_block_io(struct super_block *sb, struct block_device *bdev, int rw pg_hdr = page_address(page); - if (rw & WRITE) { + if (op_is_write(opf)) { memcpy(pg_hdr, hdr, len); if (len < SCOUTFS_BLOCK_SM_SIZE) memset((char *)pg_hdr + len, 0, @@ -1231,8 +1230,9 @@ static int sm_block_io(struct super_block *sb, struct block_device *bdev, int rw goto out; } - bio->bi_sector = blkno << (SCOUTFS_BLOCK_SM_SHIFT - 9); - bio->bi_bdev = bdev; + kc_bio_set_opf(bio, opf | REQ_SYNC); + kc_bio_set_sector(bio, blkno << (SCOUTFS_BLOCK_SM_SHIFT - 9)); + bio_set_dev(bio, bdev); bio->bi_end_io = sm_block_bio_end_io; bio->bi_private = &sbc; bio_add_page(bio, page, SCOUTFS_BLOCK_SM_SIZE, 0); @@ -1240,12 +1240,12 @@ static int sm_block_io(struct super_block *sb, struct block_device *bdev, int rw init_completion(&sbc.comp); sbc.err = 0; - submit_bio((rw & WRITE) ? WRITE_SYNC : READ_SYNC, bio); + kc_submit_bio(bio); wait_for_completion(&sbc.comp); ret = sbc.err; - if (ret == 0 && !(rw & WRITE)) { + if (ret == 0 && !op_is_write(opf)) { memcpy(hdr, pg_hdr, len); *blk_crc = block_calc_crc(pg_hdr, SCOUTFS_BLOCK_SM_SIZE); } @@ -1259,14 +1259,14 @@ int scoutfs_block_read_sm(struct super_block *sb, struct scoutfs_block_header *hdr, size_t len, __le32 *blk_crc) { - return sm_block_io(sb, bdev, READ, blkno, hdr, len, blk_crc); + return sm_block_io(sb, bdev, REQ_OP_READ, blkno, hdr, len, blk_crc); } int scoutfs_block_write_sm(struct super_block *sb, struct block_device *bdev, u64 blkno, struct scoutfs_block_header *hdr, size_t len) { - return sm_block_io(sb, bdev, WRITE, blkno, hdr, len, NULL); + return sm_block_io(sb, bdev, REQ_OP_WRITE, blkno, hdr, len, NULL); } int scoutfs_block_setup(struct super_block *sb) diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 4923730e..93d1669d 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -122,4 +122,49 @@ static inline int dir_emit_dots(struct file *file, void *dirent, #define memalloc_nofs_restore memalloc_noio_restore #endif +#ifdef KC_BIO_BI_OPF +#define kc_bio_get_opf(bio) \ +({ \ + (bio)->bi_opf; \ +}) +#define kc_bio_set_opf(bio, opf) \ +do { \ + (bio)->bi_opf = opf; \ +} while (0) +#define kc_bio_set_sector(bio, sect) \ +do { \ + (bio)->bi_iter.bi_sector = sect;\ +} while (0) +#define kc_submit_bio(bio) submit_bio(bio) +#else +#define kc_bio_get_opf(bio) \ +({ \ + (bio)->bi_rw; \ +}) +#define kc_bio_set_opf(bio, opf) \ +do { \ + (bio)->bi_rw = opf; \ +} while (0) +#define kc_bio_set_sector(bio, sect) \ +do { \ + (bio)->bi_sector = sect; \ +} while (0) +#define kc_submit_bio(bio) \ +do { \ + submit_bio((bio)->bi_rw, bio); \ +} while (0) +#define bio_set_dev(bio, bdev) \ +do { \ + (bio)->bi_bdev = (bdev); \ +} while (0) +#endif + +#ifdef KC_BIO_BI_STATUS +#define KC_DECLARE_BIO_END_IO(name, bio) name(bio) +#define kc_bio_get_errno(bio) ({ blk_status_to_errno((bio)->bi_status); }) +#else +#define KC_DECLARE_BIO_END_IO(name, bio) name(bio, int _error_arg) +#define kc_bio_get_errno(bio) ({ (int)((void)(bio), _error_arg); }) +#endif + #endif From 1d150da3f0243ce4fe38da9ef88dd0128d07aec0 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 30 May 2023 14:10:14 -0400 Subject: [PATCH 21/46] Use page->lru instead of page->list With v3.14-rc1-10-g34bf6ef94a83, page->list is removed Instead, use the union member ->lru. Signed-off-by: Auke Kok --- kmod/src/item.c | 8 ++++---- kmod/src/srch.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kmod/src/item.c b/kmod/src/item.c index 8c7900d5..948fcd70 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -2277,7 +2277,7 @@ int scoutfs_item_write_dirty(struct super_block *sb) ret = -ENOMEM; goto out; } - list_add(&page->list, &pages); + list_add(&page->lru, &pages); first = NULL; prev = &first; @@ -2290,7 +2290,7 @@ int scoutfs_item_write_dirty(struct super_block *sb) ret = -ENOMEM; goto out; } - list_add(&second->list, &pages); + list_add(&second->lru, &pages); } /* read lock next sorted page, we're only dirty_list user */ @@ -2347,8 +2347,8 @@ int scoutfs_item_write_dirty(struct super_block *sb) /* write all the dirty items into log btree blocks */ ret = scoutfs_forest_insert_list(sb, first); out: - list_for_each_entry_safe(page, second, &pages, list) { - list_del_init(&page->list); + list_for_each_entry_safe(page, second, &pages, lru) { + list_del_init(&page->lru); __free_page(page); } diff --git a/kmod/src/srch.c b/kmod/src/srch.c index ebf113e6..36385ad9 100644 --- a/kmod/src/srch.c +++ b/kmod/src/srch.c @@ -1747,7 +1747,7 @@ static int compact_logs(struct super_block *sb, goto out; } page->private = 0; - list_add_tail(&page->list, &pages); + list_add_tail(&page->lru, &pages); nr_pages++; scoutfs_inc_counter(sb, srch_compact_log_page); } @@ -1800,7 +1800,7 @@ static int compact_logs(struct super_block *sb, /* sort page entries and reset private for _next */ i = 0; - list_for_each_entry(page, &pages, list) { + list_for_each_entry(page, &pages, lru) { args[i++] = page; if (atomic_read(&srinf->shutdown)) { @@ -1821,7 +1821,7 @@ static int compact_logs(struct super_block *sb, goto out; /* make sure we finished all the pages */ - list_for_each_entry(page, &pages, list) { + list_for_each_entry(page, &pages, lru) { sre = page_priv_sre(page); if (page->private < SRES_PER_PAGE && sre->ino != 0) { ret = -ENOSPC; @@ -1834,8 +1834,8 @@ static int compact_logs(struct super_block *sb, out: scoutfs_block_put(sb, bl); vfree(args); - list_for_each_entry_safe(page, tmp, &pages, list) { - list_del(&page->list); + list_for_each_entry_safe(page, tmp, &pages, lru) { + list_del(&page->lru); __free_page(page); } From cca4fcb78891b29b415de9c39fcd0a2f942732df Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 2 Aug 2022 15:29:48 -0700 Subject: [PATCH 22/46] Use count/scan objects shrinking interface Move to the more recent interfaces for counting and scanning cached objects to shrink. Signed-off-by: Zach Brown Signed-off-by: Auke Kok --- kmod/src/Makefile | 1 + kmod/src/Makefile.kernelcompat | 9 +++++++ kmod/src/block.c | 45 ++++++++++++++++++--------------- kmod/src/counters.h | 6 +++++ kmod/src/item.c | 42 +++++++++++++++++++------------ kmod/src/kernelcompat.c | 30 ++++++++++++++++++++++ kmod/src/kernelcompat.h | 44 ++++++++++++++++++++++++++++++++ kmod/src/lock.c | 46 ++++++++++++++++++++-------------- kmod/src/util.h | 11 ++++++++ 9 files changed, 179 insertions(+), 55 deletions(-) create mode 100644 kmod/src/kernelcompat.c diff --git a/kmod/src/Makefile b/kmod/src/Makefile index d96c4967..2666e6df 100644 --- a/kmod/src/Makefile +++ b/kmod/src/Makefile @@ -25,6 +25,7 @@ scoutfs-y += \ inode.o \ ioctl.o \ item.o \ + kernelcompat.o \ lock.o \ lock_server.o \ msg.o \ diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 99615f18..409bdc27 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -130,3 +130,12 @@ endif ifneq (,$(shell grep 'bi_status' include/linux/blk_types.h)) ccflags-y += -DKC_BIO_BI_STATUS endif + +# +# v3.11-8765-ga0b02131c5fc +# +# Remove the old ->shrink() API, ->{scan,count}_objects is preferred. +# +ifneq (,$(shell grep '(*shrink)' include/linux/shrinker.h)) +ccflags-y += -DKC_SHRINKER_SHRINK +endif diff --git a/kmod/src/block.c b/kmod/src/block.c index 7016a4b4..c23764d3 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -31,6 +31,7 @@ #include "scoutfs_trace.h" #include "alloc.h" #include "triggers.h" +#include "util.h" /* * The scoutfs block cache manages metadata blocks that can be larger @@ -58,7 +59,7 @@ struct block_info { atomic64_t access_counter; struct rhashtable ht; wait_queue_head_t waitq; - struct shrinker shrinker; + KC_DEFINE_SHRINKER(shrinker); struct work_struct free_work; struct llist_head free_llist; }; @@ -1070,6 +1071,16 @@ u64 scoutfs_block_writer_dirty_bytes(struct super_block *sb, return wri->nr_dirty_blocks * SCOUTFS_BLOCK_LG_SIZE; } +static unsigned long block_count_objects(struct shrinker *shrink, struct shrink_control *sc) +{ + struct block_info *binf = KC_SHRINKER_CONTAINER_OF(shrink, struct block_info); + struct super_block *sb = binf->sb; + + scoutfs_inc_counter(sb, block_cache_count_objects); + + return shrinker_min_long(atomic_read(&binf->total_inserted)); +} + /* * Remove a number of cached blocks that haven't been used recently. * @@ -1090,24 +1101,18 @@ u64 scoutfs_block_writer_dirty_bytes(struct super_block *sb, * atomically remove blocks when the only references are ours and the * hash table. */ -static int block_shrink(struct shrinker *shrink, struct shrink_control *sc) +static unsigned long block_scan_objects(struct shrinker *shrink, struct shrink_control *sc) { - struct block_info *binf = container_of(shrink, struct block_info, - shrinker); + struct block_info *binf = KC_SHRINKER_CONTAINER_OF(shrink, struct block_info); struct super_block *sb = binf->sb; struct rhashtable_iter iter; struct block_private *bp; bool stop = false; - unsigned long nr; + unsigned long freed = 0; + unsigned long nr = sc->nr_to_scan; u64 recently; - nr = sc->nr_to_scan; - if (nr == 0) - goto out; - - scoutfs_inc_counter(sb, block_cache_shrink); - - nr = DIV_ROUND_UP(nr, SCOUTFS_BLOCK_LG_PAGES_PER); + scoutfs_inc_counter(sb, block_cache_scan_objects); recently = accessed_recently(binf); rhashtable_walk_enter(&binf->ht, &iter); @@ -1152,6 +1157,7 @@ static int block_shrink(struct shrinker *shrink, struct shrink_control *sc) if (block_remove_solo(sb, bp)) { scoutfs_inc_counter(sb, block_cache_shrink_remove); TRACE_BLOCK(shrink, bp); + freed++; nr--; } block_put(sb, bp); @@ -1160,12 +1166,11 @@ static int block_shrink(struct shrinker *shrink, struct shrink_control *sc) rhashtable_walk_stop(&iter); rhashtable_walk_exit(&iter); -out: + if (stop) - return -1; + return SHRINK_STOP; else - return min_t(u64, INT_MAX, - (u64)atomic_read(&binf->total_inserted) * SCOUTFS_BLOCK_LG_PAGES_PER); + return freed; } struct sm_block_completion { @@ -1291,9 +1296,9 @@ int scoutfs_block_setup(struct super_block *sb) atomic_set(&binf->total_inserted, 0); atomic64_set(&binf->access_counter, 0); init_waitqueue_head(&binf->waitq); - binf->shrinker.shrink = block_shrink; - binf->shrinker.seeks = DEFAULT_SEEKS; - register_shrinker(&binf->shrinker); + KC_INIT_SHRINKER_FUNCS(&binf->shrinker, block_count_objects, + block_scan_objects); + KC_REGISTER_SHRINKER(&binf->shrinker); INIT_WORK(&binf->free_work, block_free_work); init_llist_head(&binf->free_llist); @@ -1313,7 +1318,7 @@ void scoutfs_block_destroy(struct super_block *sb) struct block_info *binf = SCOUTFS_SB(sb)->block_info; if (binf) { - unregister_shrinker(&binf->shrinker); + KC_UNREGISTER_SHRINKER(&binf->shrinker); block_remove_all(sb); flush_work(&binf->free_work); rhashtable_destroy(&binf->ht); diff --git a/kmod/src/counters.h b/kmod/src/counters.h index ccfa1f6f..dd291816 100644 --- a/kmod/src/counters.h +++ b/kmod/src/counters.h @@ -30,6 +30,8 @@ EXPAND_COUNTER(block_cache_free) \ EXPAND_COUNTER(block_cache_free_work) \ EXPAND_COUNTER(block_cache_remove_stale) \ + EXPAND_COUNTER(block_cache_count_objects) \ + EXPAND_COUNTER(block_cache_scan_objects) \ EXPAND_COUNTER(block_cache_shrink) \ EXPAND_COUNTER(block_cache_shrink_next) \ EXPAND_COUNTER(block_cache_shrink_recent) \ @@ -88,6 +90,8 @@ EXPAND_COUNTER(forest_read_items) \ EXPAND_COUNTER(forest_roots_next_hint) \ EXPAND_COUNTER(forest_set_bloom_bits) \ + EXPAND_COUNTER(item_cache_count_objects) \ + EXPAND_COUNTER(item_cache_scan_objects) \ EXPAND_COUNTER(item_clear_dirty) \ EXPAND_COUNTER(item_create) \ EXPAND_COUNTER(item_delete) \ @@ -121,6 +125,7 @@ EXPAND_COUNTER(item_update) \ EXPAND_COUNTER(item_write_dirty) \ EXPAND_COUNTER(lock_alloc) \ + EXPAND_COUNTER(lock_count_objects) \ EXPAND_COUNTER(lock_free) \ EXPAND_COUNTER(lock_grant_request) \ EXPAND_COUNTER(lock_grant_response) \ @@ -134,6 +139,7 @@ EXPAND_COUNTER(lock_lock_error) \ EXPAND_COUNTER(lock_nonblock_eagain) \ EXPAND_COUNTER(lock_recover_request) \ + EXPAND_COUNTER(lock_scan_objects) \ EXPAND_COUNTER(lock_shrink_attempted) \ EXPAND_COUNTER(lock_shrink_aborted) \ EXPAND_COUNTER(lock_shrink_work) \ diff --git a/kmod/src/item.c b/kmod/src/item.c index 948fcd70..6d7bd376 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -27,6 +27,7 @@ #include "trans.h" #include "counters.h" #include "scoutfs_trace.h" +#include "util.h" /* * The item cache maintains a consistent view of items that are read @@ -76,7 +77,7 @@ struct item_cache_info { /* almost always read, barely written */ struct super_block *sb; struct item_percpu_pages __percpu *pcpu_pages; - struct shrinker shrinker; + KC_DEFINE_SHRINKER(shrinker); struct notifier_block notifier; /* often walked, but per-cpu refs are fast path */ @@ -2530,27 +2531,35 @@ retry: put_pg(sb, right); } +static unsigned long item_cache_count_objects(struct shrinker *shrink, + struct shrink_control *sc) +{ + struct item_cache_info *cinf = KC_SHRINKER_CONTAINER_OF(shrink, struct item_cache_info); + struct super_block *sb = cinf->sb; + + scoutfs_inc_counter(sb, item_cache_count_objects); + + return shrinker_min_long(cinf->lru_pages); +} + /* * Shrink the size the item cache. We're operating against the fast * path lock ordering and we skip pages if we can't acquire locks. We * can run into dirty pages or pages with items that weren't visible to * the earliest active reader which must be skipped. */ -static int item_lru_shrink(struct shrinker *shrink, - struct shrink_control *sc) +static unsigned long item_cache_scan_objects(struct shrinker *shrink, + struct shrink_control *sc) { - struct item_cache_info *cinf = container_of(shrink, - struct item_cache_info, - shrinker); + struct item_cache_info *cinf = KC_SHRINKER_CONTAINER_OF(shrink, struct item_cache_info); struct super_block *sb = cinf->sb; struct cached_page *tmp; struct cached_page *pg; + unsigned long freed = 0; u64 first_reader_seq; - int nr; + int nr = sc->nr_to_scan; - if (sc->nr_to_scan == 0) - goto out; - nr = sc->nr_to_scan; + scoutfs_inc_counter(sb, item_cache_scan_objects); /* can't invalidate pages with items that weren't visible to first reader */ first_reader_seq = first_active_reader_seq(cinf); @@ -2582,6 +2591,7 @@ static int item_lru_shrink(struct shrinker *shrink, rbtree_erase(&pg->node, &cinf->pg_root); invalidate_pcpu_page(pg); write_unlock(&pg->rwlock); + freed++; put_pg(sb, pg); @@ -2591,8 +2601,8 @@ static int item_lru_shrink(struct shrinker *shrink, write_unlock(&cinf->rwlock); spin_unlock(&cinf->lru_lock); -out: - return min_t(unsigned long, cinf->lru_pages, INT_MAX); + + return freed; } static int item_cpu_callback(struct notifier_block *nfb, @@ -2638,9 +2648,9 @@ int scoutfs_item_setup(struct super_block *sb) for_each_possible_cpu(cpu) init_pcpu_pages(cinf, cpu); - cinf->shrinker.shrink = item_lru_shrink; - cinf->shrinker.seeks = DEFAULT_SEEKS; - register_shrinker(&cinf->shrinker); + KC_INIT_SHRINKER_FUNCS(&cinf->shrinker, item_cache_count_objects, + item_cache_scan_objects); + KC_REGISTER_SHRINKER(&cinf->shrinker); cinf->notifier.notifier_call = item_cpu_callback; register_hotcpu_notifier(&cinf->notifier); @@ -2663,7 +2673,7 @@ void scoutfs_item_destroy(struct super_block *sb) BUG_ON(!list_empty(&cinf->active_list)); unregister_hotcpu_notifier(&cinf->notifier); - unregister_shrinker(&cinf->shrinker); + KC_UNREGISTER_SHRINKER(&cinf->shrinker); for_each_possible_cpu(cpu) drop_pcpu_pages(sb, cinf, cpu); diff --git a/kmod/src/kernelcompat.c b/kmod/src/kernelcompat.c new file mode 100644 index 00000000..bb11a803 --- /dev/null +++ b/kmod/src/kernelcompat.c @@ -0,0 +1,30 @@ + +#include "kernelcompat.h" + +#ifdef KC_SHRINKER_SHRINK +#include +/* + * If a target doesn't have that .{count,scan}_objects() interface then + * we have a .shrink() helper that performs the shrink work in terms of + * count/scan. + */ +int kc_shrink_wrapper_fn(struct shrinker *shrink, struct shrink_control *sc) +{ + struct kc_shrinker_wrapper *wrapper = container_of(shrink, struct kc_shrinker_wrapper, shrink); + unsigned long nr; + unsigned long rc; + + if (sc->nr_to_scan != 0) { + rc = wrapper->scan_objects(shrink, sc); + /* translate magic values to the equivalent for older kernels */ + if (rc == SHRINK_STOP) + return -1; + else if (rc == SHRINK_EMPTY) + return 0; + } + + nr = wrapper->count_objects(shrink, sc); + + return min_t(unsigned long, nr, INT_MAX); +} +#endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 93d1669d..b24d5241 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -167,4 +167,48 @@ do { \ #define kc_bio_get_errno(bio) ({ (int)((void)(bio), _error_arg); }) #endif +#ifndef KC_SHRINKER_SHRINK + +#define KC_DEFINE_SHRINKER(name) struct shrinker name +#define KC_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \ + __typeof__(name) _shrink = (name); \ + _shrink->count_objects = (countfn); \ + _shrink->scan_objects = (scanfn); \ + _shrink->seeks = DEFAULT_SEEKS; \ +} while (0) + +#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(ptr, type, shrinker) +#define KC_REGISTER_SHRINKER(ptr) (register_shrinker(ptr)) +#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr)) +#define KC_SHRINKER_FN(ptr) (ptr) +#else + +#include +#ifndef SHRINK_STOP +#define SHRINK_STOP (~0UL) +#define SHRINK_EMPTY (~0UL - 1) +#endif + +int kc_shrink_wrapper_fn(struct shrinker *shrink, struct shrink_control *sc); +struct kc_shrinker_wrapper { + unsigned long (*count_objects)(struct shrinker *, struct shrink_control *sc); + unsigned long (*scan_objects)(struct shrinker *, struct shrink_control *sc); + struct shrinker shrink; +}; + +#define KC_DEFINE_SHRINKER(name) struct kc_shrinker_wrapper name; +#define KC_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \ + struct kc_shrinker_wrapper *_wrap = (name); \ + _wrap->count_objects = (countfn); \ + _wrap->scan_objects = (scanfn); \ + _wrap->shrink.shrink = kc_shrink_wrapper_fn; \ + _wrap->shrink.seeks = DEFAULT_SEEKS; \ +} while (0) +#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(container_of(ptr, struct kc_shrinker_wrapper, shrink), type, shrinker) +#define KC_REGISTER_SHRINKER(ptr) (register_shrinker(ptr.shrink)) +#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr.shrink)) +#define KC_SHRINKER_FN(ptr) (ptr.shrink) + +#endif /* KC_SHRINKER_SHRINK */ + #endif diff --git a/kmod/src/lock.c b/kmod/src/lock.c index 2ed75b9f..db4c384f 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -35,6 +35,7 @@ #include "xattr.h" #include "item.h" #include "omap.h" +#include "util.h" /* * scoutfs uses a lock service to manage item cache consistency between @@ -76,7 +77,7 @@ struct lock_info { bool unmounting; struct rb_root lock_tree; struct rb_root lock_range_tree; - struct shrinker shrinker; + KC_DEFINE_SHRINKER(shrinker); struct list_head lru_list; unsigned long long lru_nr; struct workqueue_struct *workq; @@ -1400,6 +1401,17 @@ static void lock_shrink_worker(struct work_struct *work) } } +static unsigned long lock_count_objects(struct shrinker *shrink, + struct shrink_control *sc) +{ + struct lock_info *linfo = KC_SHRINKER_CONTAINER_OF(shrink, struct lock_info); + struct super_block *sb = linfo->sb; + + scoutfs_inc_counter(sb, lock_count_objects); + + return shrinker_min_long(linfo->lru_nr); +} + /* * Start the shrinking process for locks on the lru. If a lock is on * the lru then it can't have any active users. We don't want to block @@ -1412,21 +1424,18 @@ static void lock_shrink_worker(struct work_struct *work) * mode which will prevent the lock from being freed when the null * response arrives. */ -static int scoutfs_lock_shrink(struct shrinker *shrink, - struct shrink_control *sc) +static unsigned long lock_scan_objects(struct shrinker *shrink, + struct shrink_control *sc) { - struct lock_info *linfo = container_of(shrink, struct lock_info, - shrinker); + struct lock_info *linfo = KC_SHRINKER_CONTAINER_OF(shrink, struct lock_info); struct super_block *sb = linfo->sb; struct scoutfs_lock *lock; struct scoutfs_lock *tmp; - unsigned long nr; + unsigned long freed = 0; + unsigned long nr = sc->nr_to_scan; bool added = false; - int ret; - nr = sc->nr_to_scan; - if (nr == 0) - goto out; + scoutfs_inc_counter(sb, lock_scan_objects); spin_lock(&linfo->lock); @@ -1444,6 +1453,7 @@ restart: lock->request_pending = 1; list_add_tail(&lock->shrink_head, &linfo->shrink_list); added = true; + freed++; scoutfs_inc_counter(sb, lock_shrink_attempted); trace_scoutfs_lock_shrink(sb, lock); @@ -1458,10 +1468,8 @@ restart: if (added) queue_work(linfo->workq, &linfo->shrink_work); -out: - ret = min_t(unsigned long, linfo->lru_nr, INT_MAX); - trace_scoutfs_lock_shrink_exit(sb, sc->nr_to_scan, ret); - return ret; + trace_scoutfs_lock_shrink_exit(sb, sc->nr_to_scan, freed); + return freed; } void scoutfs_free_unused_locks(struct super_block *sb) @@ -1472,7 +1480,7 @@ void scoutfs_free_unused_locks(struct super_block *sb) .nr_to_scan = INT_MAX, }; - linfo->shrinker.shrink(&linfo->shrinker, &sc); + lock_scan_objects(KC_SHRINKER_FN(&linfo->shrinker), &sc); } static void lock_tseq_show(struct seq_file *m, struct scoutfs_tseq_entry *ent) @@ -1579,7 +1587,7 @@ void scoutfs_lock_shutdown(struct super_block *sb) trace_scoutfs_lock_shutdown(sb, linfo); /* stop the shrinker from queueing work */ - unregister_shrinker(&linfo->shrinker); + KC_UNREGISTER_SHRINKER(&linfo->shrinker); flush_work(&linfo->shrink_work); /* cause current and future lock calls to return errors */ @@ -1698,9 +1706,9 @@ int scoutfs_lock_setup(struct super_block *sb) spin_lock_init(&linfo->lock); linfo->lock_tree = RB_ROOT; linfo->lock_range_tree = RB_ROOT; - linfo->shrinker.shrink = scoutfs_lock_shrink; - linfo->shrinker.seeks = DEFAULT_SEEKS; - register_shrinker(&linfo->shrinker); + KC_INIT_SHRINKER_FUNCS(&linfo->shrinker, lock_count_objects, + lock_scan_objects); + KC_REGISTER_SHRINKER(&linfo->shrinker); INIT_LIST_HEAD(&linfo->lru_list); INIT_WORK(&linfo->inv_work, lock_invalidate_worker); INIT_LIST_HEAD(&linfo->inv_list); diff --git a/kmod/src/util.h b/kmod/src/util.h index 20d9db79..7ca9d3eb 100644 --- a/kmod/src/util.h +++ b/kmod/src/util.h @@ -17,4 +17,15 @@ static inline void down_write_two(struct rw_semaphore *a, down_write_nested(b, SINGLE_DEPTH_NESTING); } +/* + * When returning shrinker counts from scan_objects, we should steer + * clear of the magic SHRINK_STOP and SHRINK_EMPTY values, which are near + * ~0UL values. Hence, we cap count to ~0L, which is arbitarily high + * enough to avoid it. + */ +static inline long shrinker_min_long(long count) +{ + return min(count, LONG_MAX); +} + #endif From 50f5077863e7fe6d3e770ba5d1cd26e5a188c15c Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 9 May 2023 16:13:52 -0400 Subject: [PATCH 23/46] Do not use MS_* flags anymore in kernel space. MS_* flags from should not be used in the kernel anymore from 4.x onwards. Instead, we need to use the SB_* versions Signed-off-by: Auke Kok --- kmod/src/kernelcompat.h | 11 +++++++++++ kmod/src/options.c | 6 +++--- kmod/src/super.c | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index b24d5241..2df4ddfe 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -167,6 +167,17 @@ do { \ #define kc_bio_get_errno(bio) ({ (int)((void)(bio), _error_arg); }) #endif +/* + * v4.13-rc1-6-ge462ec50cb5f + * + * MS_* (mount) flags from should not be used in the kernel + * anymore from 4.x onwards. Instead, we need to use the SB_* (superblock) flags + */ +#ifndef SB_POSIXACL +#define SB_POSIXACL MS_POSIXACL +#define SB_I_VERSION MS_I_VERSION +#endif + #ifndef KC_SHRINKER_SHRINK #define KC_DEFINE_SHRINKER(name) struct shrinker name diff --git a/kmod/src/options.c b/kmod/src/options.c index 2a19a9e5..b7a1148b 100644 --- a/kmod/src/options.c +++ b/kmod/src/options.c @@ -169,7 +169,7 @@ static int parse_options(struct super_block *sb, char *options, struct scoutfs_m switch (token) { case Opt_acl: - sb->s_flags |= MS_POSIXACL; + sb->s_flags |= SB_POSIXACL; break; case Opt_data_prealloc_blocks: @@ -203,7 +203,7 @@ static int parse_options(struct super_block *sb, char *options, struct scoutfs_m break; case Opt_noacl: - sb->s_flags &= ~MS_POSIXACL; + sb->s_flags &= ~SB_POSIXACL; break; case Opt_orphan_scan_delay_ms: @@ -327,7 +327,7 @@ int scoutfs_options_show(struct seq_file *seq, struct dentry *root) { struct super_block *sb = root->d_sb; struct scoutfs_mount_options opts; - const bool is_acl = !!(sb->s_flags & MS_POSIXACL); + const bool is_acl = !!(sb->s_flags & SB_POSIXACL); scoutfs_options_read(sb, &opts); diff --git a/kmod/src/super.c b/kmod/src/super.c index bcbf9ebd..434aace6 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -179,7 +179,7 @@ static void scoutfs_put_super(struct super_block *sb) /* * Wait for invalidation and iput to finish with any lingering * inode references that escaped the evict_inodes in - * generic_shutdown_super. MS_ACTIVE is clear so final iput + * generic_shutdown_super. SB_ACTIVE is clear so final iput * will always evict. */ scoutfs_lock_flush_invalidate(sb); @@ -486,7 +486,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &scoutfs_dentry_ops; sb->s_export_op = &scoutfs_export_ops; sb->s_xattr = scoutfs_xattr_handlers; - sb->s_flags |= MS_I_VERSION | MS_POSIXACL; + sb->s_flags |= SB_I_VERSION | SB_POSIXACL; sb->s_time_gran = 1; /* btree blocks use long lived bh->b_data refs */ From 09ae10025452b3f1f0b88369b481142ad998ab28 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 13:55:07 -0400 Subject: [PATCH 24/46] Remove the use of backing_dev_info pt from address_space. Instead, use the new inline inode_to_bdi from to fill in the task's backing_dev_info. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/ioctl.c | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 409bdc27..b781eea4 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -139,3 +139,13 @@ endif ifneq (,$(shell grep '(*shrink)' include/linux/shrinker.h)) ccflags-y += -DKC_SHRINKER_SHRINK endif + +# +# v3.19-4777-g6bec00352861 +# +# backing_dev_info is removed from address_space. Instead we need to use +# inode_to_bdi() inline from . +# +ifneq (,$(shell grep 'struct backing_dev_info.*backing_dev_info' include/linux/fs.h)) +ccflags-y += -DKC_LINUX_BACKING_DEV_INFO=1 +endif diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index 964db6f4..fb8c8c46 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "format.h" #include "key.h" @@ -448,7 +449,6 @@ static long scoutfs_ioc_stage(struct file *file, unsigned long arg) { struct inode *inode = file_inode(file); struct super_block *sb = inode->i_sb; - struct address_space *mapping = inode->i_mapping; struct scoutfs_inode_info *si = SCOUTFS_I(inode); SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); struct scoutfs_ioctl_stage args; @@ -516,7 +516,7 @@ static long scoutfs_ioc_stage(struct file *file, unsigned long arg) } si->staging = true; - current->backing_dev_info = mapping->backing_dev_info; + current->backing_dev_info = inode_to_bdi(inode); pos = args.offset; written = 0; From d6c143a639ba7ebb769563e53557fa644f72a922 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 14:29:43 -0400 Subject: [PATCH 25/46] xattr functions are now passed flags through struct xattr_handler Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/acl.c | 17 ++++++++++++++++- kmod/src/acl.h | 9 +++++++++ kmod/src/xattr.c | 34 +++++++++++++++++++++++++++------- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index b781eea4..97840bf5 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -149,3 +149,12 @@ endif ifneq (,$(shell grep 'struct backing_dev_info.*backing_dev_info' include/linux/fs.h)) ccflags-y += -DKC_LINUX_BACKING_DEV_INFO=1 endif + +# +# v4.3-9290-ge409de992e3e +# +# xattr handlers are now passed a struct that contains `flags` +# +ifneq (,$(shell grep 'int...get..const struct xattr_handler.*struct dentry.*dentry,' include/linux/xattr.h)) +ccflags-y += -DKC_XATTR_STRUCT_XATTR_HANDLER=1 +endif diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 6b43d8cc..93188f9d 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -218,10 +218,17 @@ int scoutfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); return ret; } - +#ifdef KC_XATTR_STRUCT_XATTR_HANDLER +int scoutfs_acl_get_xattr(const struct xattr_handler *handler, struct dentry *dentry, + struct inode *inode, const char *name, void *value, + size_t size) +{ + int type = handler->flags; +#else int scoutfs_acl_get_xattr(struct dentry *dentry, const char *name, void *value, size_t size, int type) { +#endif struct posix_acl *acl; int ret = 0; @@ -240,9 +247,17 @@ int scoutfs_acl_get_xattr(struct dentry *dentry, const char *name, void *value, return ret; } +#ifdef KC_XATTR_STRUCT_XATTR_HANDLER +int scoutfs_acl_set_xattr(const struct xattr_handler *handler, struct dentry *dentry, + struct inode *inode, const char *name, const void *value, + size_t size, int flags) +{ + int type = handler->flags; +#else int scoutfs_acl_set_xattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { +#endif struct posix_acl *acl = NULL; int ret; diff --git a/kmod/src/acl.h b/kmod/src/acl.h index a9235eb5..1712b7e8 100644 --- a/kmod/src/acl.h +++ b/kmod/src/acl.h @@ -6,10 +6,19 @@ struct posix_acl *scoutfs_get_acl_locked(struct inode *inode, int type, struct s int scoutfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int scoutfs_set_acl_locked(struct inode *inode, struct posix_acl *acl, int type, struct scoutfs_lock *lock, struct list_head *ind_locks); +#ifdef KC_XATTR_STRUCT_XATTR_HANDLER +int scoutfs_acl_get_xattr(const struct xattr_handler *, struct dentry *dentry, + struct inode *inode, const char *name, void *value, + size_t size); +int scoutfs_acl_set_xattr(const struct xattr_handler *, struct dentry *dentry, + struct inode *inode, const char *name, const void *value, + size_t size, int flags); +#else int scoutfs_acl_get_xattr(struct dentry *dentry, const char *name, void *value, size_t size, int type); int scoutfs_acl_set_xattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type); +#endif int scoutfs_acl_chmod_locked(struct inode *inode, struct iattr *attr, struct scoutfs_lock *lock, struct list_head *ind_locks); int scoutfs_init_acl_locked(struct inode *inode, struct inode *dir, diff --git a/kmod/src/xattr.c b/kmod/src/xattr.c index abdf8e0b..75fc35b4 100644 --- a/kmod/src/xattr.c +++ b/kmod/src/xattr.c @@ -850,6 +850,7 @@ unlock: return ret; } +#ifndef KC_XATTR_STRUCT_XATTR_HANDLER /* * Future kernels have this amazing hack to rewind the name to get the * skipped prefix. We're back in the stone ages without the handler @@ -857,22 +858,41 @@ unlock: * compat hook to either call the kernel's xattr_full_name(handler), or * our hack to use the flags as the prefix length. */ -static const char *full_name_hack(void *handler, const char *name, int len) +static const char *full_name_hack(const char *name, int len) { return name - len; } +#endif -static int scoutfs_xattr_get_handler(struct dentry *dentry, const char *name, - void *value, size_t size, int handler_flags) +static int scoutfs_xattr_get_handler +#ifdef KC_XATTR_STRUCT_XATTR_HANDLER + (const struct xattr_handler *handler, struct dentry *dentry, + struct inode *inode, const char *name, void *value, + size_t size) { - name = full_name_hack(NULL, name, handler_flags); + name = xattr_full_name(handler, name); +#else + (struct dentry *dentry, const char *name, + void *value, size_t size, int handler_flags) +{ + name = full_name_hack(name, handler_flags); +#endif return scoutfs_xattr_get(dentry, name, value, size); } -static int scoutfs_xattr_set_handler(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int handler_flags) +static int scoutfs_xattr_set_handler +#ifdef KC_XATTR_STRUCT_XATTR_HANDLER + (const struct xattr_handler *handler, struct dentry *dentry, + struct inode *inode, const char *name, const void *value, + size_t size, int flags) { - name = full_name_hack(NULL, name, handler_flags); + name = xattr_full_name(handler, name); +#else + (struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int handler_flags) +{ + name = full_name_hack(name, handler_flags); +#endif return scoutfs_xattr_set(dentry, name, value, size, flags); } From e69cf3dec8a20e2a39d015b45518fb04c7d18023 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 31 May 2023 15:43:01 -0400 Subject: [PATCH 26/46] kernel_getsockname and kernel_getpeername dropped addrlen arg. v4.16-rc1-1-g9b2c45d479d0 This interface now returns (sizeof (addr)) on success, instead of 0. Therefore, we have to change the error condition detection. The compat for older kernels handles the addrlen check internally. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/kernelcompat.h | 30 ++++++++++++++++++++++++++++++ kmod/src/net.c | 34 +++++++++++++--------------------- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 97840bf5..ca408a1a 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -158,3 +158,12 @@ endif ifneq (,$(shell grep 'int...get..const struct xattr_handler.*struct dentry.*dentry,' include/linux/xattr.h)) ccflags-y += -DKC_XATTR_STRUCT_XATTR_HANDLER=1 endif + +# +# v4.16-rc1-1-g9b2c45d479d0 +# +# kernel_getsockname() and kernel_getpeername dropped addrlen arg +# +ifneq (,$(shell grep 'kernel_getsockname.*,$$' include/linux/net.h)) +ccflags-y += -DKC_KERNEL_GETSOCKNAME_ADDRLEN=1 +endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 2df4ddfe..e3b93c66 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -222,4 +222,34 @@ struct kc_shrinker_wrapper { #endif /* KC_SHRINKER_SHRINK */ +#ifdef KC_KERNEL_GETSOCKNAME_ADDRLEN +#include +#include +static inline int kc_kernel_getsockname(struct socket *sock, struct sockaddr *addr) +{ + int addrlen = sizeof(struct sockaddr_in); + int ret = kernel_getsockname(sock, addr, &addrlen); + if (ret == 0 && addrlen != sizeof(struct sockaddr_in)) + return -EAFNOSUPPORT; + else if (ret < 0) + return ret; + + return sizeof(struct sockaddr_in); +} +static inline int kc_kernel_getpeername(struct socket *sock, struct sockaddr *addr) +{ + int addrlen = sizeof(struct sockaddr_in); + int ret = kernel_getpeername(sock, addr, &addrlen); + if (ret == 0 && addrlen != sizeof(struct sockaddr_in)) + return -EAFNOSUPPORT; + else if (ret < 0) + return ret; + + return sizeof(struct sockaddr_in); +} +#else +#define kc_kernel_getsockname(sock, addr) kernel_getsockname(sock, addr) +#define kc_kernel_getpeername(sock, addr) kernel_getpeername(sock, addr) +#endif + #endif diff --git a/kmod/src/net.c b/kmod/src/net.c index eab190da..c539fde1 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -897,7 +897,6 @@ static int sock_opts_and_names(struct scoutfs_net_connection *conn, struct socket *sock) { struct timeval tv; - int addrlen; int optval; int ret; @@ -947,23 +946,18 @@ static int sock_opts_and_names(struct scoutfs_net_connection *conn, if (ret) goto out; - addrlen = sizeof(struct sockaddr_in); - ret = kernel_getsockname(sock, (struct sockaddr *)&conn->sockname, - &addrlen); - if (ret == 0 && addrlen != sizeof(struct sockaddr_in)) - ret = -EAFNOSUPPORT; - if (ret) + ret = kc_kernel_getsockname(sock, (struct sockaddr *)&conn->sockname); + if (ret < 0) goto out; - addrlen = sizeof(struct sockaddr_in); - ret = kernel_getpeername(sock, (struct sockaddr *)&conn->peername, - &addrlen); - if (ret == 0 && addrlen != sizeof(struct sockaddr_in)) - ret = -EAFNOSUPPORT; - if (ret) + ret = kc_kernel_getpeername(sock, (struct sockaddr *)&conn->peername); + if (ret < 0) goto out; + ret = 0; + conn->last_peername = conn->peername; + out: return ret; } @@ -1471,20 +1465,18 @@ int scoutfs_net_bind(struct super_block *sb, goto out; ret = kernel_listen(sock, 255); - if (ret) + if (ret < 0) goto out; - addrlen = sizeof(struct sockaddr_in); - ret = kernel_getsockname(sock, (struct sockaddr *)&conn->sockname, - &addrlen); - if (ret == 0 && addrlen != sizeof(struct sockaddr_in)) - ret = -EAFNOSUPPORT; - if (ret) + ret = kc_kernel_getsockname(sock, (struct sockaddr *)&conn->sockname); + if (ret < 0) goto out; + ret = 0; + conn->sock = sock; *sin = conn->sockname; - ret = 0; + out: if (ret < 0 && sock) sock_release(sock); From 016dac39bf58ab2f03c7a74445e94069aacc6fe5 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 31 May 2023 15:48:54 -0400 Subject: [PATCH 27/46] Handle net arg being added to sock_create_kern() Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/kernelcompat.h | 6 ++++++ kmod/src/net.c | 4 ++-- kmod/src/quorum.c | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index ca408a1a..dac5f514 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -167,3 +167,12 @@ endif ifneq (,$(shell grep 'kernel_getsockname.*,$$' include/linux/net.h)) ccflags-y += -DKC_KERNEL_GETSOCKNAME_ADDRLEN=1 endif + +# +# v4.1-rc1-410-geeb1bd5c40ed +# +# Adds a struct net parameter to sock_create_kern +# +ifneq (,$(shell grep 'sock_create_kern.*struct net' include/linux/net.h)) +ccflags-y += -DKC_SOCK_CREATE_KERN_NET=1 +endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index e3b93c66..2dad3400 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -252,4 +252,10 @@ static inline int kc_kernel_getpeername(struct socket *sock, struct sockaddr *ad #define kc_kernel_getpeername(sock, addr) kernel_getpeername(sock, addr) #endif +#ifdef KC_SOCK_CREATE_KERN_NET +#define kc_sock_create_kern(family, type, proto, res) sock_create_kern(&init_net, family, type, proto, res) +#else +#define kc_sock_create_kern sock_create_kern +#endif + #endif diff --git a/kmod/src/net.c b/kmod/src/net.c index c539fde1..cfa1b6d4 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -1046,7 +1046,7 @@ static void scoutfs_net_connect_worker(struct work_struct *work) trace_scoutfs_net_connect_work_enter(sb, 0, 0); - ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + ret = kc_sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) goto out; @@ -1447,7 +1447,7 @@ int scoutfs_net_bind(struct super_block *sb, if (WARN_ON_ONCE(conn->sock)) return -EINVAL; - ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + ret = kc_sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) goto out; diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index de260b3a..ad83e344 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -183,7 +183,7 @@ static int create_socket(struct super_block *sb) int addrlen; int ret; - ret = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + ret = kc_sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (ret) { scoutfs_err(sb, "quorum couldn't create udp socket: %d", ret); goto out; From 69068ae2c039ec42d455e61b604d1f7ec1af661f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 1 Jun 2023 13:35:54 -0400 Subject: [PATCH 28/46] Initialize msg.msg_iter from iovec. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/net.c | 16 ++++++++++++---- kmod/src/quorum.c | 10 ++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index dac5f514..3f6991c6 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -176,3 +176,12 @@ endif ifneq (,$(shell grep 'sock_create_kern.*struct net' include/linux/net.h)) ccflags-y += -DKC_SOCK_CREATE_KERN_NET=1 endif + +# +# v3.18-rc6-1619-gc0371da6047a +# +# iov_iter is now part of struct msghdr +# +ifneq (,$(shell grep 'struct iov_iter.*msg_iter' include/linux/socket.h)) +ccflags-y += -DKC_MSGHDR_STRUCT_IOV_ITER=1 +endif diff --git a/kmod/src/net.c b/kmod/src/net.c index cfa1b6d4..bbcff7db 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -549,12 +549,16 @@ static int recvmsg_full(struct socket *sock, void *buf, unsigned len) while (len) { memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *)&kv; - msg.msg_iovlen = 1; msg.msg_flags = MSG_NOSIGNAL; kv.iov_base = buf; kv.iov_len = len; +#ifndef KC_MSGHDR_STRUCT_IOV_ITER + msg.msg_iov = (struct iovec *)&kv; + msg.msg_iovlen = 1; +#else + iov_iter_init(&msg.msg_iter, READ, (struct iovec *)&kv, len, 1); +#endif ret = kernel_recvmsg(sock, &msg, &kv, 1, len, msg.msg_flags); if (ret <= 0) return -ECONNABORTED; @@ -707,12 +711,16 @@ static int sendmsg_full(struct socket *sock, void *buf, unsigned len) while (len) { memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *)&kv; - msg.msg_iovlen = 1; msg.msg_flags = MSG_NOSIGNAL; kv.iov_base = buf; kv.iov_len = len; +#ifndef KC_MSGHDR_STRUCT_IOV_ITER + msg.msg_iov = (struct iovec *)&kv; + msg.msg_iovlen = 1; +#else + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)&kv, len, 1); +#endif ret = kernel_sendmsg(sock, &msg, &kv, 1, len); if (ret <= 0) return -ECONNABORTED; diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index ad83e344..f1b323bd 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -243,8 +243,10 @@ static int send_msg_members(struct super_block *sb, int type, u64 term, int only }; struct sockaddr_in sin; struct msghdr mh = { +#ifndef KC_MSGHDR_STRUCT_IOV_ITER .msg_iov = (struct iovec *)&kv, .msg_iovlen = 1, +#endif .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL, .msg_name = &sin, .msg_namelen = sizeof(sin), @@ -266,6 +268,9 @@ static int send_msg_members(struct super_block *sb, int type, u64 term, int only scoutfs_quorum_slot_sin(&qinf->qconf, i, &sin); now = ktime_get(); +#ifdef KC_MSGHDR_STRUCT_IOV_ITER + iov_iter_init(&mh.msg_iter, WRITE, (struct iovec *)&kv, sizeof(qmes), 1); +#endif ret = kernel_sendmsg(qinf->sock, &mh, &kv, 1, kv.iov_len); if (ret != kv.iov_len) failed++; @@ -308,8 +313,10 @@ static int recv_msg(struct super_block *sb, struct quorum_host_msg *msg, .iov_len = sizeof(struct scoutfs_quorum_message), }; struct msghdr mh = { +#ifndef KC_MSGHDR_STRUCT_IOV_ITER .msg_iov = (struct iovec *)&kv, .msg_iovlen = 1, +#endif .msg_flags = MSG_NOSIGNAL, }; @@ -331,6 +338,9 @@ static int recv_msg(struct super_block *sb, struct quorum_host_msg *msg, return ret; } +#ifdef KC_MSGHDR_STRUCT_IOV_ITER + iov_iter_init(&mh.msg_iter, READ, (struct iovec *)&kv, sizeof(struct scoutfs_quorum_message), 1); +#endif ret = kernel_recvmsg(qinf->sock, &mh, &kv, 1, kv.iov_len, mh.msg_flags); if (ret < 0) return ret; From 0e91f9a2779ccc10ed0cf8db47ff1fe47fba2a6c Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 10 May 2023 18:51:38 -0400 Subject: [PATCH 29/46] Adjust scoutfs_quorum_loop trace point. Convert the timeout struct unto a u64 nsecs value before passing it to the trace point event, as to not overflow the 64bit limitation on args. Signed-off-by: Auke Kok --- kmod/src/quorum.c | 3 +-- kmod/src/scoutfs_trace.h | 14 ++++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index f1b323bd..3395e5ee 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -781,8 +781,7 @@ static void scoutfs_quorum_worker(struct work_struct *work) msg.type = SCOUTFS_QUORUM_MSG_INVALID; trace_scoutfs_quorum_loop(sb, qst.role, qst.term, qst.vote_for, - qst.vote_bits, - ktime_to_timespec64(qst.timeout)); + qst.vote_bits, ktime_to_ns(qst.timeout)); /* receiving greater terms resets term, becomes follower */ if (msg.type != SCOUTFS_QUORUM_MSG_INVALID && diff --git a/kmod/src/scoutfs_trace.h b/kmod/src/scoutfs_trace.h index 3eb735d5..96feeedd 100644 --- a/kmod/src/scoutfs_trace.h +++ b/kmod/src/scoutfs_trace.h @@ -2024,9 +2024,9 @@ DEFINE_EVENT(scoutfs_quorum_message_class, scoutfs_quorum_recv_message, TRACE_EVENT(scoutfs_quorum_loop, TP_PROTO(struct super_block *sb, int role, u64 term, int vote_for, - unsigned long vote_bits, struct timespec64 timeout), + unsigned long vote_bits, unsigned long long nsecs), - TP_ARGS(sb, role, term, vote_for, vote_bits, timeout), + TP_ARGS(sb, role, term, vote_for, vote_bits, nsecs), TP_STRUCT__entry( SCSB_TRACE_FIELDS @@ -2035,8 +2035,7 @@ TRACE_EVENT(scoutfs_quorum_loop, __field(int, vote_for) __field(unsigned long, vote_bits) __field(unsigned long, vote_count) - __field(unsigned long long, timeout_sec) - __field(int, timeout_nsec) + __field(unsigned long long, nsecs) ), TP_fast_assign( @@ -2046,14 +2045,13 @@ TRACE_EVENT(scoutfs_quorum_loop, __entry->vote_for = vote_for; __entry->vote_bits = vote_bits; __entry->vote_count = hweight_long(vote_bits); - __entry->timeout_sec = timeout.tv_sec; - __entry->timeout_nsec = timeout.tv_nsec; + __entry->nsecs = nsecs; ), - TP_printk(SCSBF" term %llu role %d vote_for %d vote_bits 0x%lx vote_count %lu timeout %llu.%u", + TP_printk(SCSBF" term %llu role %d vote_for %d vote_bits 0x%lx vote_count %lu timeout %llu", SCSB_TRACE_ARGS, __entry->term, __entry->role, __entry->vote_for, __entry->vote_bits, __entry->vote_count, - __entry->timeout_sec, __entry->timeout_nsec) + __entry->nsecs) ); TRACE_EVENT(scoutfs_trans_seq_last, From ec50e66fff566430054af37cc62187217a65926f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:12:33 -0400 Subject: [PATCH 30/46] Timespec64 changes for yr2038. Provide a fallback `current_time(inode)` implementation for older kernels. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/acl.c | 2 +- kmod/src/data.c | 4 ++-- kmod/src/dir.c | 14 +++++++------- kmod/src/inode.c | 4 ++-- kmod/src/inode.h | 2 +- kmod/src/kernelcompat.c | 30 ++++++++++++++++++++++++++++++ kmod/src/kernelcompat.h | 8 ++++++++ kmod/src/xattr.c | 2 +- 9 files changed, 61 insertions(+), 14 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 3f6991c6..346a8249 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -185,3 +185,12 @@ endif ifneq (,$(shell grep 'struct iov_iter.*msg_iter' include/linux/socket.h)) ccflags-y += -DKC_MSGHDR_STRUCT_IOV_ITER=1 endif + +# +# v4.17-rc6-7-g95582b008388 +# +# Kernel has current_time(inode) to uniformly retreive timespec in the right unit +# +ifneq (,$(shell grep 'extern struct timespec64 current_time' include/linux/fs.h)) +ccflags-y += -DKC_CURRENT_TIME_INODE=1 +endif diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 93188f9d..9458f376 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -183,7 +183,7 @@ int scoutfs_set_acl_locked(struct inode *inode, struct posix_acl *acl, int type, if (!value) { /* can be setting an acl that only affects mode, didn't need xattr */ inode_inc_iversion(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = current_time(inode); } } diff --git a/kmod/src/data.c b/kmod/src/data.c index 54009404..a51ee67b 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -1221,7 +1221,7 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off, struct data_ext_args from_args; struct data_ext_args to_args; struct scoutfs_extent ext; - struct timespec cur_time; + struct kc_timespec cur_time; LIST_HEAD(locks); bool done = false; loff_t from_size; @@ -1442,7 +1442,7 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off, up_write(&from_si->extent_sem); up_write(&to_si->extent_sem); - cur_time = CURRENT_TIME; + cur_time = current_time(from); if (!is_stage) { to->i_ctime = to->i_mtime = cur_time; inode_inc_iversion(to); diff --git a/kmod/src/dir.c b/kmod/src/dir.c index aa1272af..f8bf50e9 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -735,7 +735,7 @@ static int scoutfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, i_size_read(dir) + dentry->d_name.len); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = current_time(inode); inode->i_mtime = inode->i_atime = inode->i_ctime = dir->i_mtime; si->crtime = inode->i_mtime; inode_inc_iversion(dir); @@ -859,7 +859,7 @@ retry: set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, dir_size); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = current_time(inode); inode->i_ctime = dir->i_mtime; inc_nlink(inode); inode_inc_iversion(dir); @@ -900,7 +900,7 @@ static int scoutfs_unlink(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode = dentry->d_inode; - struct timespec ts = current_kernel_time(); + struct kc_timespec ts = current_time(inode); struct scoutfs_lock *inode_lock = NULL; struct scoutfs_lock *orph_lock = NULL; struct scoutfs_lock *dir_lock = NULL; @@ -1204,7 +1204,7 @@ static int scoutfs_symlink(struct inode *dir, struct dentry *dentry, set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, i_size_read(dir) + dentry->d_name.len); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = current_time(inode); inode_inc_iversion(dir); inode->i_ctime = dir->i_mtime; @@ -1558,7 +1558,7 @@ static int scoutfs_rename_common(struct inode *old_dir, struct scoutfs_lock *orph_lock = NULL; struct scoutfs_dirent new_dent; struct scoutfs_dirent old_dent; - struct timespec now; + struct kc_timespec now; bool ins_new = false; bool del_new = false; bool ins_old = false; @@ -1724,7 +1724,7 @@ retry: inc_nlink(new_dir); } - now = CURRENT_TIME; + now = current_time(old_inode); old_dir->i_ctime = now; old_dir->i_mtime = now; if (new_dir != old_dir) { @@ -1861,7 +1861,7 @@ static int scoutfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mod if (ret < 0) goto out; /* XXX returning error but items created */ - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); si->crtime = inode->i_mtime; insert_inode_hash(inode); ihold(inode); /* need to update inode modifications in d_tmpfile */ diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 6016c0d2..54c9850d 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -384,7 +384,7 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock, scoutfs_inode_inc_data_version(inode); truncate_setsize(inode, new_size); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_ctime = inode->i_mtime = current_time(inode); if (truncate) si->flags |= SCOUTFS_INO_FLAG_TRUNCATE; scoutfs_inode_set_data_seq(inode); @@ -1474,7 +1474,7 @@ int scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, d inode->i_ino = ino; /* XXX overflow */ inode_init_owner(inode, dir, mode); inode_set_bytes(inode, 0); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); inode->i_rdev = rdev; set_inode_ops(inode); diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 79eacde0..86e1b9fb 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -22,7 +22,7 @@ struct scoutfs_inode_info { u64 online_blocks; u64 offline_blocks; u32 flags; - struct timespec crtime; + struct kc_timespec crtime; /* * Protects per-inode extent items, most particularly readers diff --git a/kmod/src/kernelcompat.c b/kmod/src/kernelcompat.c index bb11a803..7ad197ee 100644 --- a/kmod/src/kernelcompat.c +++ b/kmod/src/kernelcompat.c @@ -28,3 +28,33 @@ int kc_shrink_wrapper_fn(struct shrinker *shrink, struct shrink_control *sc) return min_t(unsigned long, nr, INT_MAX); } #endif + +#ifndef KC_CURRENT_TIME_INODE +struct timespec64 kc_current_time(struct inode *inode) +{ + struct timespec64 now; + unsigned gran; + + getnstimeofday64(&now); + + if (unlikely(!inode->i_sb)) { + WARN(1, "current_time() called with uninitialized super_block in the inode"); + return now; + } + + gran = inode->i_sb->s_time_gran; + + /* Avoid division in the common cases 1 ns and 1 s. */ + if (gran == 1) { + /* nothing */ + } else if (gran == NSEC_PER_SEC) { + now.tv_nsec = 0; + } else if (gran > 1 && gran < NSEC_PER_SEC) { + now.tv_nsec -= now.tv_nsec % gran; + } else { + WARN(1, "illegal file time granularity: %u", gran); + } + + return now; +} +#endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 2dad3400..b18fa847 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -178,6 +178,14 @@ do { \ #define SB_I_VERSION MS_I_VERSION #endif +#ifndef KC_CURRENT_TIME_INODE +struct timespec64 kc_current_time(struct inode *inode); +#define current_time kc_current_time +#define kc_timespec timespec +#else +#define kc_timespec timespec64 +#endif + #ifndef KC_SHRINKER_SHRINK #define KC_DEFINE_SHRINKER(name) struct shrinker name diff --git a/kmod/src/xattr.c b/kmod/src/xattr.c index 75fc35b4..da736ef5 100644 --- a/kmod/src/xattr.c +++ b/kmod/src/xattr.c @@ -773,7 +773,7 @@ int scoutfs_xattr_set_locked(struct inode *inode, const char *name, size_t name_ /* XXX do these want i_mutex or anything? */ inode_inc_iversion(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = current_time(inode); ret = 0; out: From e88845d185a433785a9e2be9aa96def2d5fccc63 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:39:56 -0400 Subject: [PATCH 31/46] (un)register_hotcpu_notifier is obsolete v4.9-12228-g530e9b76ae8f Drops all (un)register_(hot)cpu_notifier() API functions. From here on we need to use the new cpuhp_* API. We avoid this entirely for now, at the cost of leaking pages until the filesystem is unmounted. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/item.c | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 346a8249..17be9619 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -194,3 +194,13 @@ endif ifneq (,$(shell grep 'extern struct timespec64 current_time' include/linux/fs.h)) ccflags-y += -DKC_CURRENT_TIME_INODE=1 endif + +# +# v4.9-12228-g530e9b76ae8f +# +# register_cpu_notifier and family were all removed and to be +# replaced with cpuhp_* API calls. +# +ifneq (,$(shell grep 'define register_hotcpu_notifier' include/linux/cpu.h)) +ccflags-y += -DKC_CPU_NOTIFIER +endif diff --git a/kmod/src/item.c b/kmod/src/item.c index 6d7bd376..673797ef 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -78,7 +78,9 @@ struct item_cache_info { struct super_block *sb; struct item_percpu_pages __percpu *pcpu_pages; KC_DEFINE_SHRINKER(shrinker); +#ifdef KC_CPU_NOTIFIER struct notifier_block notifier; +#endif /* often walked, but per-cpu refs are fast path */ rwlock_t rwlock; @@ -2605,6 +2607,7 @@ static unsigned long item_cache_scan_objects(struct shrinker *shrink, return freed; } +#ifdef KC_CPU_NOTIFIER static int item_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -2619,6 +2622,7 @@ static int item_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } +#endif int scoutfs_item_setup(struct super_block *sb) { @@ -2651,8 +2655,10 @@ int scoutfs_item_setup(struct super_block *sb) KC_INIT_SHRINKER_FUNCS(&cinf->shrinker, item_cache_count_objects, item_cache_scan_objects); KC_REGISTER_SHRINKER(&cinf->shrinker); +#ifdef KC_CPU_NOTIFIER cinf->notifier.notifier_call = item_cpu_callback; register_hotcpu_notifier(&cinf->notifier); +#endif sbi->item_cache_info = cinf; return 0; @@ -2672,7 +2678,9 @@ void scoutfs_item_destroy(struct super_block *sb) if (cinf) { BUG_ON(!list_empty(&cinf->active_list)); +#ifdef KC_CPU_NOTIFIER unregister_hotcpu_notifier(&cinf->notifier); +#endif KC_UNREGISTER_SHRINKER(&cinf->shrinker); for_each_possible_cpu(cpu) From 65be4682e368debc92bd8eea4142b73e6e64b2df Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:39:20 -0400 Subject: [PATCH 32/46] implement generic_file_buffered_write() This function is removed in el8 therefore we need to implement it ourselves now. Copy it. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/kernelcompat.c | 24 ++++++++++++++++++++++++ kmod/src/kernelcompat.h | 7 +++++++ 3 files changed, 40 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 17be9619..6393ac1f 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -204,3 +204,12 @@ endif ifneq (,$(shell grep 'define register_hotcpu_notifier' include/linux/cpu.h)) ccflags-y += -DKC_CPU_NOTIFIER endif + +# +# v3.14-rc8-130-gccad2365668f +# +# generic_file_buffered_write is removed, backport it +# +ifneq (,$(shell grep 'extern ssize_t generic_file_buffered_write' include/linux/fs.h)) +ccflags-y += -DKC_GENERIC_FILE_BUFFERED_WRITE=1 +endif diff --git a/kmod/src/kernelcompat.c b/kmod/src/kernelcompat.c index 7ad197ee..7f8da413 100644 --- a/kmod/src/kernelcompat.c +++ b/kmod/src/kernelcompat.c @@ -1,4 +1,6 @@ +#include + #include "kernelcompat.h" #ifdef KC_SHRINKER_SHRINK @@ -58,3 +60,25 @@ struct timespec64 kc_current_time(struct inode *inode) return now; } #endif + +#ifndef KC_GENERIC_FILE_BUFFERED_WRITE +ssize_t +kc_generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos, loff_t *ppos, + size_t count, ssize_t written) +{ + struct file *file = iocb->ki_filp; + ssize_t status; + struct iov_iter i; + + iov_iter_init(&i, WRITE, iov, nr_segs, count); + status = generic_perform_write(file, &i, pos); + + if (likely(status >= 0)) { + written += status; + *ppos = pos + status; + } + + return written ? written : status; +} +#endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index b18fa847..32124829 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -266,4 +266,11 @@ static inline int kc_kernel_getpeername(struct socket *sock, struct sockaddr *ad #define kc_sock_create_kern sock_create_kern #endif +#ifndef KC_GENERIC_FILE_BUFFERED_WRITE +ssize_t kc_generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos, loff_t *ppos, + size_t count, ssize_t written); +#define generic_file_buffered_write kc_generic_file_buffered_write +#endif + #endif From bafecbc604128faf1addd7e0e50fa7ca9ec5f62f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 5 Jun 2023 19:39:20 -0400 Subject: [PATCH 33/46] Implement .readahead for address_space_operations (aops). .readpages is obsolete in el8 kernels. We implement the .readahead method instead which is passed a struct readahead_control. We use the readahead_page(rac) accessor to retrieve page by page from the struct. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 12 ++++++++++++ kmod/src/data.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 6393ac1f..1ea7a805 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -213,3 +213,15 @@ endif ifneq (,$(shell grep 'extern ssize_t generic_file_buffered_write' include/linux/fs.h)) ccflags-y += -DKC_GENERIC_FILE_BUFFERED_WRITE=1 endif + +# +# v5.7-438-g8151b4c8bee4 +# +# struct address_space_operations switches away from .readpages to .readahead +# +# RHEL has backported this feature all the way to RHEL8, as part of RHEL_KABI, +# which means we need to detect this very precisely +# +ifneq (,$(shell grep 'readahead.*struct readahead_control' include/linux/fs.h)) +ccflags-y += -DKC_FILE_AOPS_READAHEAD +endif diff --git a/kmod/src/data.c b/kmod/src/data.c index a51ee67b..987f90a1 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -729,6 +729,7 @@ static int scoutfs_readpage(struct file *file, struct page *page) return ret; } +#ifndef KC_FILE_AOPS_READAHEAD /* * This is used for opportunistic read-ahead which can throw the pages * away if it needs to. If the caller didn't deal with offline extents @@ -775,6 +776,29 @@ out: BUG_ON(!list_empty(pages)); return ret; } +#else +static void scoutfs_readahead(struct readahead_control *rac) +{ + struct inode *inode = rac->file->f_inode; + struct super_block *sb = inode->i_sb; + struct scoutfs_lock *inode_lock = NULL; + int ret; + + ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, + SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock); + if (ret) + return; + + ret = scoutfs_data_wait_check(inode, readahead_pos(rac), + readahead_length(rac), SEF_OFFLINE, + SCOUTFS_IOC_DWO_READ, NULL, + inode_lock); + if (ret == 0) + mpage_readahead(rac, scoutfs_get_block_read); + + scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); +} +#endif static int scoutfs_writepage(struct page *page, struct writeback_control *wbc) { @@ -1873,7 +1897,11 @@ int scoutfs_data_waiting(struct super_block *sb, u64 ino, u64 iblock, const struct address_space_operations scoutfs_file_aops = { .readpage = scoutfs_readpage, +#ifndef KC_FILE_AOPS_READAHEAD .readpages = scoutfs_readpages, +#else + .readahead = scoutfs_readahead, +#endif .writepage = scoutfs_writepage, .writepages = scoutfs_writepages, .write_begin = scoutfs_write_begin, From d480243c115e4eae926161cfaaa8342a0a115c1a Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:32:57 -0400 Subject: [PATCH 34/46] Support .read/write_iter callbacks in lieu of .aio_read/write The aio_read and aio_write callbacks are no longer used by newer kernels which now uses iter based readers and writers. We can avoid implementing plain .read and .write as an iter will be generated when needed for us automatically. We add a new data_wait_check_iter() function accordingly. With these methods removed from the kernel, the el8 kernel no longer uses the extended ops wrapper struct and is much closer now to upstream. As a result, a lot of methods are moving around from inode_dir_operations to and from inode_file_operations etc, and perhaps things will look a bit more structured as a result. As a result, we need a slightly different data_wait_check() that accounts for the iter and offset properly. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 23 +++++++ kmod/src/data.c | 36 +++++++++++ kmod/src/data.h | 3 + kmod/src/dir.c | 93 ++++++++++++++++++++++------ kmod/src/dir.h | 4 ++ kmod/src/file.c | 108 +++++++++++++++++++++++++++++++++ kmod/src/file.h | 5 ++ kmod/src/inode.c | 19 +++++- kmod/src/inode.h | 5 ++ kmod/src/ioctl.c | 2 + 10 files changed, 276 insertions(+), 22 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 1ea7a805..55c5a256 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -225,3 +225,26 @@ endif ifneq (,$(shell grep 'readahead.*struct readahead_control' include/linux/fs.h)) ccflags-y += -DKC_FILE_AOPS_READAHEAD endif + +# +# v4.0-rc7-1743-g8436318205b9 +# +# .aio_read and .aio_write no longer exist. All reads and writes now use the +# .read_iter and .write_iter methods, or must implement .read and .write (which +# we don't). +# +ifneq (,$(shell grep 'ssize_t.*aio_read' include/linux/fs.h)) +ccflags-y += -DKC_LINUX_HAVE_FOP_AIO_READ=1 +endif + +# +# rhel7 has a custom inode_operations_wrapper struct that is discarded +# entirely in favor of upstream structure since rhel8. +# +ifneq (,$(shell grep 'void.*follow_link.*struct dentry' include/linux/fs.h)) +ccflags-y += -DKC_LINUX_HAVE_RHEL_IOPS_WRAPPER=1 +endif + +ifneq (,$(shell grep 'size_t.*ki_left;' include/linux/aio.h)) +ccflags-y += -DKC_LINUX_AIO_KI_LEFT=1 +endif diff --git a/kmod/src/data.c b/kmod/src/data.c index 987f90a1..78dd74ad 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -1807,6 +1807,37 @@ int scoutfs_data_wait_check_iov(struct inode *inode, const struct iovec *iov, return ret; } +int scoutfs_data_wait_check_iter(struct inode *inode, loff_t pos, struct iov_iter *iter, + u8 sef, u8 op, struct scoutfs_data_wait *dw, + struct scoutfs_lock *lock) +{ + size_t count = iov_iter_count(iter); + size_t off = iter->iov_offset; + const struct iovec *iov; + size_t len; + int ret = 0; + + for (iov = iter->iov; count > 0; iov++) { + len = iov->iov_len - off; + if (len == 0) + continue; + + /* aren't we waiting on too much data here ? */ + ret = scoutfs_data_wait_check(inode, pos, len, + sef, op, dw, lock); + + if (ret != 0) + break; + + + pos += len; + count -= len; + off = 0; + } + + return ret; +} + int scoutfs_data_wait(struct inode *inode, struct scoutfs_data_wait *dw) { DECLARE_DATA_WAIT_ROOT(inode->i_sb, rt); @@ -1909,10 +1940,15 @@ const struct address_space_operations scoutfs_file_aops = { }; const struct file_operations scoutfs_file_fops = { +#ifdef KC_LINUX_HAVE_FOP_AIO_READ .read = do_sync_read, .write = do_sync_write, .aio_read = scoutfs_file_aio_read, .aio_write = scoutfs_file_aio_write, +#else + .read_iter = scoutfs_file_read_iter, + .write_iter = scoutfs_file_write_iter, +#endif .unlocked_ioctl = scoutfs_ioctl, .fsync = scoutfs_file_fsync, .llseek = scoutfs_file_llseek, diff --git a/kmod/src/data.h b/kmod/src/data.h index a34854eb..1fbfce9b 100644 --- a/kmod/src/data.h +++ b/kmod/src/data.h @@ -65,6 +65,9 @@ int scoutfs_data_wait_check_iov(struct inode *inode, const struct iovec *iov, unsigned long nr_segs, loff_t pos, u8 sef, u8 op, struct scoutfs_data_wait *ow, struct scoutfs_lock *lock); +int scoutfs_data_wait_check_iter(struct inode *inode, loff_t pos, struct iov_iter *iter, + u8 sef, u8 op, struct scoutfs_data_wait *ow, + struct scoutfs_lock *lock); bool scoutfs_data_wait_found(struct scoutfs_data_wait *ow); int scoutfs_data_wait(struct inode *inode, struct scoutfs_data_wait *ow); diff --git a/kmod/src/dir.c b/kmod/src/dir.c index f8bf50e9..357d33c6 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -1059,14 +1059,14 @@ static int symlink_item_ops(struct super_block *sb, enum symlink_ops op, u64 ino } /* - * Full a buffer with the null terminated symlink, point nd at it, and - * return it so put_link can free it once the vfs is done. + * Fill a buffer with the null terminated symlink, and return it + * so callers can free it once the vfs is done. * * We chose to pay the runtime cost of per-call allocation and copy * overhead instead of wiring up symlinks to the page cache, storing * each small link in a full page, and later having to reclaim them. */ -static void *scoutfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *scoutfs_get_link_target(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct super_block *sb = inode->i_sb; @@ -1125,32 +1125,41 @@ out: if (ret < 0) { kfree(path); path = ERR_PTR(ret); - } else { - nd_set_link(nd, path); } + scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); return path; } +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER +static void *scoutfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *path; + + path = scoutfs_get_link_target(dentry); + if (!IS_ERR_OR_NULL(path)) + nd_set_link(nd, path); + return path; +} + static void scoutfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { if (!IS_ERR_OR_NULL(cookie)) kfree(cookie); } +#else +static const char *scoutfs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +{ + char *path; -const struct inode_operations scoutfs_symlink_iops = { - .readlink = generic_readlink, - .follow_link = scoutfs_follow_link, - .put_link = scoutfs_put_link, - .getattr = scoutfs_getattr, - .setattr = scoutfs_setattr, - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = scoutfs_listxattr, - .removexattr = generic_removexattr, - .get_acl = scoutfs_get_acl, -}; + path = scoutfs_get_link_target(dentry); + if (!IS_ERR_OR_NULL(path)) + set_delayed_call(done, kfree_link, path); + + return path; +} +#endif /* * Symlink target paths can be annoyingly large. We store relatively @@ -1811,12 +1820,14 @@ out_unlock: return ret; } +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER static int scoutfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { return scoutfs_rename_common(old_dir, old_dentry, new_dir, new_dentry, 0); } +#endif static int scoutfs_rename2(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, @@ -1886,6 +1897,37 @@ out: return ret; } +const struct inode_operations scoutfs_symlink_iops = { +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER + .readlink = generic_readlink, + .follow_link = scoutfs_follow_link, + .put_link = scoutfs_put_link, +#else + .get_link = scoutfs_get_link, +#endif + .getattr = scoutfs_getattr, + .setattr = scoutfs_setattr, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, +#endif + .listxattr = scoutfs_listxattr, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER + .removexattr = generic_removexattr, +#endif + .get_acl = scoutfs_get_acl, +#ifndef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER + .tmpfile = scoutfs_tmpfile, + .rename = scoutfs_rename_common, + .symlink = scoutfs_symlink, + .unlink = scoutfs_unlink, + .link = scoutfs_link, + .mkdir = scoutfs_mkdir, + .create = scoutfs_create, + .lookup = scoutfs_lookup, +#endif +}; + const struct file_operations scoutfs_dir_fops = { .KC_FOP_READDIR = scoutfs_readdir, #ifdef KC_FMODE_KABI_ITERATE @@ -1897,9 +1939,12 @@ const struct file_operations scoutfs_dir_fops = { }; - +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER const struct inode_operations_wrapper scoutfs_dir_iops = { .ops = { +#else +const struct inode_operations scoutfs_dir_iops = { +#endif .lookup = scoutfs_lookup, .mknod = scoutfs_mknod, .create = scoutfs_create, @@ -1907,17 +1952,25 @@ const struct inode_operations_wrapper scoutfs_dir_iops = { .link = scoutfs_link, .unlink = scoutfs_unlink, .rmdir = scoutfs_unlink, - .rename = scoutfs_rename, .getattr = scoutfs_getattr, .setattr = scoutfs_setattr, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER + .rename = scoutfs_rename, .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = scoutfs_listxattr, .removexattr = generic_removexattr, +#endif + .listxattr = scoutfs_listxattr, .get_acl = scoutfs_get_acl, .symlink = scoutfs_symlink, .permission = scoutfs_permission, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER }, +#endif .tmpfile = scoutfs_tmpfile, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER .rename2 = scoutfs_rename2, +#else + .rename = scoutfs_rename2, +#endif }; diff --git a/kmod/src/dir.h b/kmod/src/dir.h index 9bd1f193..9985b7c3 100644 --- a/kmod/src/dir.h +++ b/kmod/src/dir.h @@ -5,7 +5,11 @@ #include "lock.h" extern const struct file_operations scoutfs_dir_fops; +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER extern const struct inode_operations_wrapper scoutfs_dir_iops; +#else +extern const struct inode_operations scoutfs_dir_iops; +#endif extern const struct inode_operations scoutfs_symlink_iops; extern const struct dentry_operations scoutfs_dentry_ops; diff --git a/kmod/src/file.c b/kmod/src/file.c index 08058592..fd31a9d0 100644 --- a/kmod/src/file.c +++ b/kmod/src/file.c @@ -29,6 +29,7 @@ #include "per_task.h" #include "omap.h" +#ifdef KC_LINUX_HAVE_FOP_AIO_READ /* * Start a high level file read. We check for offline extents in the * read region here so that we only check the extents once. We use the @@ -146,6 +147,113 @@ out: return ret; } +#else +ssize_t scoutfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + struct super_block *sb = inode->i_sb; + struct scoutfs_lock *scoutfs_inode_lock = NULL; + SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); + DECLARE_DATA_WAIT(dw); + int ret; + +retry: + /* protect checked extents from release */ + inode_lock(inode); + atomic_inc(&inode->i_dio_count); + inode_unlock(inode); + + ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, + SCOUTFS_LKF_REFRESH_INODE, inode, &scoutfs_inode_lock); + if (ret) + goto out; + + if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, scoutfs_inode_lock)) { + ret = scoutfs_data_wait_check_iter(inode, iocb->ki_pos, to, + SEF_OFFLINE, + SCOUTFS_IOC_DWO_READ, + &dw, scoutfs_inode_lock); + if (ret != 0) + goto out; + } else { + WARN_ON_ONCE(true); + } + + ret = generic_file_read_iter(iocb, to); + +out: + inode_dio_end(inode); + scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); + scoutfs_unlock(sb, scoutfs_inode_lock, SCOUTFS_LOCK_READ); + + if (scoutfs_data_wait_found(&dw)) { + ret = scoutfs_data_wait(inode, &dw); + if (ret == 0) + goto retry; + } + return ret; +} + +ssize_t scoutfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + struct super_block *sb = inode->i_sb; + struct scoutfs_lock *scoutfs_inode_lock = NULL; + SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); + DECLARE_DATA_WAIT(dw); + int ret; + int written; + +retry: + inode_lock(inode); + ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, + SCOUTFS_LKF_REFRESH_INODE, inode, &scoutfs_inode_lock); + if (ret) + goto out; + + ret = generic_write_checks(iocb, from); + if (ret <= 0) + goto out; + + ret = scoutfs_complete_truncate(inode, scoutfs_inode_lock); + if (ret) + goto out; + + if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, scoutfs_inode_lock)) { + /* data_version is per inode, whole file must be online */ + ret = scoutfs_data_wait_check_iter(inode, iocb->ki_pos, from, + SEF_OFFLINE, + SCOUTFS_IOC_DWO_WRITE, + &dw, scoutfs_inode_lock); + if (ret != 0) + goto out; + } + + /* XXX: remove SUID bit */ + + written = __generic_file_write_iter(iocb, from); + +out: + scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); + scoutfs_unlock(sb, scoutfs_inode_lock, SCOUTFS_LOCK_WRITE); + inode_unlock(inode); + + if (scoutfs_data_wait_found(&dw)) { + ret = scoutfs_data_wait(inode, &dw); + if (ret == 0) + goto retry; + } + + if (ret > 0 || ret == -EIOCBQUEUED) + ret = generic_write_sync(iocb, written); + + return written ? written : ret; +} +#endif int scoutfs_permission(struct inode *inode, int mask) { diff --git a/kmod/src/file.h b/kmod/src/file.h index 82d86618..82829ef5 100644 --- a/kmod/src/file.h +++ b/kmod/src/file.h @@ -1,10 +1,15 @@ #ifndef _SCOUTFS_FILE_H_ #define _SCOUTFS_FILE_H_ +#ifdef KC_LINUX_HAVE_FOP_AIO_READ ssize_t scoutfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); ssize_t scoutfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); +#else +ssize_t scoutfs_file_read_iter(struct kiocb *, struct iov_iter *); +ssize_t scoutfs_file_write_iter(struct kiocb *, struct iov_iter *); +#endif int scoutfs_permission(struct inode *inode, int mask); loff_t scoutfs_file_llseek(struct file *file, loff_t offset, int whence); diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 54c9850d..540004cc 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -143,10 +143,12 @@ void scoutfs_destroy_inode(struct inode *inode) static const struct inode_operations scoutfs_file_iops = { .getattr = scoutfs_getattr, .setattr = scoutfs_setattr, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = scoutfs_listxattr, .removexattr = generic_removexattr, +#endif + .listxattr = scoutfs_listxattr, .get_acl = scoutfs_get_acl, .fiemap = scoutfs_data_fiemap, }; @@ -154,10 +156,12 @@ static const struct inode_operations scoutfs_file_iops = { static const struct inode_operations scoutfs_special_iops = { .getattr = scoutfs_getattr, .setattr = scoutfs_setattr, +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = scoutfs_listxattr, .removexattr = generic_removexattr, +#endif + .listxattr = scoutfs_listxattr, .get_acl = scoutfs_get_acl, }; @@ -174,8 +178,12 @@ static void set_inode_ops(struct inode *inode) inode->i_fop = &scoutfs_file_fops; break; case S_IFDIR: +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER inode->i_op = &scoutfs_dir_iops.ops; inode->i_flags |= S_IOPS_WRAPPER; +#else + inode->i_op = &scoutfs_dir_iops; +#endif inode->i_fop = &scoutfs_dir_fops; break; case S_IFLNK: @@ -340,10 +348,17 @@ int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock) return ret; } +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER int scoutfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; +#else +int scoutfs_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int query_flags) +{ + struct inode *inode = d_inode(path->dentry); +#endif struct super_block *sb = inode->i_sb; struct scoutfs_lock *lock = NULL; int ret; diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 86e1b9fb..607ac9f8 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -123,8 +123,13 @@ void scoutfs_inode_get_onoff(struct inode *inode, s64 *on, s64 *off); int scoutfs_complete_truncate(struct inode *inode, struct scoutfs_lock *lock); int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock); +#ifdef KC_LINUX_HAVE_RHEL_IOPS_WRAPPER int scoutfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); +#else +int scoutfs_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int query_flags); +#endif int scoutfs_setattr(struct dentry *dentry, struct iattr *attr); int scoutfs_inode_orphan_create(struct super_block *sb, u64 ino, struct scoutfs_lock *lock, diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index fb8c8c46..6bf70403 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -480,8 +480,10 @@ static long scoutfs_ioc_stage(struct file *file, unsigned long arg) /* the iocb is really only used for the file pointer :P */ init_sync_kiocb(&kiocb, file); kiocb.ki_pos = args.offset; +#ifdef KC_LINUX_AIO_KI_LEFT kiocb.ki_left = args.length; kiocb.ki_nbytes = args.length; +#endif iov.iov_base = (void __user *)(unsigned long)args.buf_ptr; iov.iov_len = args.length; From e580f33f82f3fa5baef19c859f20313e54c415db Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 5 Jul 2023 14:00:36 -0400 Subject: [PATCH 35/46] Ignore loop device resizing messages. These occasionally trigger during tests. Signed-off-by: Auke Kok --- tests/funcs/filter.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/funcs/filter.sh b/tests/funcs/filter.sh index 766ab562..2ff9d286 100644 --- a/tests/funcs/filter.sh +++ b/tests/funcs/filter.sh @@ -85,5 +85,8 @@ t_filter_dmesg() re="$re|scoutfs .* error.*server failed to bind to.*" re="$re|scoutfs .* critical transaction commit failure.*" + # change-devices causes loop device resizing + re="$re|loop[0-9].* detected capacity change from.*" + egrep -v "($re)" } From 205d8ebd4a362f281c12ac9c78a98449e904e956 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 5 Jul 2023 14:01:51 -0400 Subject: [PATCH 36/46] Account for quoting style changes in coreutils. In older versions of coreutils, quoted strings are occasionally output using utf-8 open/close single quotes. New versions of coreutils will exclusively use the ASCII single quote character "'" when the output is not a TTY - as is the case with all test scripts. We can avoid most of these problems by always setting LC_ALL=C in testing, however. Signed-off-by: Auke Kok --- tests/golden/basic-posix-consistency | 2 +- tests/golden/inode-deletion | 2 +- tests/golden/offline-extent-waiting | 4 ++-- tests/run-tests.sh | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/golden/basic-posix-consistency b/tests/golden/basic-posix-consistency index 2c5fb6ab..3bf10ae1 100644 --- a/tests/golden/basic-posix-consistency +++ b/tests/golden/basic-posix-consistency @@ -47,7 +47,7 @@ four --- dir within dir --- overwrite file --- can't overwrite non-empty dir -mv: cannot move ‘/mnt/test/test/basic-posix-consistency/dir/c/clobber’ to ‘/mnt/test/test/basic-posix-consistency/dir/a/dir’: Directory not empty +mv: cannot move '/mnt/test/test/basic-posix-consistency/dir/c/clobber' to '/mnt/test/test/basic-posix-consistency/dir/a/dir': Directory not empty --- can overwrite empty dir --- can rename into root == path resoluion diff --git a/tests/golden/inode-deletion b/tests/golden/inode-deletion index 1e36ff37..f586d563 100644 --- a/tests/golden/inode-deletion +++ b/tests/golden/inode-deletion @@ -17,7 +17,7 @@ ino not found in dseq index mount 0 contents after mount 1 rm: contents ino found in dseq index ino found in dseq index -stat: cannot stat ‘/mnt/test/test/inode-deletion/file’: No such file or directory +stat: cannot stat '/mnt/test/test/inode-deletion/file': No such file or directory ino not found in dseq index ino not found in dseq index == lots of deletions use one open map diff --git a/tests/golden/offline-extent-waiting b/tests/golden/offline-extent-waiting index 5b4af2d2..9ea47d4f 100644 --- a/tests/golden/offline-extent-waiting +++ b/tests/golden/offline-extent-waiting @@ -20,10 +20,10 @@ offline waiting should now have two known entries: data_wait_err found 2 waiters. offline waiting should now have 0 known entries: 0 -dd: error reading ‘/mnt/test/test/offline-extent-waiting/dir/file’: Input/output error +dd: error reading '/mnt/test/test/offline-extent-waiting/dir/file': Input/output error 0+0 records in 0+0 records out -dd: error reading ‘/mnt/test/test/offline-extent-waiting/dir/file’: Input/output error +dd: error reading '/mnt/test/test/offline-extent-waiting/dir/file': Input/output error 0+0 records in 0+0 records out offline waiting should be empty again: diff --git a/tests/run-tests.sh b/tests/run-tests.sh index a9613687..1202cada 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -1,5 +1,8 @@ #!/usr/bin/bash +# Force system tools to use ASCII quotes +export LC_ALL=C + # # XXX # - could have helper functions for waiting for pids From a9beeaf5da46f1deac03f328ee7db175114bb503 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 5 Jul 2023 14:05:10 -0400 Subject: [PATCH 37/46] Account for e2fsprogs output format changes. The filefrag program in e2fsprogs-v1.42.10-10-g29758d2f now includes an extra flag, and changes how the `unknown` flag is output. We essentially adjust for this "new" golden value on the fly if we encounter it. We don't expect future changes to the output. Signed-off-by: Auke Kok --- tests/tests/setattr_more.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/tests/setattr_more.sh b/tests/tests/setattr_more.sh index af05b89f..c15a507a 100644 --- a/tests/tests/setattr_more.sh +++ b/tests/tests/setattr_more.sh @@ -55,10 +55,17 @@ scoutfs setattr -t 67305985.999999999 -V 1 -s 1 "$FILE" 2>&1 | t_filter_fs TZ=GMT stat -c "%z" "$FILE" rm "$FILE" +# +# With e2fsprogs-v1.42.10-10-g29758d2f, the output of filefrag 'flags' changes +# significantly. First, the _LAST flag is now output. Second, the 'unknown' +# flag is now printed out as 'unknown_loc'. To compensate for this, we check +# and replace the "correct" output for new versions here with the expected +# value. +# echo "== large offline extents are created" touch "$FILE" scoutfs setattr -V 1 -o -s $((10007 * 4096)) "$FILE" 2>&1 | t_filter_fs -filefrag -v -b4096 "$FILE" 2>&1 | t_filter_fs +filefrag -v -b4096 "$FILE" 2>&1 | sed 's/last,unknown_loc,eof$/unknown,eof/' | t_filter_fs rm "$FILE" # had a bug where we were creating extents that were too long From 46e8dfe884a5729b8958f5701e7f09bfb3dd34a4 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 5 Jul 2023 14:07:57 -0400 Subject: [PATCH 38/46] Account for coreutils using statx() call instead of stat() `stat` internally switched to using the new `statx` syscall, and this affects the output of perror() subsequently. This is the same error as before (and expected). Signed-off-by: Auke Kok --- tests/tests/inode-deletion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/inode-deletion.sh b/tests/tests/inode-deletion.sh index 5af97354..9324d035 100644 --- a/tests/tests/inode-deletion.sh +++ b/tests/tests/inode-deletion.sh @@ -72,7 +72,7 @@ check_ino_index "$ino" "$dseq" "$T_M0" check_ino_index "$ino" "$dseq" "$T_M1" exec {FD}>&- # close # we know that revalidating will unhash the remote dentry -stat "$T_D0/file" 2>&1 | t_filter_fs +stat "$T_D0/file" 2>&1 | sed 's/cannot statx/cannot stat/' | t_filter_fs check_ino_index "$ino" "$dseq" "$T_M0" check_ino_index "$ino" "$dseq" "$T_M1" From 11c041d2ea553b8b9f8bd3381958c26b77f126d9 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 5 Jul 2023 14:58:52 -0400 Subject: [PATCH 39/46] New versions of getfattr will quote empty attr values. Instead of messing with quotes and using grep for the correct xattr name, directly query the value of the xattr being tested only, and compare that to the input. Side effect is that this is significantly simpler and faster. Signed-off-by: Auke Kok --- tests/tests/simple-xattr-unit.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/tests/simple-xattr-unit.sh b/tests/tests/simple-xattr-unit.sh index 31cc5878..b761f708 100644 --- a/tests/tests/simple-xattr-unit.sh +++ b/tests/tests/simple-xattr-unit.sh @@ -27,15 +27,9 @@ test_xattr_lengths() { echo "key len $name_len val len $val_len" >> "$T_TMP.log" setfattr -n $name -v \"$val\" "$FILE" - # grep has trouble with enormous args? so we dump the - # name=value to a file and compare with a known good file - getfattr -d --absolute-names "$FILE" | grep "$name" > "$T_TMP.got" + getfattr -d --only-values --absolute-names "$FILE" -n "$name" > "$T_TMP.got" + echo -n "$val" > "$T_TMP.good" - if [ $val_len == 0 ]; then - echo "$name" > "$T_TMP.good" - else - echo "$name=\"$val\"" > "$T_TMP.good" - fi cmp "$T_TMP.good" "$T_TMP.got" || \ t_fail "cmp failed name len $name_len val len $val_len" From 29160b0bc6dd0f9424ec437aa008956ba9011cdf Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 5 Jul 2023 18:17:18 -0400 Subject: [PATCH 40/46] Don't cache ACL's in newer kernels. The caller takes care of caching for us. Us doing caching messes with memory management of cached ACLs and breaks. Signed-off-by: Auke Kok --- kmod/src/acl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 9458f376..bfe81bc5 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -69,12 +69,14 @@ struct posix_acl *scoutfs_get_acl_locked(struct inode *inode, int type, struct s char *name; int ret; +#ifndef KC___POSIX_ACL_CREATE if (!IS_POSIXACL(inode)) return NULL; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; +#endif ret = acl_xattr_name_len(type, &name, NULL); if (ret < 0) @@ -96,9 +98,11 @@ struct posix_acl *scoutfs_get_acl_locked(struct inode *inode, int type, struct s acl = ERR_PTR(ret); } +#ifndef KC___POSIX_ACL_CREATE /* can set null negative cache */ if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); +#endif kfree(value); @@ -112,8 +116,10 @@ struct posix_acl *scoutfs_get_acl(struct inode *inode, int type) struct posix_acl *acl; int ret; +#ifndef KC___POSIX_ACL_CREATE if (!IS_POSIXACL(inode)) return NULL; +#endif ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, 0, inode, &lock); if (ret < 0) { @@ -188,8 +194,10 @@ int scoutfs_set_acl_locked(struct inode *inode, struct posix_acl *acl, int type, } out: +#ifndef KC___POSIX_ACL_CREATE if (!ret) set_cached_acl(inode, type, acl); +#endif kfree(value); From 592e3d471fb97e1e6af68caf5fb5271d5db563cf Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 10 Jul 2023 18:31:55 -0400 Subject: [PATCH 41/46] Use `.prefix` for POSIX acl instead of `.name`. New kernels expect to do a partial match when a .prefix is used here, and provide a .name member in case matching should look at the whole string. This is what we want. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 10 ++++++++++ kmod/src/xattr.c | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 55c5a256..352f2671 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -248,3 +248,13 @@ endif ifneq (,$(shell grep 'size_t.*ki_left;' include/linux/aio.h)) ccflags-y += -DKC_LINUX_AIO_KI_LEFT=1 endif + +# +# v4.4-rc4-4-g98e9cb5711c6 +# +# Introduces a new xattr_handler .name member that can be used to match the +# entire field, instead of just a prefix. For these kernels, we must use +# the new .name field instead. +ifneq (,$(shell grep 'static inline const char .xattr_prefix' include/linux/xattr.h)) +ccflags-y += -DKC_XATTR_HANDLER_NAME=1 +endif diff --git a/kmod/src/xattr.c b/kmod/src/xattr.c index da736ef5..fa418b8c 100644 --- a/kmod/src/xattr.c +++ b/kmod/src/xattr.c @@ -925,14 +925,22 @@ static const struct xattr_handler scoutfs_xattr_security_handler = { }; static const struct xattr_handler scoutfs_xattr_acl_access_handler = { +#ifdef KC_XATTR_HANDLER_NAME + .name = XATTR_NAME_POSIX_ACL_ACCESS, +#else .prefix = XATTR_NAME_POSIX_ACL_ACCESS, +#endif .flags = ACL_TYPE_ACCESS, .get = scoutfs_acl_get_xattr, .set = scoutfs_acl_set_xattr, }; static const struct xattr_handler scoutfs_xattr_acl_default_handler = { +#ifdef KC_XATTR_HANDLER_NAME + .name = XATTR_NAME_POSIX_ACL_DEFAULT, +#else .prefix = XATTR_NAME_POSIX_ACL_DEFAULT, +#endif .flags = ACL_TYPE_DEFAULT, .get = scoutfs_acl_get_xattr, .set = scoutfs_acl_set_xattr, From 819df4be60e37ce67b6b5bb8ea19cf74faa2e651 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 10 Jul 2023 18:33:31 -0400 Subject: [PATCH 42/46] Skip userns based testing for RHEL8. In RHEL7, this was skipped automatically. In RHEL8, we don't support the needed passing through of the actual user namespace into our ACL set/get handlers. Once we get around v5.11 or so, the handlers are automatically passed the namespace. Until then, skip this test. Signed-off-by: Auke Kok --- tests/golden/xfstests | 1 - tests/tests/xfstests.sh | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/golden/xfstests b/tests/golden/xfstests index cc382847..16824a05 100644 --- a/tests/golden/xfstests +++ b/tests/golden/xfstests @@ -241,7 +241,6 @@ generic/312 generic/314 generic/316 generic/317 -generic/318 generic/324 generic/326 generic/327 diff --git a/tests/tests/xfstests.sh b/tests/tests/xfstests.sh index 13349368..25e66bbe 100644 --- a/tests/tests/xfstests.sh +++ b/tests/tests/xfstests.sh @@ -75,6 +75,7 @@ generic/215 # mmap missing generic/246 # mmap missing generic/247 # mmap missing generic/248 # mmap missing +generic/318 # can't support user namespaces until v5.11 generic/321 # requires selinux enabled for '+' in ls? generic/325 # mmap missing generic/338 # BUG_ON update inode error handling From a7704e0b56cc5e40ff3b20055be78db20de71927 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 13 Jul 2023 16:59:45 -0400 Subject: [PATCH 43/46] Allow the kernel to return -ESTALE from orphan-inode test In newer kernels, we always get -ESTALE because the inode has been marked immediately as deleting. Since this is expected behavior we should not fail the test here on this error value. Signed-off-by: Auke Kok --- tests/src/handle_fsetxattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/handle_fsetxattr.c b/tests/src/handle_fsetxattr.c index 5d063552..b39d7db5 100644 --- a/tests/src/handle_fsetxattr.c +++ b/tests/src/handle_fsetxattr.c @@ -48,7 +48,7 @@ struct our_handle { static void exit_usage(void) { printf(" -h/-? output this usage message and exit\n" - " -e keep trying on enoent, consider success an error\n" + " -e keep trying on enoent and estale, consider success an error\n" " -i 64bit inode number for handle open, can be multiple\n" " -m scoutfs mount path string for ioctl fd\n" " -n optional xattr name string, defaults to \""DEFAULT_NAME"\"\n" @@ -149,7 +149,7 @@ int main(int argc, char **argv) fd = open_by_handle_at(mntfd, &handle.handle, O_RDWR); if (fd == -1) { - if (!enoent_success_err || errno != ENOENT) { + if (!enoent_success_err || ( errno != ENOENT && errno != ESTALE )) { perror("open_by_handle_at"); return 1; } From 293cee95543e2a3a81139e92bdc3f09afaa8c801 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 14 Jul 2023 13:13:40 -0400 Subject: [PATCH 44/46] Don't use static struct initializer. In rhel7 this is a nested struct with ktime_t. However, in rhel8 ktime_t is a simple s64, and not a union, and thus we can't do this as easily. Just memset it. Signed-off-by: Auke Kok --- kmod/src/quorum.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index 3395e5ee..88e5c07a 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -729,11 +729,13 @@ static void scoutfs_quorum_worker(struct work_struct *work) struct sockaddr_in unused; struct quorum_host_msg msg; struct quorum_status qst = {0,}; - struct hb_recording hbr = {{0,},}; + struct hb_recording hbr; bool record_hb; int ret; int err; + memset(&hbr, 0, sizeof(struct hb_recording)); + /* recording votes from slots as native single word bitmap */ BUILD_BUG_ON(SCOUTFS_QUORUM_MAX_SLOTS > BITS_PER_LONG); From 0e1e55d25b1551494950a1a4d6691d01fcb68672 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 14 Jul 2023 13:25:51 -0400 Subject: [PATCH 45/46] Ignore `last` flag output by filefrag. New versions of filefrag will output the presence of the `last` flag as well, but we don't care. Signed-off-by: Auke Kok --- tests/tests/data-prealloc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/data-prealloc.sh b/tests/tests/data-prealloc.sh index fdc09f8e..6c798246 100644 --- a/tests/tests/data-prealloc.sh +++ b/tests/tests/data-prealloc.sh @@ -95,7 +95,7 @@ print_logical_extents() } print $2, $6, flags } - ' + ' | sed 's/last,eof/eof/' } t_save_all_sysfs_mount_options data_prealloc_blocks From d2c2fece2ae9ab232c403a8434d9e584aae857b6 Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Thu, 10 Aug 2023 16:23:57 -0700 Subject: [PATCH 46/46] Add rpm spec file support for el8 builds The rpmbuild support files no longer define the previously used kernel module macros. This carves out the differences between el7 and el8 with conditionals based on the distro we are building for. Signed-off-by: Ben McClelland --- kmod/scoutfs-kmod.spec.in | 42 ++++++++++++++++++++++++++++++------- utils/scoutfs-utils.spec.in | 2 +- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/kmod/scoutfs-kmod.spec.in b/kmod/scoutfs-kmod.spec.in index ee1acf54..e9cfc2dc 100644 --- a/kmod/scoutfs-kmod.spec.in +++ b/kmod/scoutfs-kmod.spec.in @@ -3,16 +3,28 @@ %define kmod_git_hash @@GITHASH@@ %define pkg_date %(date +%%Y%%m%%d) +# Disable the building of the debug package(s). +%define debug_package %{nil} + # take kernel version or default to uname -r %{!?kversion: %global kversion %(uname -r)} %global kernel_version %{kversion} +%if 0%{?el7} %global kernel_source() /usr/src/kernels/%{kernel_version}.$(arch) -%global kernel_release() %{kversion} +%endif +%if 0%{?el8} +%global kernel_source() /usr/src/kernels/%{kernel_version} +%endif %{!?_release: %global _release 0.%{pkg_date}git%{kmod_git_hash}} +%if 0%{?el7} Name: %{kmod_name} +%endif +%if 0%{?el8} +Name: kmod-%{kmod_name} +%endif Summary: %{kmod_name} kernel module Version: %{kmod_version} Release: %{_release}%{?dist} @@ -20,24 +32,30 @@ License: GPLv2 Group: System/Kernel URL: http://scoutfs.org/ +%if 0%{?el7} BuildRequires: %{kernel_module_package_buildreqs} -BuildRequires: git +%endif +%if 0%{?el8} +BuildRequires: elfutils-libelf-devel +%endif BuildRequires: kernel-devel-uname-r = %{kernel_version} +BuildRequires: git BuildRequires: module-init-tools ExclusiveArch: x86_64 Source: %{kmod_name}-kmod-%{kmod_version}.tar +%if 0%{?el7} # Build only for standard kernel variant(s); for debug packages, append "debug" # after "default" (separated by space) %kernel_module_package default +%endif -# Disable the building of the debug package(s). -%define debug_package %{nil} - -%global install_mod_dir extra/%{name} - +%global install_mod_dir extra/%{kmod_name} +%if 0%{?el8} +%global flavors_to_build x86_64 +%endif %description %{kmod_name} - kernel module @@ -66,7 +84,7 @@ export INSTALL_MOD_DIR=%{install_mod_dir} mkdir -p %{install_mod_dir} for flavor in %{flavors_to_build}; do export KSRC=%{kernel_source $flavor} - export KVERSION=%{kernel_release $KSRC} + export KVERSION=%{kversion} install -d $INSTALL_MOD_PATH/lib/modules/$KVERSION/%{install_mod_dir} cp $PWD/obj/$flavor/src/scoutfs.ko $INSTALL_MOD_PATH/lib/modules/$KVERSION/%{install_mod_dir}/ done @@ -74,6 +92,14 @@ done # mark modules executable so that strip-to-file can strip them find %{buildroot} -type f -name \*.ko -exec %{__chmod} u+x \{\} \; +%if 0%{?el8} +%files +/lib/modules + +%post +weak-modules --add-kernel --no-initramfs +depmod -a +%endif %clean rm -rf %{buildroot} diff --git a/utils/scoutfs-utils.spec.in b/utils/scoutfs-utils.spec.in index 4568b73f..fb24b812 100644 --- a/utils/scoutfs-utils.spec.in +++ b/utils/scoutfs-utils.spec.in @@ -61,7 +61,7 @@ install -m 644 -D fenced/scoutfs-fenced.conf.example $RPM_BUILD_ROOT%{_sysconfdi %files %defattr(644,root,root,755) %{_mandir}/man*/scoutfs*.gz -%{_unitdir}/scoutfs-fenced.service +/%{_unitdir}/scoutfs-fenced.service %{_sysconfdir}/scoutfs %defattr(755,root,root,755) %{_sbindir}/scoutfs