From 40df1e078b61626f0f6d49ed2aedc59518b6600c Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 21 Apr 2025 13:47:22 -0700 Subject: [PATCH 01/23] prandom_bytes and family removed, switch to get_random_bytes variants. In v6.1-rc5-2-ge9a688bcb193, get_random_u32_below() becomes available and can start replacing prandom_bytes_max(). Switch to it where we can. get_random_bytes() has been available since el7, so also replace prandom_bytes() where we're using it. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 8 ++++++++ kmod/src/block.c | 2 +- kmod/src/inode.c | 2 +- kmod/src/kernelcompat.h | 4 ++++ kmod/src/quorum.c | 2 +- kmod/src/quota.c | 2 +- 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 81dc8a586..911e70deb 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -496,3 +496,11 @@ endif ifneq (,$(shell grep 'struct posix_acl.*get_inode_acl' include/linux/fs.h)) ccflags-y += -DKC_GET_INODE_ACL endif + +# +# v6.1-rc5-2-ge9a688bcb193 +# +# get_random_u32_below() implementation +ifneq (,$(shell grep 'u32 get_random_u32_below' include/linux/random.h)) +ccflags-y += -DKC_HAVE_GET_RANDOM_U32_BELOW +endif diff --git a/kmod/src/block.c b/kmod/src/block.c index 463e1b015..a9a95d822 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -884,7 +884,7 @@ int scoutfs_block_dirty_ref(struct super_block *sb, struct scoutfs_alloc *alloc, hdr->magic = cpu_to_le32(magic); hdr->fsid = cpu_to_le64(sbi->fsid); hdr->blkno = cpu_to_le64(bl->blkno); - prandom_bytes(&hdr->seq, sizeof(hdr->seq)); + get_random_bytes(&hdr->seq, sizeof(hdr->seq)); trace_scoutfs_block_dirty_ref(sb, le64_to_cpu(ref->blkno), le64_to_cpu(ref->seq), le64_to_cpu(hdr->blkno), le64_to_cpu(hdr->seq)); diff --git a/kmod/src/inode.c b/kmod/src/inode.c index a4d118f14..e34587287 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -2068,7 +2068,7 @@ void scoutfs_inode_schedule_orphan_dwork(struct super_block *sb) low = (opts.orphan_scan_delay_ms * 80) / 100; high = (opts.orphan_scan_delay_ms * 120) / 100; - delay = msecs_to_jiffies(low + prandom_u32_max(high - low)) ?: 1; + delay = msecs_to_jiffies(low + get_random_u32_below(high - low)) ?: 1; mod_delayed_work(system_wq, &inf->orphan_scan_dwork, delay); } diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 5564a12a2..9f6fd2b4a 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -489,4 +489,8 @@ static inline void stack_trace_print(unsigned long *entries, unsigned int nr_ent } #endif +#ifndef KC_HAVE_GET_RANDOM_U32_BELOW +#define get_random_u32_below prandom_u32_max +#endif + #endif diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index 242804ed9..54615c52e 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -162,7 +162,7 @@ static void quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, struct s static ktime_t election_timeout(void) { return ktime_add_ms(ktime_get(), SCOUTFS_QUORUM_ELECT_MIN_MS + - prandom_u32_max(SCOUTFS_QUORUM_ELECT_VAR_MS)); + get_random_u32_below(SCOUTFS_QUORUM_ELECT_VAR_MS)); } static ktime_t heartbeat_interval(void) diff --git a/kmod/src/quota.c b/kmod/src/quota.c index 3163ee8c9..9f331325a 100644 --- a/kmod/src/quota.c +++ b/kmod/src/quota.c @@ -204,7 +204,7 @@ static struct squota_check *lookup_random_check(struct rhashtable *rht) tbl = rht_dereference_rcu(rht->tbl, rht); do { - for (s = 0, i = prandom_u32_max(tbl->size); + for (s = 0, i = get_random_u32_below(tbl->size); s < tbl->size; s++, i = (i + 1) % tbl->size) { rht_for_each_entry_rcu(chk, pos, tbl, i, head) { From 8a953c9ba3f89202cf70de0fa284f1954a092318 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 18 Apr 2025 14:11:56 -0400 Subject: [PATCH 02/23] Stop using egrep. egrep Is no longer in el10, so replace it with `grep -E` everywhere. Signed-off-by: Auke Kok --- kmod/src/Makefile | 4 ++-- tests/funcs/filter.sh | 2 +- utils/sparse.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kmod/src/Makefile b/kmod/src/Makefile index fa632aa10..9aea45711 100644 --- a/kmod/src/Makefile +++ b/kmod/src/Makefile @@ -60,11 +60,11 @@ scoutfs-y += \ # .PHONY: $(src)/check_exported_types $(src)/check_exported_types: - @if egrep '\<[us](8|16|32|64\>)' $(src)/format.h $(src)/ioctl.h; then \ + @if grep -E '\<[us](8|16|32|64\>)' $(src)/format.h $(src)/ioctl.h; then \ echo "no raw types in exported headers, preface with __"; \ exit 1; \ fi - @if egrep '\<__packed\>' $(src)/format.h $(src)/ioctl.h; then \ + @if grep -E '\<__packed\>' $(src)/format.h $(src)/ioctl.h; then \ echo "no __packed allowed in exported headers"; \ exit 1; \ fi diff --git a/tests/funcs/filter.sh b/tests/funcs/filter.sh index 3dc593c80..fdaf92fe6 100644 --- a/tests/funcs/filter.sh +++ b/tests/funcs/filter.sh @@ -173,6 +173,6 @@ t_filter_dmesg() # creating block devices may trigger this re="$re|block device autoloading is deprecated and will be removed." - egrep -v "($re)" | \ + grep -v -E "($re)" | \ ignore_harmless_unwind_kasan_stack_oob } diff --git a/utils/sparse.sh b/utils/sparse.sh index adef573b4..a31b36307 100755 --- a/utils/sparse.sh +++ b/utils/sparse.sh @@ -71,7 +71,7 @@ else m64="" fi -sparse $m64 $include $search/include "$@" 2>&1 | egrep -v "($RE)" | tee .sparse.output +sparse $m64 $include $search/include "$@" 2>&1 | grep -v -E "($RE)" | tee .sparse.output rm -f $defines From 85e3424a630609b1f31620c60ecc056568359ae8 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 21 Apr 2025 10:33:56 -0700 Subject: [PATCH 03/23] Use a/m/c_time accessor functions. In v6.6-rc5-1-g077c212f0344, one can no longer directly access the inode m_time and a_time etc. We have to go through these static inline functions to get to them. The compat is matched closely to mimic the new functions. Further back, ctime accessors were added in v6.5-rc1-7-g9b6304c1d537, and need to be applied as well. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 15 ++++++ kmod/src/acl.c | 2 +- kmod/src/attr_x.c | 10 ++-- kmod/src/data.c | 6 ++- kmod/src/dir.c | 53 ++++++++++++------- kmod/src/inode.c | 32 +++++++----- kmod/src/kernelcompat.c | 10 ++++ kmod/src/kernelcompat.h | 95 ++++++++++++++++++++++++++++++++++ kmod/src/xattr.c | 2 +- 9 files changed, 182 insertions(+), 43 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 911e70deb..4f2546292 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -504,3 +504,18 @@ endif ifneq (,$(shell grep 'u32 get_random_u32_below' include/linux/random.h)) ccflags-y += -DKC_HAVE_GET_RANDOM_U32_BELOW endif + +# v6.5-rc1-7-g9b6304c1d537 +# +# ctime accessor methods +ifneq (,$(shell grep 'timespec64 inode_set_ctime_current' include/linux/fs.h)) +ccflags-y += -DKC_FS_INODE_C_TIME_ACCESSOR +endif + +# +# v6.6-rc5-1-g077c212f0344 +# +# Must use access methods from fs.h to get to inode ctime/mtime/atime +ifneq (,$(shell grep 'inline time64_t inode_get_atime_sec' include/linux/fs.h)) +ccflags-y += -DKC_FS_INODE_AM_TIME_ACCESSOR +endif diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 356e31070..be1aed4e8 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -197,7 +197,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); + inode_set_ctime_current(inode); } } diff --git a/kmod/src/attr_x.c b/kmod/src/attr_x.c index 39e84a36e..409c9c799 100644 --- a/kmod/src/attr_x.c +++ b/kmod/src/attr_x.c @@ -103,8 +103,8 @@ int scoutfs_get_attr_x(struct inode *inode, struct scoutfs_ioctl_inode_attr_x *i size = fill_attr(size, iax, SCOUTFS_IOC_IAX_OFFLINE_BLOCKS, offline_blocks, offline); } - size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_sec, inode->i_ctime.tv_sec); - size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_nsec, inode->i_ctime.tv_nsec); + size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_sec, inode_get_ctime_sec(inode)); + size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_nsec, inode_get_ctime_nsec(inode)); size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CRTIME, crtime_sec, si->crtime.tv_sec); size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CRTIME, crtime_nsec, si->crtime.tv_nsec); size = fill_attr(size, iax, SCOUTFS_IOC_IAX_SIZE, size, i_size_read(inode)); @@ -223,10 +223,8 @@ int scoutfs_set_attr_x(struct inode *inode, struct scoutfs_ioctl_inode_attr_x *i scoutfs_inode_set_data_version(inode, iax->data_version); if (iax->x_mask & SCOUTFS_IOC_IAX_SIZE) i_size_write(inode, iax->size); - if (iax->x_mask & SCOUTFS_IOC_IAX_CTIME) { - inode->i_ctime.tv_sec = iax->ctime_sec; - inode->i_ctime.tv_nsec = iax->ctime_nsec; - } + if (iax->x_mask & SCOUTFS_IOC_IAX_CTIME) + inode_set_ctime(inode, iax->ctime_sec, iax->ctime_nsec); if (iax->x_mask & SCOUTFS_IOC_IAX_CRTIME) { si->crtime.tv_sec = iax->crtime_sec; si->crtime.tv_nsec = iax->crtime_nsec; diff --git a/kmod/src/data.c b/kmod/src/data.c index 7903e8d78..9c164542f 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -1483,12 +1483,14 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off, cur_time = current_time(from); if (!is_stage) { - to->i_ctime = to->i_mtime = cur_time; + inode_set_ctime_to_ts(to, cur_time); + inode_set_mtime_to_ts(to, cur_time); inode_inc_iversion(to); scoutfs_inode_inc_data_version(to); scoutfs_inode_set_data_seq(to); } - from->i_ctime = from->i_mtime = cur_time; + inode_set_ctime_to_ts(from, cur_time); + inode_set_mtime_to_ts(from, cur_time); inode_inc_iversion(from); scoutfs_inode_inc_data_version(from); scoutfs_inode_set_data_seq(from); diff --git a/kmod/src/dir.c b/kmod/src/dir.c index d2343e58a..1199d13a4 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -759,6 +759,7 @@ static int scoutfs_mknod(KC_VFS_NS_DEF struct scoutfs_lock *dir_lock = NULL; struct scoutfs_lock *inode_lock = NULL; struct scoutfs_inode_info *si; + struct kc_timespec cur_time; LIST_HEAD(ind_locks); u64 hash; u64 pos; @@ -790,9 +791,13 @@ static int scoutfs_mknod(KC_VFS_NS_DEF 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(inode); - inode->i_mtime = inode->i_atime = inode->i_ctime = dir->i_mtime; - si->crtime = inode->i_mtime; + cur_time = current_time(inode); + inode_set_mtime_to_ts(dir, cur_time); + inode_set_ctime_to_ts(dir, cur_time); + inode_set_mtime_to_ts(inode, cur_time); + inode_set_atime_to_ts(inode, cur_time); + inode_set_ctime_to_ts(inode, cur_time); + si->crtime = inode_get_mtime(inode); inode_inc_iversion(dir); inode_inc_iversion(inode); scoutfs_forest_inc_inode_count(sb); @@ -845,6 +850,7 @@ static int scoutfs_link(struct dentry *old_dentry, struct scoutfs_lock *dir_lock; struct scoutfs_lock *inode_lock = NULL; struct scoutfs_lock *orph_lock = NULL; + struct kc_timespec cur_time; LIST_HEAD(ind_locks); bool del_orphan = false; u64 dir_size; @@ -919,8 +925,10 @@ static int scoutfs_link(struct dentry *old_dentry, set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, dir_size); - dir->i_mtime = dir->i_ctime = current_time(inode); - inode->i_ctime = dir->i_mtime; + cur_time = current_time(inode); + inode_set_mtime_to_ts(dir, cur_time); + inode_set_ctime_to_ts(dir, cur_time); + inode_set_ctime_to_ts(inode, inode_get_mtime(dir)); inc_nlink(inode); inode_inc_iversion(dir); inode_inc_iversion(inode); @@ -1030,13 +1038,13 @@ static int scoutfs_unlink(struct inode *dir, struct dentry *dentry) set_dentry_fsdata(dentry, dir_lock); - dir->i_ctime = ts; - dir->i_mtime = ts; + inode_set_ctime_to_ts(dir, ts); + inode_set_mtime_to_ts(dir, ts); i_size_write(dir, i_size_read(dir) - dentry->d_name.len); inode_inc_iversion(dir); inode_inc_iversion(inode); - inode->i_ctime = ts; + inode_set_ctime_to_ts(inode, ts); drop_nlink(inode); if (S_ISDIR(inode->i_mode)) { drop_nlink(dir); @@ -1239,6 +1247,7 @@ static int scoutfs_symlink(KC_VFS_NS_DEF struct scoutfs_lock *dir_lock = NULL; struct scoutfs_lock *inode_lock = NULL; struct scoutfs_inode_info *si; + struct kc_timespec cur_time; LIST_HEAD(ind_locks); u64 hash; u64 pos; @@ -1278,11 +1287,13 @@ static int scoutfs_symlink(KC_VFS_NS_DEF 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(inode); + cur_time = current_time(inode); + inode_set_mtime_to_ts(dir, cur_time); + inode_set_ctime_to_ts(dir, cur_time); inode_inc_iversion(dir); - inode->i_ctime = dir->i_mtime; - si->crtime = inode->i_ctime; + inode_set_ctime_to_ts(inode, inode_get_mtime(dir)); + si->crtime = inode_get_ctime(inode); i_size_write(inode, name_len); inode_inc_iversion(inode); scoutfs_forest_inc_inode_count(sb); @@ -1804,15 +1815,15 @@ static int scoutfs_rename_common(KC_VFS_NS_DEF } now = current_time(old_inode); - old_dir->i_ctime = now; - old_dir->i_mtime = now; + inode_set_ctime_to_ts(old_dir, now); + inode_set_mtime_to_ts(old_dir, now); if (new_dir != old_dir) { - new_dir->i_ctime = now; - new_dir->i_mtime = now; + inode_set_ctime_to_ts(new_dir, now); + inode_set_mtime_to_ts(new_dir, now); } - old_inode->i_ctime = now; + inode_set_ctime_to_ts(old_inode, now); if (new_inode) - new_inode->i_ctime = now; + inode_set_ctime_to_ts(new_inode, now); inode_inc_iversion(old_dir); inode_inc_iversion(old_inode); @@ -1939,6 +1950,7 @@ static int scoutfs_tmpfile(KC_VFS_NS_DEF struct scoutfs_lock *inode_lock = NULL; struct scoutfs_lock *orph_lock = NULL; struct scoutfs_inode_info *si; + struct kc_timespec cur_time; LIST_HEAD(ind_locks); int ret; @@ -1955,8 +1967,11 @@ static int scoutfs_tmpfile(KC_VFS_NS_DEF if (ret < 0) goto out; /* XXX returning error but items created */ - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - si->crtime = inode->i_mtime; + cur_time = current_time(inode); + inode_set_mtime_to_ts(inode, cur_time); + inode_set_ctime_to_ts(inode, cur_time); + inode_set_atime_to_ts(inode, cur_time); + si->crtime = inode_get_mtime(inode); insert_inode_hash(inode); ihold(inode); /* need to update inode modifications in d_tmpfile */ #ifdef KC_D_TMPFILE_DENTRY diff --git a/kmod/src/inode.c b/kmod/src/inode.c index e34587287..6ee0861fb 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -275,12 +275,9 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode, int in i_gid_write(inode, le32_to_cpu(cinode->gid)); inode->i_mode = le32_to_cpu(cinode->mode); inode->i_rdev = le32_to_cpu(cinode->rdev); - inode->i_atime.tv_sec = le64_to_cpu(cinode->atime.sec); - inode->i_atime.tv_nsec = le32_to_cpu(cinode->atime.nsec); - inode->i_mtime.tv_sec = le64_to_cpu(cinode->mtime.sec); - inode->i_mtime.tv_nsec = le32_to_cpu(cinode->mtime.nsec); - inode->i_ctime.tv_sec = le64_to_cpu(cinode->ctime.sec); - inode->i_ctime.tv_nsec = le32_to_cpu(cinode->ctime.nsec); + inode_set_atime(inode, le64_to_cpu(cinode->atime.sec), le32_to_cpu(cinode->atime.nsec)); + inode_set_mtime(inode, le64_to_cpu(cinode->mtime.sec), le32_to_cpu(cinode->mtime.nsec)); + inode_set_ctime(inode, le64_to_cpu(cinode->ctime.sec), le32_to_cpu(cinode->ctime.nsec)); si->meta_seq = le64_to_cpu(cinode->meta_seq); si->data_seq = le64_to_cpu(cinode->data_seq); @@ -412,6 +409,7 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock, { struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; + struct kc_timespec cur_time; SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); LIST_HEAD(ind_locks); int ret; @@ -434,7 +432,9 @@ 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); + cur_time = current_time(inode); + inode_set_ctime_to_ts(inode, cur_time); + inode_set_mtime_to_ts(inode, cur_time); if (truncate) si->flags |= SCOUTFS_INO_FLAG_TRUNCATE; scoutfs_inode_set_data_seq(inode); @@ -901,14 +901,14 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode, int i cinode->gid = cpu_to_le32(i_gid_read(inode)); cinode->mode = cpu_to_le32(inode->i_mode); cinode->rdev = cpu_to_le32(inode->i_rdev); - cinode->atime.sec = cpu_to_le64(inode->i_atime.tv_sec); - cinode->atime.nsec = cpu_to_le32(inode->i_atime.tv_nsec); + cinode->atime.sec = cpu_to_le64(inode_get_atime_sec(inode)); + cinode->atime.nsec = cpu_to_le32(inode_get_atime_nsec(inode)); memset(cinode->atime.__pad, 0, sizeof(cinode->atime.__pad)); - cinode->ctime.sec = cpu_to_le64(inode->i_ctime.tv_sec); - cinode->ctime.nsec = cpu_to_le32(inode->i_ctime.tv_nsec); + cinode->ctime.sec = cpu_to_le64(inode_get_ctime_sec(inode)); + cinode->ctime.nsec = cpu_to_le32(inode_get_ctime_nsec(inode)); memset(cinode->ctime.__pad, 0, sizeof(cinode->ctime.__pad)); - cinode->mtime.sec = cpu_to_le64(inode->i_mtime.tv_sec); - cinode->mtime.nsec = cpu_to_le32(inode->i_mtime.tv_nsec); + cinode->mtime.sec = cpu_to_le64(inode_get_mtime_sec(inode)); + cinode->mtime.nsec = cpu_to_le32(inode_get_mtime_nsec(inode)); memset(cinode->mtime.__pad, 0, sizeof(cinode->mtime.__pad)); cinode->meta_seq = cpu_to_le64(scoutfs_inode_meta_seq(inode)); @@ -1566,6 +1566,7 @@ int scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, d struct scoutfs_inode sinode; struct scoutfs_key key; struct inode *inode; + struct kc_timespec cur_time; int inode_bytes; int ret; @@ -1595,7 +1596,10 @@ int scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, d inode_init_owner(KC_VFS_INIT_NS inode, dir, mode); inode_set_bytes(inode, 0); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + cur_time = current_time(inode); + inode_set_mtime_to_ts(inode, cur_time); + inode_set_atime_to_ts(inode, cur_time); + inode_set_ctime_to_ts(inode, cur_time); inode->i_rdev = rdev; set_inode_ops(inode); diff --git a/kmod/src/kernelcompat.c b/kmod/src/kernelcompat.c index 2463d1341..fc5e895c1 100644 --- a/kmod/src/kernelcompat.c +++ b/kmod/src/kernelcompat.c @@ -147,3 +147,13 @@ unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_contro } #endif + +#ifndef KC_FS_INODE_C_TIME_ACCESSOR +struct timespec64 inode_set_ctime_current(struct inode *inode) +{ + struct timespec64 now = current_time(inode); + + inode_set_ctime(inode, now.tv_sec, now.tv_nsec); + return now; +} +#endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 9f6fd2b4a..c91255d2b 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -493,4 +493,99 @@ static inline void stack_trace_print(unsigned long *entries, unsigned int nr_ent #define get_random_u32_below prandom_u32_max #endif +#ifndef KC_FS_INODE_C_TIME_ACCESSOR +struct timespec64 inode_set_ctime_current(struct inode *inode); +static inline struct timespec64 inode_set_ctime_to_ts(struct inode *inode, + struct timespec64 ts) +{ + inode->i_ctime.tv_sec = ts.tv_sec; + inode->i_ctime.tv_nsec = ts.tv_nsec; + return ts; +} + +static inline struct timespec64 inode_set_ctime(struct inode *inode, + time64_t sec, long nsec) +{ + struct timespec64 ts = { .tv_sec = sec, + .tv_nsec = nsec }; + + return inode_set_ctime_to_ts(inode, ts); +} + +static inline struct timespec64 inode_get_ctime(const struct inode *inode) +{ + struct timespec64 ts = { .tv_sec = inode->i_ctime.tv_sec, + .tv_nsec = inode->i_ctime.tv_nsec }; + return ts; +} +#endif + +#ifndef KC_FS_INODE_AM_TIME_ACCESSOR +static inline struct timespec64 inode_get_mtime(const struct inode *inode) +{ + struct timespec64 ts = { .tv_sec = inode->i_mtime.tv_sec, + .tv_nsec = inode->i_mtime.tv_nsec }; + return ts; +} + +static inline struct timespec64 inode_set_mtime_to_ts(struct inode *inode, + struct timespec64 ts) +{ + inode->i_mtime.tv_sec = ts.tv_sec; + inode->i_mtime.tv_nsec = ts.tv_nsec; + return ts; +} + +static inline struct timespec64 inode_set_mtime(struct inode *inode, + time64_t sec, long nsec) +{ + struct timespec64 ts = { .tv_sec = sec, + .tv_nsec = nsec }; + + return inode_set_mtime_to_ts(inode, ts); +} + +static inline struct timespec64 inode_set_atime_to_ts(struct inode *inode, + struct timespec64 ts) +{ + inode->i_atime.tv_sec = ts.tv_sec; + inode->i_atime.tv_nsec = ts.tv_nsec; + return ts; +} + +static inline struct timespec64 inode_set_atime(struct inode *inode, + time64_t sec, long nsec) +{ + struct timespec64 ts = { .tv_sec = sec, + .tv_nsec = nsec }; + + return inode_set_atime_to_ts(inode, ts); +} + +static inline time64_t inode_get_ctime_sec(const struct inode *inode) +{ + return inode->i_ctime.tv_sec; +} +static inline long inode_get_ctime_nsec(const struct inode *inode) +{ + return inode->i_ctime.tv_nsec; +} +static inline time64_t inode_get_mtime_sec(const struct inode *inode) +{ + return inode->i_mtime.tv_sec; +} +static inline long inode_get_mtime_nsec(const struct inode *inode) +{ + return inode->i_mtime.tv_nsec; +} +static inline time64_t inode_get_atime_sec(const struct inode *inode) +{ + return inode->i_atime.tv_sec; +} +static inline long inode_get_atime_nsec(const struct inode *inode) +{ + return inode->i_atime.tv_nsec; +} +#endif + #endif diff --git a/kmod/src/xattr.c b/kmod/src/xattr.c index 7805b3643..d6235ea5b 100644 --- a/kmod/src/xattr.c +++ b/kmod/src/xattr.c @@ -907,7 +907,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); + inode_set_ctime_to_ts(inode, current_time(inode)); ret = 0; out: From a455d089e55787a4cea34cc25c725d88e17c4f9b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 21 Apr 2025 22:28:16 -0400 Subject: [PATCH 04/23] Fix el10 not skipping the format-version-forward-back test. The logic only accounted for single-digit versions. With el10, that breaks. Signed-off-by: Auke Kok --- tests/tests/format-version-forward-back.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests/format-version-forward-back.sh b/tests/tests/format-version-forward-back.sh index d907ef493..ed5543c1d 100644 --- a/tests/tests/format-version-forward-back.sh +++ b/tests/tests/format-version-forward-back.sh @@ -11,8 +11,8 @@ # format version. # -# not supported on el8 or higher -if [ $(source /etc/os-release ; echo ${VERSION_ID:0:1}) -gt 7 ]; then +# not supported on el8, or higher versions. +if [ $(source /etc/os-release ; echo ${VERSION_ID} | cut -d. -f1) -gt 7 ]; then t_skip_permitted "Unsupported OS version" fi From c63b3188c3223170e24102b414da8d9f56aac1a4 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 21 Apr 2025 22:30:38 -0400 Subject: [PATCH 05/23] Account for difference in `stat` output format for device nodes. The new format in el10 has non-hex output, separated by a comma. Add the additional filter string so this works as expected. Signed-off-by: Auke Kok --- tests/funcs/filter.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/funcs/filter.sh b/tests/funcs/filter.sh index fdaf92fe6..44f965fe2 100644 --- a/tests/funcs/filter.sh +++ b/tests/funcs/filter.sh @@ -3,7 +3,8 @@ t_filter_fs() { sed -e 's@mnt/test\.[0-9]*@mnt/test@g' \ - -e 's@Device: [a-fA-F0-9]*h/[0-9]*d@Device: 0h/0d@g' + -e 's@Device: [a-fA-F0-9]*h/[0-9]*d@Device: 0h/0d@g' \ + -e 's@Device: [0-9]*,[0-9]*@Device: 0h/0d@g' } # From 34a78ae4a68e6889e0b46912d5acad84e99741e5 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 21 Apr 2025 22:47:42 -0400 Subject: [PATCH 06/23] unaligned.h moved from asm/ to linux/ In v6.12-rc1-3-g5f60d5f6bbc1, asm/unaligned.h only included asm-generic/unaligned.h and that was cleaned up from architecture specific things. Everyone should now include linux/unaligned.h and the former include was removed. A quick peek at server.c shows that while included, it no longer uses any function from this header at all, so it can just be dropped. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 8 ++++++++ kmod/src/server.c | 1 - kmod/src/srch.c | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 4f2546292..2470d064f 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -519,3 +519,11 @@ endif ifneq (,$(shell grep 'inline time64_t inode_get_atime_sec' include/linux/fs.h)) ccflags-y += -DKC_FS_INODE_AM_TIME_ACCESSOR endif + +# +# v6.12-rc1-3-g5f60d5f6bbc1 +# +# asm/unaligned.h replaced with linux/unaligned.h +ifneq (,$(shell grep -s 'define __LINUX_UNALIGNED_H' include/linux/unaligned.h)) +ccflags-y += -DKC_HAVE__LINUX_UNALIGNED_H +endif diff --git a/kmod/src/server.c b/kmod/src/server.c index 7f979df72..cb5727b87 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "format.h" #include "counters.h" diff --git a/kmod/src/srch.c b/kmod/src/srch.c index e1b5fb90c..d6ffc10fd 100644 --- a/kmod/src/srch.c +++ b/kmod/src/srch.c @@ -18,7 +18,11 @@ #include #include #include +#ifdef KC_HAVE__LINUX_UNALIGNED_H +#include +#else #include +#endif #include "super.h" #include "format.h" From b1bef1b7f5c6b10094679006017024772c541b92 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 21 Apr 2025 23:04:18 -0400 Subject: [PATCH 07/23] Fix compiler warnings for flex array definitions. Instead of defining a struct that ends with a flex array member with `val[0]`, the compiler now balks at this since technically, the spec considers this unsanitary. As a result however, we can't memcpy to `struct->val` since that's a pointer and now we're writing something of a different length (u8's in our case) into something that's of pointer size. So there we have to do the opposite, and memcpy to &struct->val[0]. Signed-off-by: Auke Kok --- kmod/src/btree.c | 4 ++-- kmod/src/btree.h | 2 +- kmod/src/item.c | 8 ++++---- kmod/src/wkic.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kmod/src/btree.c b/kmod/src/btree.c index 7a21afc72..c6baa3be2 100644 --- a/kmod/src/btree.c +++ b/kmod/src/btree.c @@ -2042,7 +2042,7 @@ struct merged_item { u64 seq; u8 flags; unsigned int val_len; - u8 val[0]; + u8 val[]; }; static inline struct merged_item *mitem_container(struct rb_node *node) @@ -2208,7 +2208,7 @@ static int merge_read_item(struct super_block *sb, struct scoutfs_key *key, u64 mitem->flags = flags; mitem->val_len = val_len; if (val_len) - memcpy(mitem->val, val, val_len); + memcpy(&mitem->val[0], val, val_len); if (found) { replace_mitem(rng, found, mitem); diff --git a/kmod/src/btree.h b/kmod/src/btree.h index 8656dd654..065c190e9 100644 --- a/kmod/src/btree.h +++ b/kmod/src/btree.h @@ -30,7 +30,7 @@ struct scoutfs_btree_item_list { u64 seq; u8 flags; int val_len; - u8 val[0]; + u8 val[]; }; int scoutfs_btree_lookup(struct super_block *sb, diff --git a/kmod/src/item.c b/kmod/src/item.c index e0047be48..bbd6878dd 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -146,7 +146,7 @@ struct cached_item { unsigned int val_len; struct scoutfs_key key; u64 seq; - char val[0]; + char val[]; }; #define CACHED_ITEM_ALIGN 8 @@ -424,7 +424,7 @@ static struct cached_item *alloc_item(struct cached_page *pg, item->seq = seq; if (val_len) - memcpy(item->val, val, val_len); + memcpy(&item->val[0], val, val_len); update_pg_max_seq(pg, item); @@ -1999,7 +1999,7 @@ int scoutfs_item_update(struct super_block *sb, struct scoutfs_key *key, if (val_len <= found->val_len) { if (val_len) - memcpy(found->val, val, val_len); + memcpy(&found->val[0], val, val_len); if (val_len < found->val_len) pg->erased_bytes += item_val_bytes(found->val_len) - item_val_bytes(val_len); @@ -2316,7 +2316,7 @@ int scoutfs_item_write_dirty(struct super_block *sb) lst->seq = item->seq; lst->flags = item->deletion ? SCOUTFS_ITEM_FLAG_DELETION : 0; lst->val_len = item->val_len; - memcpy(lst->val, item->val, item->val_len); + memcpy(&lst->val[0], item->val, item->val_len); } spin_lock(&cinf->dirty_lock); diff --git a/kmod/src/wkic.c b/kmod/src/wkic.c index 44eef494c..0dc476f4c 100644 --- a/kmod/src/wkic.c +++ b/kmod/src/wkic.c @@ -171,7 +171,7 @@ struct wkic_item { u64 seq; unsigned int val_len; u8 flags; - u8 val[0] __aligned(ARCH_KMALLOC_MINALIGN); /* totls have native structs */ + u8 val[] __aligned(ARCH_KMALLOC_MINALIGN); /* totls have native structs */ }; static struct wkic_item *witem_container(struct rb_node *node) @@ -763,7 +763,7 @@ static void fill_page_items(struct super_block *sb, struct wkic_page *wpage, str pg_item->val_len = witem->val_len; pg_item->flags = witem->flags; if (witem->val_len) - memcpy(pg_item->val, witem->val, witem->val_len); + memcpy(&pg_item->val[0], witem->val, witem->val_len); /* always inserting greatest item into page */ rb_link_node(&pg_item->node, parent, node); From 4c4a9c154d32fcf4bc0000651aad90930c72ac1f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 22 Apr 2025 14:41:21 -0400 Subject: [PATCH 08/23] RIP bd_inode. v6.9-rc4-29-g203c1ce0bb06 removes bd_inode. The canonical replacement is bd_mapping->host, were applicable. We have one use where we directly need the mapping instead of the inode, as well. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 8 ++++++++ kmod/src/alloc.c | 4 ++-- kmod/src/kernelcompat.h | 8 ++++++++ kmod/src/server.c | 2 +- kmod/src/super.c | 4 ++-- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 2470d064f..6be0ecf4f 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -527,3 +527,11 @@ endif ifneq (,$(shell grep -s 'define __LINUX_UNALIGNED_H' include/linux/unaligned.h)) ccflags-y += -DKC_HAVE__LINUX_UNALIGNED_H endif + +# +# v6.9-rc4-29-g203c1ce0bb06 +# +# RIP bd_inode. (note, struct moved between headers!) +ifneq (,$(shell grep -s 'struct inode.*bd_inode' include/linux/blk_types.h include/linux/fs.h)) +ccflags-y += -DKC_HAVE_BD_INODE +endif diff --git a/kmod/src/alloc.c b/kmod/src/alloc.c index 0ceaf3b8b..21cbebda0 100644 --- a/kmod/src/alloc.c +++ b/kmod/src/alloc.c @@ -308,14 +308,14 @@ static bool invalid_extent(u64 start, u64 end, u64 first, u64 last) static bool invalid_meta_blkno(struct super_block *sb, u64 blkno) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - u64 last_meta = (i_size_read(sbi->meta_bdev->bd_inode) >> SCOUTFS_BLOCK_LG_SHIFT) - 1; + u64 last_meta = (i_size_read(KC_BDEV_INODE(sbi->meta_bdev)) >> SCOUTFS_BLOCK_LG_SHIFT) - 1; return invalid_extent(blkno, blkno, SCOUTFS_META_DEV_START_BLKNO, last_meta); } static bool invalid_data_extent(struct super_block *sb, u64 start, u64 len) { - u64 last_data = (i_size_read(sb->s_bdev->bd_inode) >> SCOUTFS_BLOCK_SM_SHIFT) - 1; + u64 last_data = (i_size_read(KC_BDEV_INODE(sb->s_bdev)) >> SCOUTFS_BLOCK_SM_SHIFT) - 1; return invalid_extent(start, start + len - 1, SCOUTFS_DATA_DEV_START_BLKNO, last_data); } diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index c91255d2b..e00440b01 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -588,4 +588,12 @@ static inline long inode_get_atime_nsec(const struct inode *inode) } #endif +#ifdef KC_HAVE_BD_INODE +#define KC_BDEV_INODE(b) (b)->bd_inode +#define KC_BDEV_MAPPING(b) (b)->bd_inode->i_mapping +#else +#define KC_BDEV_INODE(b) (b)->bd_mapping->host +#define KC_BDEV_MAPPING(b) (b)->bd_mapping +#endif + #endif diff --git a/kmod/src/server.c b/kmod/src/server.c index cb5727b87..7df995605 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -3371,7 +3371,7 @@ static int server_clear_volopt(struct super_block *sb, struct scoutfs_net_connec static u64 device_blocks(struct block_device *bdev, int shift) { - return i_size_read(bdev->bd_inode) >> shift; + return i_size_read(KC_BDEV_INODE(bdev)) >> shift; } static int server_resize_devices(struct super_block *sb, struct scoutfs_net_connection *conn, diff --git a/kmod/src/super.c b/kmod/src/super.c index 3c8371608..0c5fce685 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -283,7 +283,7 @@ int scoutfs_write_super(struct super_block *sb, static bool small_bdev(struct super_block *sb, char *which, u64 blocks, struct block_device *bdev, int shift) { - u64 size = (u64)i_size_read(bdev->bd_inode); + u64 size = (u64)i_size_read(KC_BDEV_INODE(bdev)); u64 count = size >> shift; if (blocks > count) { @@ -508,7 +508,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; /* btree blocks use long lived bh->b_data refs */ - mapping_set_gfp_mask(sb->s_bdev->bd_inode->i_mapping, GFP_NOFS); + mapping_set_gfp_mask(KC_BDEV_MAPPING(sb->s_bdev), GFP_NOFS); sbi = kzalloc(sizeof(struct scoutfs_sb_info), GFP_KERNEL); sb->s_fs_info = sbi; From 5f2f8f199b3f664180a4e991c7ace1ec83046d17 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 22 Apr 2025 15:33:42 -0400 Subject: [PATCH 09/23] Adjust for __assign_str() losing second argument. In v6.8-9146-gc759e609030c, the second argument for __assign_str() was removed, as the second parameter is already derived from the __string() definition and no longer needed. We have to do a little digging in headers here to find the definition. Note the missing `;` at a few places... it has to be added now. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 11 +++++++++++ kmod/src/kernelcompat.h | 6 ++++++ kmod/src/scoutfs_trace.h | 12 ++++++------ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 6be0ecf4f..30d3630bf 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -535,3 +535,14 @@ endif ifneq (,$(shell grep -s 'struct inode.*bd_inode' include/linux/blk_types.h include/linux/fs.h)) ccflags-y += -DKC_HAVE_BD_INODE endif + +# +# v6.8-9146-gc759e609030c +# +# Removes __assign_str_len() and removes the 2nd param of __assign_str(). +ifneq (,$(shell grep -s 'define __assign_str.dst, src' \ + include/trace/trace_events.h \ + include/trace/ftrace.h \ + include/trace/stages/stage6_event_callback.h)) +ccflags-y += -DKC_HAVE_ASSIGN_STR_PARMS +endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index e00440b01..56d3f202e 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -596,4 +596,10 @@ static inline long inode_get_atime_nsec(const struct inode *inode) #define KC_BDEV_MAPPING(b) (b)->bd_mapping #endif +#ifdef KC_HAVE_ASSIGN_STR_PARMS +#define kc__assign_str(a, b) __assign_str(a, b) +#else +#define kc__assign_str(a, b) __assign_str(a) +#endif + #endif diff --git a/kmod/src/scoutfs_trace.h b/kmod/src/scoutfs_trace.h index c71573529..252799805 100644 --- a/kmod/src/scoutfs_trace.h +++ b/kmod/src/scoutfs_trace.h @@ -102,7 +102,7 @@ TRACE_EVENT(scoutfs_setattr, SCSB_TRACE_ASSIGN(dentry->d_inode->i_sb); __entry->ino = scoutfs_ino(dentry->d_inode); __entry->d_len = dentry->d_name.len; - __assign_str(d_name, dentry->d_name.name); + kc__assign_str(d_name, dentry->d_name.name); __entry->ia_valid = attr->ia_valid; __entry->size_change = !!(attr->ia_valid & ATTR_SIZE); __entry->ia_size = attr->ia_size; @@ -1638,9 +1638,9 @@ TRACE_EVENT(scoutfs_rename, TP_fast_assign( SCSB_TRACE_ASSIGN(sb); __entry->old_dir_ino = scoutfs_ino(old_dir); - __assign_str(old_name, old_dentry->d_name.name) + kc__assign_str(old_name, old_dentry->d_name.name); __entry->new_dir_ino = scoutfs_ino(new_dir); - __assign_str(new_name, new_dentry->d_name.name) + kc__assign_str(new_name, new_dentry->d_name.name); __entry->new_inode_ino = new_dentry->d_inode ? scoutfs_ino(new_dentry->d_inode) : 0; ), @@ -1670,7 +1670,7 @@ TRACE_EVENT(scoutfs_d_revalidate, TP_fast_assign( SCSB_TRACE_ASSIGN(sb); __entry->dentry = dentry; - __assign_str(name, dentry->d_name.name) + kc__assign_str(name, dentry->d_name.name); __entry->ino = dentry->d_inode ? scoutfs_ino(dentry->d_inode) : 0; __entry->dir_ino = dir_ino; __entry->flags = flags; @@ -1705,7 +1705,7 @@ TRACE_EVENT(scoutfs_validate_dentry, SCSB_TRACE_ASSIGN(sb); __entry->dentry = dentry; __entry->dir_ino = dir_ino; - __assign_str(name, dentry->d_name.name) + kc__assign_str(name, dentry->d_name.name); __entry->dentry_ino = dentry_ino; __entry->dent_ino = dent_ino; __entry->fsdata_gen = (unsigned long long)dentry->d_fsdata; @@ -1827,7 +1827,7 @@ TRACE_EVENT(scoutfs_get_name, SCSB_TRACE_ASSIGN(sb); __entry->parent_ino = scoutfs_ino(parent); __entry->child_ino = scoutfs_ino(child); - __assign_str(name, name); + kc__assign_str(name, name); ), TP_printk(SCSBF" parent %llu child %llu name: %s", From 80926cfe556b66893bba417ecb6091156c59f9ab Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 22 Apr 2025 17:46:09 -0400 Subject: [PATCH 10/23] bio_add_page is now __must_check The return type always has been int, so, we just need to add return value checking and do something with it. We could return -ENOMEM here as well, either way it'll fall all the way through no matter what. This is since v6.4-rc2-100-g83f2caaaf9cb. Signed-off-by: Auke Kok --- kmod/src/block.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kmod/src/block.c b/kmod/src/block.c index a9a95d822..34165aebb 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -1229,7 +1229,12 @@ static int sm_block_io(struct super_block *sb, struct block_device *bdev, blk_op kc_bio_set_sector(bio, blkno << (SCOUTFS_BLOCK_SM_SHIFT - 9)); bio->bi_end_io = sm_block_bio_end_io; bio->bi_private = &sbc; - bio_add_page(bio, page, SCOUTFS_BLOCK_SM_SIZE, 0); + ret = bio_add_page(bio, page, SCOUTFS_BLOCK_SM_SIZE, 0); + if (ret != SCOUTFS_BLOCK_SM_SIZE) { + bio_put(bio); + ret = -EFAULT; + goto out; + } init_completion(&sbc.comp); sbc.err = 0; From 4ef1f56f766a9134467be7449d3097f25847a12b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 22 Apr 2025 19:15:22 -0400 Subject: [PATCH 11/23] Shrinker API v4. Yet another major shrinker API evolution in v6.6-rc4-53-gc42d50aefd17. The struct shrinker now has to be dynamically allocated. This is purposely a backwards incompatible break. We add another KC_ wrapper around the new shrinker_alloc() and move some initialization around to make this as much as possible low impact, but compatible with the old APIs through substitution. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 ++++ kmod/src/block.c | 11 +++-- kmod/src/item.c | 10 ++--- kmod/src/kernelcompat.h | 77 ++++++++++++++++++++++++---------- kmod/src/quota.c | 12 ++++-- kmod/src/wkic.c | 11 +++-- 6 files changed, 91 insertions(+), 39 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 30d3630bf..74079e66e 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -546,3 +546,12 @@ ifneq (,$(shell grep -s 'define __assign_str.dst, src' \ include/trace/stages/stage6_event_callback.h)) ccflags-y += -DKC_HAVE_ASSIGN_STR_PARMS endif + +# +# v6.6-rc4-53-gc42d50aefd17 +# +# el10 yet again modifies the shrinker API significantly, breaking our current +# implementation. +ifneq (,$(shell grep 'struct shrinker .shrinker_alloc' include/linux/shrinker.h)) +ccflags-y += -DKC_SHRINKER_ALLOC +endif diff --git a/kmod/src/block.c b/kmod/src/block.c index 34165aebb..ca92f6b1c 100644 --- a/kmod/src/block.c +++ b/kmod/src/block.c @@ -1290,9 +1290,12 @@ int scoutfs_block_setup(struct super_block *sb) binf->sb = sb; init_waitqueue_head(&binf->waitq); - KC_INIT_SHRINKER_FUNCS(&binf->shrinker, block_count_objects, - block_scan_objects); - KC_REGISTER_SHRINKER(&binf->shrinker, "scoutfs-block:" SCSBF, SCSB_ARGS(sb)); + KC_SETUP_SHRINKER(binf->shrinker, binf, 0, block_count_objects, + block_scan_objects, "scoutfs-block:" SCSBF, SCSB_ARGS(sb)); + if (KC_SHRINKER_IS_NULL(binf->shrinker)) { + ret = -ENOMEM; + goto out; + } INIT_WORK(&binf->free_work, block_free_work); init_llist_head(&binf->free_llist); @@ -1314,7 +1317,7 @@ void scoutfs_block_destroy(struct super_block *sb) struct block_info *binf = SCOUTFS_SB(sb)->block_info; if (binf) { - KC_UNREGISTER_SHRINKER(&binf->shrinker); + KC_UNREGISTER_SHRINKER(binf->shrinker); block_shrink_all(sb); flush_work(&binf->free_work); rhashtable_destroy(&binf->ht); diff --git a/kmod/src/item.c b/kmod/src/item.c index bbd6878dd..d6fca8b0e 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -2626,10 +2626,10 @@ int scoutfs_item_setup(struct super_block *sb) for_each_possible_cpu(cpu) init_pcpu_pages(cinf, cpu); - - KC_INIT_SHRINKER_FUNCS(&cinf->shrinker, item_cache_count_objects, - item_cache_scan_objects); - KC_REGISTER_SHRINKER(&cinf->shrinker, "scoutfs-item:" SCSBF, SCSB_ARGS(sb)); + KC_SETUP_SHRINKER(cinf->shrinker, cinf, 0, item_cache_count_objects, + item_cache_scan_objects, "scoutfs-item:" SCSBF, SCSB_ARGS(sb)); + if (KC_SHRINKER_IS_NULL(cinf->shrinker)) + return -ENOMEM; #ifdef KC_CPU_NOTIFIER cinf->notifier.notifier_call = item_cpu_callback; register_hotcpu_notifier(&cinf->notifier); @@ -2654,7 +2654,7 @@ void scoutfs_item_destroy(struct super_block *sb) #ifdef KC_CPU_NOTIFIER unregister_hotcpu_notifier(&cinf->notifier); #endif - KC_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.h b/kmod/src/kernelcompat.h index 56d3f202e..f0eb179fc 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -142,25 +142,54 @@ struct timespec64 kc_current_time(struct inode *inode); #define kc_timespec timespec64 #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; \ +#ifdef KC_SHRINKER_ALLOC +// el10+ + +#define KC_DEFINE_SHRINKER(name) struct shrinker *(name) +#define KC_SHRINKER_CONTAINER_OF(ptr, type) ptr->private_data +#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \ +do { \ + ptr = shrinker_alloc(flags, fmt, args); \ + if (ptr) { \ + ptr->private_data = (priv); \ + ptr->seeks = DEFAULT_SEEKS; \ + ptr->count_objects = countfn; \ + ptr->scan_objects = scanfn; \ + shrinker_register(ptr); \ + } \ } while (0) +#define KC_UNREGISTER_SHRINKER(ptr) shrinker_free(ptr) +#define KC_SHRINKER_FN(ptr) (ptr) +#define KC_SHRINKER_IS_NULL(ptr) (!(ptr)) +#else /* KC_SHRINKER_ALLOC */ +#ifndef KC_SHRINKER_SHRINK +// el9, el8 + +#define KC_DEFINE_SHRINKER(name) struct shrinker (name) #define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(ptr, type, shrinker) #ifdef KC_SHRINKER_NAME -#define KC_REGISTER_SHRINKER register_shrinker +#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \ +do { \ + (ptr).count_objects = (countfn); \ + (ptr).scan_objects = (scanfn); \ + (ptr).seeks = DEFAULT_SEEKS; \ + register_shrinker(&(ptr), fmt, args); \ +} while (0) #else -#define KC_REGISTER_SHRINKER(ptr, fmt, ...) (register_shrinker(ptr)) +#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \ +do { \ + (ptr).count_objects = (countfn); \ + (ptr).scan_objects = (scanfn); \ + (ptr).seeks = DEFAULT_SEEKS; \ + register_shrinker(&(ptr)); \ +} while (0) #endif /* KC_SHRINKER_NAME */ -#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr)) -#define KC_SHRINKER_FN(ptr) (ptr) -#else +#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr))) +#define KC_SHRINKER_FN(ptr) (&ptr) + +#else /* KC_SHRINKER_SHRINK */ +// el7 #include #ifndef SHRINK_STOP @@ -176,19 +205,21 @@ struct kc_shrinker_wrapper { }; #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, fmt, ...) (register_shrinker(ptr.shrink)) -#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr.shrink)) -#define KC_SHRINKER_FN(ptr) (ptr.shrink) +#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \ +do { \ + (ptr).count_objects = (countfn); \ + (ptr).scan_objects = (scanfn); \ + (ptr).shrink.shrink = kc_shrink_wrapper_fn; \ + (ptr).shrink.seeks = DEFAULT_SEEKS; \ + register_shrinker(&(ptr).shrink); \ +} while (0) +#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr).shrink)) +#define KC_SHRINKER_FN(ptr) (&(ptr).shrink) #endif /* KC_SHRINKER_SHRINK */ +#define KC_SHRINKER_IS_NULL(ptr) (0) +#endif /* KC_SHRINKER_ALLOC */ #ifdef KC_KERNEL_GETSOCKNAME_ADDRLEN #include diff --git a/kmod/src/quota.c b/kmod/src/quota.c index 9f331325a..96d829814 100644 --- a/kmod/src/quota.c +++ b/kmod/src/quota.c @@ -269,7 +269,7 @@ static void shrink_all_cached_checks(struct squota_info *qtinf) { struct shrink_control sc = { .nr_to_scan = LONG_MAX, }; - scan_cached_checks(KC_SHRINKER_FN(&qtinf->shrinker), &sc); + scan_cached_checks(KC_SHRINKER_FN(qtinf->shrinker), &sc); } static u8 ns_is_attr(u8 ns) @@ -1225,8 +1225,12 @@ int scoutfs_quota_setup(struct super_block *sb) spin_lock_init(&qtinf->lock); init_waitqueue_head(&qtinf->waitq); - KC_INIT_SHRINKER_FUNCS(&qtinf->shrinker, count_cached_checks, scan_cached_checks); - KC_REGISTER_SHRINKER(&qtinf->shrinker, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb)); + KC_SETUP_SHRINKER(qtinf->shrinker, qtinf, 0, count_cached_checks, + scan_cached_checks, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb)); + if (KC_SHRINKER_IS_NULL(qtinf->shrinker)) { + ret = -ENOMEM; + goto out; + } sbi->squota_info = qtinf; @@ -1250,7 +1254,7 @@ void scoutfs_quota_destroy(struct super_block *sb) if (qtinf) { debugfs_remove(qtinf->drop_dentry); - KC_UNREGISTER_SHRINKER(&qtinf->shrinker); + KC_UNREGISTER_SHRINKER(qtinf->shrinker); spin_lock(&qtinf->lock); rs = rcu_dereference_protected(qtinf->ruleset, lockdep_is_held(&qtinf->lock)); diff --git a/kmod/src/wkic.c b/kmod/src/wkic.c index 0dc476f4c..e404ed9ff 100644 --- a/kmod/src/wkic.c +++ b/kmod/src/wkic.c @@ -1112,8 +1112,13 @@ int scoutfs_wkic_setup(struct super_block *sb) } winf->sb = sb; - KC_INIT_SHRINKER_FUNCS(&winf->shrinker, wkic_shrink_count, wkic_shrink_scan); - KC_REGISTER_SHRINKER(&winf->shrinker, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb)); + KC_SETUP_SHRINKER(winf->shrinker, winf, 0, wkic_shrink_count, + wkic_shrink_scan, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb)); + if (KC_SHRINKER_IS_NULL(winf->shrinker)) { + debugfs_remove(winf->drop_dentry); + kfree(winf); + return -ENOMEM; + } sbi->wkic_info = winf; return 0; @@ -1141,7 +1146,7 @@ void scoutfs_wkic_destroy(struct super_block *sb) if (winf) { debugfs_remove(winf->drop_dentry); - KC_UNREGISTER_SHRINKER(&winf->shrinker); + KC_UNREGISTER_SHRINKER(winf->shrinker); /* trees are in sync so tearing down one frees all pages */ rbtree_postorder_for_each_entry_safe(wpage, tmp, &winf->wpage_roots[0], nodes[0]) { From 38906a51da3851711a9199af379d51a69f4dfcd8 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 22 Apr 2025 23:50:18 -0400 Subject: [PATCH 12/23] generic_fillattr() now wants the request_mask arg from caller. Since ~v6.5-rc1-95-g0d72b92883c6, generic_fillattr() asks us to pass through the request_mask from the caller. This allows it to only request a subset. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 7 +++++++ kmod/src/inode.c | 1 + kmod/src/kernelcompat.h | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 74079e66e..849fa7dfe 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -547,6 +547,13 @@ ifneq (,$(shell grep -s 'define __assign_str.dst, src' \ ccflags-y += -DKC_HAVE_ASSIGN_STR_PARMS endif +# +# v6.5-113-g615e95831ec3 +# +ifneq (,$(shell grep 'generic_fillattr..*,.u32,' include/linux/fs.h)) +ccflags-y += -DKC_GENERIC_FILLATTR_REQUEST_MASK +endif + # # v6.6-rc4-53-gc42d50aefd17 # diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 6ee0861fb..5f853fab9 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -398,6 +398,7 @@ int scoutfs_getattr(KC_VFS_NS_DEF SCOUTFS_LKF_REFRESH_INODE, inode, &lock); if (ret == 0) { generic_fillattr(KC_VFS_INIT_NS + KC_FILLATTR_REQUEST_MASK inode, stat); scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ); } diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index f0eb179fc..6fe22ac5f 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -310,6 +310,12 @@ typedef unsigned int blk_opf_t; #endif #endif /* KC_VFS_METHOD_MNT_IDMAP_ARG */ +#ifdef KC_GENERIC_FILLATTR_REQUEST_MASK +#define KC_FILLATTR_REQUEST_MASK request_mask, +#else +#define KC_FILLATTR_REQUEST_MASK +#endif + #ifdef KC_BIO_ALLOC_DEV_OPF_ARGS #define kc_bio_alloc bio_alloc #else From f08a338a6b51109e0a7d2cb703939ae9a58c1624 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 22 Apr 2025 23:33:56 -0400 Subject: [PATCH 13/23] set_blocksize() takes struct file argument. In v6.9-rc4-8-gead083aeeed9, this now takes a struct file argument, adding to the ifdef salad we've got going on here. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 8 ++++++++ kmod/src/super.c | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 849fa7dfe..bfa2a2a7f 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -562,3 +562,11 @@ endif ifneq (,$(shell grep 'struct shrinker .shrinker_alloc' include/linux/shrinker.h)) ccflags-y += -DKC_SHRINKER_ALLOC endif + +# +# v6.9-rc4-8-gead083aeeed9 +# +# set_blocksize() now has a struct file arg. +ifneq (,$(shell grep -s 'int set_blocksize.struct file' include/linux/blkdev.h)) +ccflags-y += -DKC_BLKDEV_SET_BLOCKSIZE_FILE +endif diff --git a/kmod/src/super.c b/kmod/src/super.c index 0c5fce685..a67399636 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -552,6 +552,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) } sbi->meta_bdev_file = meta_bdev_file; sbi->meta_bdev = file_bdev(meta_bdev_file); + #else #ifdef KC_BLKDEV_PUT_HOLDER_ARG meta_bdev = blkdev_get_by_path(opts.metadev_path, SCOUTFS_META_BDEV_MODE, sb, NULL); @@ -567,7 +568,11 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) sbi->meta_bdev = meta_bdev; #endif +#ifdef KC_BLKDEV_SET_BLOCKSIZE_FILE + ret = set_blocksize(sbi->meta_bdev_file, SCOUTFS_BLOCK_SM_SIZE); +#else ret = set_blocksize(sbi->meta_bdev, SCOUTFS_BLOCK_SM_SIZE); +#endif if (ret != 0) { scoutfs_err(sb, "failed to set metadev blocksize, returned %d", ret); From e42705d757efd4d87050b387de74f26bdbf38453 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 29 Apr 2025 13:19:24 -0400 Subject: [PATCH 14/23] Add sysfs default_groups usage. Since v5.1-rc3-29-gaa30f47cf666, and in el9, there are changes to reduce the amount of boilerplate code needed to hook up lots of attribute files using a .default_groups member. In el10, this becomes the required method as the .default_attrs member now becomes removed. This touches every sysfs part that we have. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 8 ++++++++ kmod/src/counters.c | 14 ++++++++++++-- kmod/src/fence.c | 6 +++++- kmod/src/kernelcompat.h | 10 ++++++++++ kmod/src/options.c | 7 ++++++- kmod/src/quorum.c | 5 ++++- kmod/src/srch.c | 6 +++++- kmod/src/sysfs.c | 17 ++++++++++++++--- kmod/src/sysfs.h | 11 ++++++++--- kmod/src/volopt.c | 13 ++++++++++++- 10 files changed, 84 insertions(+), 13 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index bfa2a2a7f..ec4fb889f 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -570,3 +570,11 @@ endif ifneq (,$(shell grep -s 'int set_blocksize.struct file' include/linux/blkdev.h)) ccflags-y += -DKC_BLKDEV_SET_BLOCKSIZE_FILE endif + +# +# v5.1-rc3-29-gaa30f47cf666 +# +# struct kobj_type now has member `default_groups` +ifneq (,$(shell grep 'const struct attribute_group ..default_groups;' include/linux/kobject.h)) +ccflags-y += -DKC_KOBJECT_DEFAULT_GROUPS +endif diff --git a/kmod/src/counters.c b/kmod/src/counters.c index 5578ae26e..9ba5b1a7c 100644 --- a/kmod/src/counters.c +++ b/kmod/src/counters.c @@ -34,6 +34,17 @@ static struct attribute scoutfs_counter_attrs[] = { #define NR_ATTRS ARRAY_SIZE(scoutfs_counter_attrs) static struct attribute *scoutfs_counter_attr_ptrs[NR_ATTRS + 1]; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +static struct attribute_group scoutfs_counter_attr_group = { + .attrs = scoutfs_counter_attr_ptrs, +}; + +static const struct attribute_group *scoutfs_counter_attr_groups[] = { + &scoutfs_counter_attr_group, + NULL, +}; +#endif + static ssize_t scoutfs_counter_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -45,7 +56,6 @@ static ssize_t scoutfs_counter_attr_show(struct kobject *kobj, counters = container_of(kobj, struct scoutfs_counters, kobj); index = attr - scoutfs_counter_attrs; pcpu = &counters->FIRST_COUNTER + index; - return snprintf(buf, PAGE_SIZE, "%lld\n", percpu_counter_sum(pcpu)); } @@ -63,7 +73,7 @@ static const struct sysfs_ops scoutfs_counter_attr_ops = { }; static struct kobj_type scoutfs_counters_ktype = { - .default_attrs = scoutfs_counter_attr_ptrs, + .KC_KOBJ_DEFAULT_OP = KC_KOBJ_DEFAULT_PICK(scoutfs_counter_attr_groups, scoutfs_counter_attr_ptrs), .sysfs_ops = &scoutfs_counter_attr_ops, .release = scoutfs_counters_kobj_release, }; diff --git a/kmod/src/fence.c b/kmod/src/fence.c index 3669dc2d8..4139da8b1 100644 --- a/kmod/src/fence.c +++ b/kmod/src/fence.c @@ -217,6 +217,9 @@ static struct attribute *fence_attrs[] = { SCOUTFS_ATTR_PTR(rid), NULL, }; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +ATTRIBUTE_GROUPS(fence); +#endif #define FENCE_TIMEOUT_MS (MSEC_PER_SEC * 30) @@ -255,7 +258,8 @@ int scoutfs_fence_start(struct super_block *sb, u64 rid, __be32 ipv4_addr, int r fence->rid = rid; ret = scoutfs_sysfs_create_attrs_parent(sb, &fi->kset->kobj, - &fence->ssa, fence_attrs, + &fence->ssa, + KC_KOBJ_DEFAULT(fence), "%016llx", rid); if (ret < 0) { kfree(fence); diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 6fe22ac5f..9a6d224d6 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -639,4 +639,14 @@ static inline long inode_get_atime_nsec(const struct inode *inode) #define kc__assign_str(a, b) __assign_str(a) #endif +#ifdef KC_KOBJECT_DEFAULT_GROUPS +#define KC_KOBJ_DEFAULT_OP default_groups +#define KC_KOBJ_DEFAULT(name) (name##_groups) +#define KC_KOBJ_DEFAULT_PICK(group, attrs) (group) +#else +#define KC_KOBJ_DEFAULT_OP default_attrs +#define KC_KOBJ_DEFAULT(name) (name##_attrs) +#define KC_KOBJ_DEFAULT_PICK(group, attrs) (attrs) +#endif + #endif diff --git a/kmod/src/options.c b/kmod/src/options.c index b7565d76d..6812a7dbd 100644 --- a/kmod/src/options.c +++ b/kmod/src/options.c @@ -752,13 +752,18 @@ static struct attribute *options_attrs[] = { SCOUTFS_ATTR_PTR(quorum_slot_nr), NULL, }; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +ATTRIBUTE_GROUPS(options); +#endif int scoutfs_options_setup(struct super_block *sb) { DECLARE_OPTIONS_INFO(sb, optinf); int ret; - ret = scoutfs_sysfs_create_attrs(sb, &optinf->sysfs_attrs, options_attrs, "mount_options"); + ret = scoutfs_sysfs_create_attrs(sb, &optinf->sysfs_attrs, + KC_KOBJ_DEFAULT_PICK(options_groups, options_attrs), + "mount_options"); if (ret < 0) scoutfs_options_destroy(sb); return ret; diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index 54615c52e..24be890b1 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -1192,6 +1192,9 @@ static struct attribute *quorum_attrs[] = { SCOUTFS_ATTR_PTR(is_leader), NULL, }; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +ATTRIBUTE_GROUPS(quorum); +#endif static inline bool valid_ipv4_unicast(__be32 addr) { @@ -1352,7 +1355,7 @@ int scoutfs_quorum_setup(struct super_block *sb) if (ret < 0) goto out; - ret = scoutfs_sysfs_create_attrs(sb, &qinf->ssa, quorum_attrs, + ret = scoutfs_sysfs_create_attrs(sb, &qinf->ssa, KC_KOBJ_DEFAULT(quorum), "quorum"); if (ret < 0) goto out; diff --git a/kmod/src/srch.c b/kmod/src/srch.c index d6ffc10fd..efd72061f 100644 --- a/kmod/src/srch.c +++ b/kmod/src/srch.c @@ -2350,6 +2350,9 @@ static struct attribute *srch_attrs[] = { SCOUTFS_ATTR_PTR(compact_delay_ms), NULL, }; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +ATTRIBUTE_GROUPS(srch); +#endif void scoutfs_srch_destroy(struct super_block *sb) { @@ -2391,7 +2394,8 @@ int scoutfs_srch_setup(struct super_block *sb) sbi->srch_info = srinf; - ret = scoutfs_sysfs_create_attrs(sb, &srinf->ssa, srch_attrs, "srch"); + ret = scoutfs_sysfs_create_attrs(sb, &srinf->ssa, KC_KOBJ_DEFAULT(srch), + "srch"); if (ret < 0) goto out; diff --git a/kmod/src/sysfs.c b/kmod/src/sysfs.c index b3c7ddbf0..3b7e176fb 100644 --- a/kmod/src/sysfs.c +++ b/kmod/src/sysfs.c @@ -103,12 +103,11 @@ static ssize_t attr_funcs_show(struct kobject *kobj, struct attribute *attr, }; \ \ static struct kobj_type _name##_ktype = { \ - .default_attrs = _name##_attrs, \ + .KC_KOBJ_DEFAULT_OP = KC_KOBJ_DEFAULT(_name), \ .sysfs_ops = &_name##_sysfs_ops, \ .release = _name##_release, \ }; - static struct attribute *sb_id_attrs[] = { &data_device_maj_min_attr_funcs.attr, &format_version_attr_funcs.attr, @@ -116,6 +115,9 @@ static struct attribute *sb_id_attrs[] = { &rid_attr_funcs.attr, NULL, }; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +ATTRIBUTE_GROUPS(sb_id); +#endif KTYPE(sb_id); struct kobject *scoutfs_sysfs_sb_dir(struct super_block *sb) @@ -155,7 +157,12 @@ void scoutfs_sysfs_init_attrs(struct super_block *sb, int scoutfs_sysfs_create_attrs_parent(struct super_block *sb, struct kobject *parent, struct scoutfs_sysfs_attrs *ssa, - struct attribute **attrs, char *fmt, ...) +#ifdef KC_KOBJECT_DEFAULT_GROUPS + const struct attribute_group **groups, +#else + struct attribute **attrs, +#endif + char *fmt, ...) { va_list args; size_t name_len; @@ -168,7 +175,11 @@ int scoutfs_sysfs_create_attrs_parent(struct super_block *sb, ssa->sb = sb; init_completion(&ssa->comp); +#ifdef KC_KOBJECT_DEFAULT_GROUPS + ssa->ktype.default_groups = groups; +#else ssa->ktype.default_attrs = attrs; +#endif ssa->ktype.sysfs_ops = &kobj_sysfs_ops; ssa->ktype.release = scoutfs_sysfs_release; diff --git a/kmod/src/sysfs.h b/kmod/src/sysfs.h index 70b85af81..177e98f75 100644 --- a/kmod/src/sysfs.h +++ b/kmod/src/sysfs.h @@ -39,10 +39,15 @@ void scoutfs_sysfs_init_attrs(struct super_block *sb, int scoutfs_sysfs_create_attrs_parent(struct super_block *sb, struct kobject *parent, struct scoutfs_sysfs_attrs *ssa, - struct attribute **attrs, char *fmt, ...); -#define scoutfs_sysfs_create_attrs(sb, ssa, attrs, fmt, args...) \ +#ifdef KC_KOBJECT_DEFAULT_GROUPS + const struct attribute_group **groups, +#else + struct attribute **attrs, +#endif + char *fmt, ...); +#define scoutfs_sysfs_create_attrs(sb, ssa, group_or_attrs, fmt, args...) \ scoutfs_sysfs_create_attrs_parent(sb, scoutfs_sysfs_sb_dir(sb), \ - ssa, attrs, fmt, ##args) + ssa, group_or_attrs, fmt, ##args) void scoutfs_sysfs_destroy_attrs(struct super_block *sb, struct scoutfs_sysfs_attrs *ssa); diff --git a/kmod/src/volopt.c b/kmod/src/volopt.c index 303d94b06..b87e4ac52 100644 --- a/kmod/src/volopt.c +++ b/kmod/src/volopt.c @@ -52,6 +52,15 @@ static struct volopt_nr_name { /* initialized by setup, pointer array is null terminated */ static struct kobj_attribute volopt_attrs[ARRAY_SIZE(volopt_table)]; static struct attribute *volopt_attr_ptrs[ARRAY_SIZE(volopt_table) + 1]; +#ifdef KC_KOBJECT_DEFAULT_GROUPS +static const struct attribute_group volopt_group = { + .attrs = volopt_attr_ptrs, +}; +static const struct attribute_group *volopt_groups[] = { + &volopt_group, + NULL, +}; +#endif static void get_opt_data(struct kobj_attribute *attr, struct scoutfs_volume_options *volopt, u64 *bit, __le64 **opt) @@ -164,7 +173,9 @@ int scoutfs_volopt_setup(struct super_block *sb) BUILD_BUG_ON(ARRAY_SIZE(volopt_table) != ARRAY_SIZE(volopt_attr_ptrs) - 1); volopt_attr_ptrs[i] = NULL; - ret = scoutfs_sysfs_create_attrs(sb, &vinf->ssa, volopt_attr_ptrs, "volume_options"); + ret = scoutfs_sysfs_create_attrs(sb, &vinf->ssa, + KC_KOBJ_DEFAULT_PICK(volopt_groups, volopt_attr_ptrs), + "volume_options"); if (ret < 0) goto out; From 92e3c72d9d6c74a6688c83daeebe52948f4a4950 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 29 Apr 2025 18:13:51 -0400 Subject: [PATCH 15/23] mv overwrite error format changes in el10 This is somewhat cumbersome, we want to see the error message, but the format changes enough to make this messy. We opt to change the golden to the new format, which only shows one of the arguments in its error output: the thing that cannot be overwritten. We then add a filter that rewrites the old output format with sed patterns to be exactly like the new format, so this will work everywhere again, without changing or adding filters to obscure error messages. Signed-off-by: Auke Kok --- tests/golden/basic-posix-consistency | 2 +- tests/tests/basic-posix-consistency.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/golden/basic-posix-consistency b/tests/golden/basic-posix-consistency index e96251bc7..7fd126a19 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 overwrite '/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/tests/basic-posix-consistency.sh b/tests/tests/basic-posix-consistency.sh index 6abe4e46a..bb9d9e66d 100644 --- a/tests/tests/basic-posix-consistency.sh +++ b/tests/tests/basic-posix-consistency.sh @@ -138,7 +138,9 @@ echo "--- can't overwrite non-empty dir" mkdir "$T_D0/dir/a/dir" touch "$T_D0/dir/a/dir/nope" mkdir "$T_D1/dir/c/clobber" -mv -T "$T_D1/dir/c/clobber" "$T_D1/dir/a/dir" 2>&1 | t_filter_fs +mv -T "$T_D1/dir/c/clobber" "$T_D1/dir/a/dir" 2>&1 | \ + sed "s@mv: cannot move '.*' to '\(.*\)': Directory not empty@mv: cannot overwrite '\1': Directory not empty@g" | \ + t_filter_fs find "$T_D0/dir" -ls 2>&1 | t_filter_fs > "$T_TMP.0" find "$T_D1/dir" -ls 2>&1 | t_filter_fs > "$T_TMP.1" diff -u "$T_TMP.0" "$T_TMP.1" From bcde8b2169479e40e7e8dbbec92934769ded533c Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 1 May 2025 12:27:31 -0400 Subject: [PATCH 16/23] Fix unlocked pt_excl in scoutfs_readahead. This caller of scoutfs_get_block is now actively used in el10 and the WARN_ON_ONCE(!lock) in data.c:567 triggers. XXX FIXME XXX However, this will hit the `BUG_ON(!list_empty(pages));` that's a few lines further, in some of our testing, so, it's still not right Signed-off-by: Auke Kok --- kmod/src/data.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index 9c164542f..26790d0b7 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -716,24 +716,24 @@ static int scoutfs_readpage(struct file *file, struct page *page) return ret; } - if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) { - ret = scoutfs_data_wait_check(inode, page_offset(page), - PAGE_SIZE, SEF_OFFLINE, - SCOUTFS_IOC_DWO_READ, &dw, - inode_lock); - if (ret != 0) { - unlock_page(page); - scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); - scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); - } - if (ret > 0) { - ret = scoutfs_data_wait(inode, &dw); - if (ret == 0) - ret = AOP_TRUNCATED_PAGE; - } - if (ret != 0) - return ret; + scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock); + + ret = scoutfs_data_wait_check(inode, page_offset(page), + PAGE_SIZE, SEF_OFFLINE, + SCOUTFS_IOC_DWO_READ, &dw, + inode_lock); + if (ret != 0) { + unlock_page(page); + scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); + scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); + } + if (ret > 0) { + ret = scoutfs_data_wait(inode, &dw); + if (ret == 0) + ret = AOP_TRUNCATED_PAGE; } + if (ret != 0) + return ret; #ifdef KC_MPAGE_READ_FOLIO ret = mpage_read_folio(folio, scoutfs_get_block_read); @@ -741,8 +741,8 @@ static int scoutfs_readpage(struct file *file, struct page *page) ret = mpage_readpage(page, scoutfs_get_block_read); #endif - scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); + scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); return ret; } @@ -760,8 +760,10 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { struct inode *inode = file->f_inode; + struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; struct scoutfs_lock *inode_lock = NULL; + SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); struct page *page; struct page *tmp; int ret; @@ -771,6 +773,8 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping, if (ret) goto out; + scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock); + list_for_each_entry_safe(page, tmp, pages, lru) { ret = scoutfs_data_wait_check(inode, page_offset(page), PAGE_SIZE, SEF_OFFLINE, @@ -790,6 +794,7 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping, ret = mpage_readpages(mapping, pages, nr_pages, scoutfs_get_block_read); out: + scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); BUG_ON(!list_empty(pages)); return ret; @@ -798,8 +803,10 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping, static void scoutfs_readahead(struct readahead_control *rac) { struct inode *inode = rac->file->f_inode; + struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; struct scoutfs_lock *inode_lock = NULL; + SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); int ret; ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, @@ -807,6 +814,8 @@ static void scoutfs_readahead(struct readahead_control *rac) if (ret) return; + scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock); + ret = scoutfs_data_wait_check(inode, readahead_pos(rac), readahead_length(rac), SEF_OFFLINE, SCOUTFS_IOC_DWO_READ, NULL, @@ -814,6 +823,7 @@ static void scoutfs_readahead(struct readahead_control *rac) if (ret == 0) mpage_readahead(rac, scoutfs_get_block_read); + scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ); } #endif From 8ceedbd8194843bdb20b3f105fe6f13b53b4d988 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 1 May 2025 15:10:57 -0400 Subject: [PATCH 17/23] Obsolete scoutfs_writepage. Due to folios, the kernel will call scoutfs_writepages() and this becomes unused. It could be ported but the helper function to call isn't exported anymore. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 11 +++++++++++ kmod/src/data.c | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index ec4fb889f..752fb23e2 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -578,3 +578,14 @@ endif ifneq (,$(shell grep 'const struct attribute_group ..default_groups;' include/linux/kobject.h)) ccflags-y += -DKC_KOBJECT_DEFAULT_GROUPS endif + +# +# v6.7-rc4-307-g17bf23a981be +# +# block_write_full_page() is replaced with block_write_full_folio(), +# but that isn't exported as it used to be (and the only users now +# are builtin). However, the kernel will fall back to using the +# .writepages method instead, so we can drop this method. +ifneq (,$(shell grep 'int block_write_full_page.struct page' include/linux/buffer_head.h)) +ccflags-y += -DKC_HAVE_BLOCK_WRITE_FULL_PAGE +endif diff --git a/kmod/src/data.c b/kmod/src/data.c index 26790d0b7..e7abf7684 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -828,10 +828,12 @@ static void scoutfs_readahead(struct readahead_control *rac) } #endif +#ifdef KC_HAVE_BLOCK_WRITE_FULL_PAGE static int scoutfs_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, scoutfs_get_block_write, wbc); } +#endif static int scoutfs_writepages(struct address_space *mapping, struct writeback_control *wbc) @@ -2213,7 +2215,9 @@ const struct address_space_operations scoutfs_file_aops = { #else .readahead = scoutfs_readahead, #endif +#ifdef KC_HAVE_BLOCK_WRITE_FULL_PAGE .writepage = scoutfs_writepage, +#endif .writepages = scoutfs_writepages, .write_begin = scoutfs_write_begin, .write_end = scoutfs_write_end, From f29a411bf1df5b4fc48f3cc52c7ebfff0dfea8fb Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 1 May 2025 17:43:34 -0400 Subject: [PATCH 18/23] generic_file_splice_read is removed. Based on my reading of the gfs2 driver, it appears it's likely the safer approach to take copy_splice_read instead of filemap_splice_read as it may potentially lead to cluster deadlocks. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/data.c | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 752fb23e2..27ea02560 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -589,3 +589,12 @@ endif ifneq (,$(shell grep 'int block_write_full_page.struct page' include/linux/buffer_head.h)) ccflags-y += -DKC_HAVE_BLOCK_WRITE_FULL_PAGE endif + +# +# v6.4-rc2-29-gc6585011bc1d +# +# generic_file_splice_read is removed. It can be replaced with filemap_splice_read +# or copy_splice_read. +ifneq (,$(shell grep 'ssize_t generic_file_splice_read.struct file' include/linux/fs.h)) +ccflags-y += -DKC_HAVE_GENERIC_FILE_SPLICE_READ +endif diff --git a/kmod/src/data.c b/kmod/src/data.c index e7abf7684..46a427c92 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -2232,8 +2232,12 @@ const struct file_operations scoutfs_file_fops = { #else .read_iter = scoutfs_file_read_iter, .write_iter = scoutfs_file_write_iter, - .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, +#endif +#ifdef KC_HAVE_GENERIC_FILE_SPLICE_READ + .splice_read = generic_file_splice_read, +#else + .splice_read = copy_splice_read, #endif .mmap = scoutfs_file_mmap, .unlocked_ioctl = scoutfs_ioctl, From bcdd6e89a4b2ad68385894cad269eb30f00b5280 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 5 May 2025 15:08:50 -0400 Subject: [PATCH 19/23] Hook up buffer_migrate_folio. This works together with the dropped block_write_full_page(), allowing us to drop the _writepage() method as long as we implement _writepages(). Since v5.19-rc3-395-g67235182a41c. This used to be the .migratepage() method. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/data.c | 3 +++ 2 files changed, 12 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 27ea02560..d289d4bc2 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -598,3 +598,12 @@ endif ifneq (,$(shell grep 'ssize_t generic_file_splice_read.struct file' include/linux/fs.h)) ccflags-y += -DKC_HAVE_GENERIC_FILE_SPLICE_READ endif + +# +# v5.19-rc3-395-g67235182a41c +# +# Adds buffer_migrate_folio(), similar to other fss. Quote willy: "If the filesystem +# implements migrate_folio and writepages, there is no need for a writepage implementation." +ifneq (,$(shell grep 'int buffer_migrate_folio.struct address_space' include/linux/buffer_head.h)) +ccflags-y += -DKC_HAVE_BUFFER_MIGRATE_FOLIO +endif diff --git a/kmod/src/data.c b/kmod/src/data.c index 46a427c92..0f2cb098b 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -2207,6 +2207,9 @@ const struct address_space_operations scoutfs_file_aops = { .dirty_folio = block_dirty_folio, .invalidate_folio = block_invalidate_folio, .read_folio = scoutfs_read_folio, +#ifdef KC_HAVE_BUFFER_MIGRATE_FOLIO + .migrate_folio = buffer_migrate_folio, +#endif #else .readpage = scoutfs_readpage, #endif From 90a29aeee6f40101097db4ee79aad095de29dcef Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 5 May 2025 18:25:11 -0400 Subject: [PATCH 20/23] Switch to .iterate_shared Since v4.6-rc3-29-g6192269444eb there has been a special readdir VFS method that can be called for the same directory multiple times in parallel, without any additional VFS locking. The VFS has provided a WRAP_DIR_ITER() macro to re-wrap the method with extra locking, in case the method wasn't safe for this. With el10, the old .readdir method is now gone, and we have no choice but to either use the wrapper, or just hook up our readdir() method to the .iterate_shared op. From what I can see, our implementation is safe to do this. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 8 ++++++++ kmod/src/dir.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index d289d4bc2..d8e55b113 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -607,3 +607,11 @@ endif ifneq (,$(shell grep 'int buffer_migrate_folio.struct address_space' include/linux/buffer_head.h)) ccflags-y += -DKC_HAVE_BUFFER_MIGRATE_FOLIO endif + +# +# v4.6-rc3-29-g6192269444eb +# +# Adds .iterate_shared readdir() iterator vfs method. +ifneq (,$(shell grep 'iterate_shared...struct file.., struct dir_context' include/linux/fs.h)) +ccflags-y += -DKC_HAVE_ITERATE_SHARED +endif diff --git a/kmod/src/dir.c b/kmod/src/dir.c index 1199d13a4..2e5168b54 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -2039,7 +2039,11 @@ const struct inode_operations scoutfs_symlink_iops = { }; const struct file_operations scoutfs_dir_fops = { +#ifdef KC_HAVE_ITERATE_SHARED + .iterate_shared = scoutfs_readdir, +#else .iterate = scoutfs_readdir, +#endif #ifdef KC_FMODE_KABI_ITERATE .open = scoutfs_dir_open, #endif From 5407e2de5a2757a063d643069a761d9e3c405529 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 8 Dec 2025 14:46:08 -0800 Subject: [PATCH 21/23] Avoid \Z negative pattern in test exclude list In RHEL10, the grep version is bumped from 3.6 to 3.11, and grep no longer recognizes the \Z character anymore. We have 2 solutions: We can either choose to use `grep -P` to continue using it, or, alternatively, we can choose a different `null` match to have an effectively empty exclude list. The latter seems easy enough: By default, we can just exclude empty lines ("^$") obtaining the exact same behavior as before. Signed-off-by: Auke Kok --- tests/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-tests.sh b/tests/run-tests.sh index f6c506ec6..e182fd1e3 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -301,7 +301,7 @@ fi # include everything by default test -z "$T_INCLUDE" && T_INCLUDE="-e '.*'" # (quickly) exclude nothing by default -test -z "$T_EXCLUDE" && T_EXCLUDE="-e '\Zx'" +test -z "$T_EXCLUDE" && T_EXCLUDE="-e '^$'" # eval to strip re ticks but not expand tests=$(grep -v "^#" $T_SEQUENCE | From d51cb2000f1859deb936d5270bc5054a87c06c0e Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 8 Dec 2025 16:23:56 -0800 Subject: [PATCH 22/23] Fix compat for list_lru_walk in el10 In el10, we don't need compat for list_lru_walk, as was intended in 8b6418fb. However, the actual redefine from kc_list_lru_walk to list_lru_walk was omitted. It wasn't needed until el10. Add it now. Signed-off-by: Auke Kok --- kmod/src/kernelcompat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 9a6d224d6..9df5e6a4d 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -489,6 +489,7 @@ unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_contro kc_list_lru_walk_cb_t isolate, void *cb_arg); #else #define kc_list_lru_shrink_walk list_lru_shrink_walk +#define kc_list_lru_walk list_lru_walk #endif #if defined(KC_LIST_LRU_WALK_CB_ITEM_LOCK) From 161477b987b30cc49aafa7cd349c793f5c57f3f2 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 21 Nov 2025 17:35:28 -0500 Subject: [PATCH 23/23] block_write_{begin,end} take a folio as well as page_mkwrite. Adds compat handlers for block_write_begin and block_write_end to take a folio argument instead of page, as this is needed since v6.11-rc1-54-g9f04609f74ec. To avoid having two duplicate page_mkwrite functions there's now a complete page/folio ifdef split here to make it handle either. This is ugly but it's the most straightforward solution here and avoids more obscure macros. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++ kmod/src/data.c | 48 +++++++++++++++++++++++++++++----- kmod/src/kernelcompat.h | 6 +++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index d8e55b113..686fc4193 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -615,3 +615,12 @@ endif ifneq (,$(shell grep 'iterate_shared...struct file.., struct dir_context' include/linux/fs.h)) ccflags-y += -DKC_HAVE_ITERATE_SHARED endif + +# +# v6.11-rc1-54-g9f04609f74ec +# +# Last of a series of changes that make block_write_begin/end take a folio instead of +# a struct pagep. +ifneq (,$(shell grep 'int __block_write_begin.struct.folio' include/linux/buffer_head.h)) +ccflags-y += -DKC_BLOCK_WRITE_BEGIN_FOLIO +endif diff --git a/kmod/src/data.c b/kmod/src/data.c index 0f2cb098b..ce38c4bec 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -853,7 +853,7 @@ static int scoutfs_write_begin(struct file *file, #ifdef KC_BLOCK_WRITE_BEGIN_AOP_FLAGS unsigned flags, #endif - struct page **pagep, void **fsdata) + KC_PAGE_OR_FOLIO(struct page **pagep, struct folio **folio), void **fsdata) { struct inode *inode = mapping->host; struct scoutfs_inode_info *si = SCOUTFS_I(inode); @@ -898,7 +898,7 @@ static int scoutfs_write_begin(struct file *file, #ifdef KC_BLOCK_WRITE_BEGIN_AOP_FLAGS flags, #endif - pagep, scoutfs_get_block_write); + KC_PAGE_OR_FOLIO(pagep, folio), scoutfs_get_block_write); if (ret < 0) { scoutfs_release_trans(sb); scoutfs_inode_index_unlock(sb, &wbd->ind_locks); @@ -931,7 +931,8 @@ static int writepages_sync_none(struct address_space *mapping, loff_t start, static int scoutfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) + KC_PAGE_OR_FOLIO(struct page *pagep, struct folio *folio), + void *fsdata) { struct inode *inode = mapping->host; struct scoutfs_inode_info *si = SCOUTFS_I(inode); @@ -939,10 +940,11 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping, struct write_begin_data *wbd = fsdata; int ret; - trace_scoutfs_write_end(sb, scoutfs_ino(inode), page->index, (u64)pos, - len, copied); + trace_scoutfs_write_end(sb, scoutfs_ino(inode), + KC_PAGE_OR_FOLIO(pagep->index, folio_index(folio)), + (u64)pos, len, copied); - ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + ret = generic_write_end(file, mapping, pos, len, copied, KC_PAGE_OR_FOLIO(pagep, folio), fsdata); if (ret > 0) { if (!si->staging) { scoutfs_inode_set_data_seq(inode); @@ -1981,7 +1983,11 @@ static int scoutfs_data_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { #endif +#ifdef KC_MPAGE_READ_FOLIO + struct folio *folio = page_folio(vmf->page); +#else struct page *page = vmf->page; +#endif struct file *file = vma->vm_file; struct inode *inode = file_inode(file); struct scoutfs_inode_info *si = SCOUTFS_I(inode); @@ -2049,27 +2055,50 @@ static int scoutfs_data_page_mkwrite(struct vm_area_struct *vma, down_write(&si->extent_sem); +#ifdef KC_MPAGE_READ_FOLIO + if (!folio_trylock(folio)) { +#else if (!trylock_page(page)) { +#endif ret = VM_FAULT_NOPAGE; goto out_sem; } ret = VM_FAULT_LOCKED; +#ifdef KC_MPAGE_READ_FOLIO + if ((folio->mapping != inode->i_mapping) || + (!folio_test_uptodate(folio)) || + (folio_pos(folio) > size)) { + folio_unlock(folio); +#else if ((page->mapping != inode->i_mapping) || (!PageUptodate(page)) || - (page_offset(page) > size)) { + (page_offset(page) > size)) { unlock_page(page); +#endif ret = VM_FAULT_NOPAGE; goto out_sem; } +#ifdef KC_MPAGE_READ_FOLIO + if (folio_index(folio) == (size - 1) >> PAGE_SHIFT) +#else if (page->index == (size - 1) >> PAGE_SHIFT) +#endif len = ((size - 1) & ~PAGE_MASK) + 1; +#ifdef KC_MPAGE_READ_FOLIO + err = __block_write_begin(KC_PAGE_OR_FOLIO(folio_page(folio, 0), folio), pos, PAGE_SIZE, scoutfs_get_block); +#else err = __block_write_begin(page, pos, PAGE_SIZE, scoutfs_get_block); +#endif if (err) { ret = vmf_error(err); +#ifdef KC_MPAGE_READ_FOLIO + folio_unlock(folio); +#else unlock_page(page); +#endif goto out_sem; } /* end scoutfs_write_begin */ @@ -2079,8 +2108,13 @@ static int scoutfs_data_page_mkwrite(struct vm_area_struct *vma, * progress, we are guaranteed that writeback during freezing will * see the dirty page and writeprotect it again. */ +#ifdef KC_MPAGE_READ_FOLIO + folio_mark_dirty(folio); + folio_wait_stable(folio); +#else set_page_dirty(page); wait_for_stable_page(page); +#endif /* scoutfs_write_end */ scoutfs_inode_set_data_seq(inode); diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 9df5e6a4d..3d2db22da 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -650,4 +650,10 @@ static inline long inode_get_atime_nsec(const struct inode *inode) #define KC_KOBJ_DEFAULT_PICK(group, attrs) (attrs) #endif +#ifdef KC_BLOCK_WRITE_BEGIN_FOLIO +#define KC_PAGE_OR_FOLIO(p, f) f +#else +#define KC_PAGE_OR_FOLIO(p, f) p +#endif + #endif