From c87b1e31f62b827e2f421a57362923d78afc2279 Mon Sep 17 00:00:00 2001 From: Cheyenne Wills Date: Tue, 10 Mar 2026 14:24:54 -0600 Subject: [PATCH] Linux: Use set_default_d_op() to set dentry ops The Linux 6.17 commit: 'new helper: set_default_d_op()' (05fb0e666495c) replaced the way that the default dentry_operations is set on a super_block. The s_d_op member was renamed to __s_d_op and a new helper function set_default_d_op() is now used to set the default dentry_operations. The OpenAFS commit 'linux: 2.6.38: New d_op handling' (08bb83d950) added an autoconf test for using the s_d_op member in the super_block struct. With the above Linux commit, the test for STRUCT_SUPER_BLOCK_HAS_S_D_OP fails, and the __s_d_op member in the super_block is not set during afs_fill_super(), but instead dp->d_op is set during various vfs operations. Doing so sets the dentry ops for the dentry, but does not set the flag DCACHE_OP_REVALIDATE on the dentry, and so Linux never calls our d_revalidate function, causing dentries to not get properly revalidated. To fix this, add a new autoconf test for set_default_d_op(), and use that function when available. Add a comment for the autoconf test for the super_block member s_d_op to note the change. Add an additional build time check to ensure that we don't accidentally revert to the pre-2.6.38 behavior after Linux 2.6.38 In afs_fill_super(), use set_default_d_op() to initialize the super_block with the afs_dentry_operations. The dentry->d_op member only needs to be updated when set_default_d_op() is not available and the super_block does not have the s_d_op member. Note: This commit fixes a reported problem with stale dentries that was discovered on a Linux 6.17 system. Reviewed-on: https://gerrit.openafs.org/16700 Tested-by: BuildBot Reviewed-by: Andrew Deason Tested-by: Michael Meffie Reviewed-by: Michael Meffie (cherry picked from commit a99b2ff4c04a9b1a4ba3ab5fac1b37bfd5d43568) Change-Id: Ic454c52ca88c82a9efa62a486ec05300a95c6cb0 (cherry picked from commit 6d0a2107fcab28fc4ba64d365133d171b75bd3dc) --- src/afs/LINUX/osi_vfsops.c | 8 ++++++-- src/afs/LINUX/osi_vnodeops.c | 6 +++--- src/cf/linux-kernel-func.m4 | 10 ++++++++++ src/cf/linux-kernel-struct.m4 | 4 ++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/afs/LINUX/osi_vfsops.c b/src/afs/LINUX/osi_vfsops.c index 18506474ee48..f1e59074760c 100644 --- a/src/afs/LINUX/osi_vfsops.c +++ b/src/afs/LINUX/osi_vfsops.c @@ -117,8 +117,12 @@ afs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic = AFS_VFSMAGIC; sb->s_op = &afs_sops; /* Super block (vfs) ops */ -#if defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) +#if defined(HAVE_LINUX_SET_DEFAULT_D_OP) + set_default_d_op(sb, &afs_dentry_operations); +#elif defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) sb->s_d_op = &afs_dentry_operations; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) +# error "Missing method to set the super_block's dentry operations member" #endif #if defined(HAVE_LINUX_SUPER_SETUP_BDI) code = super_setup_bdi(sb); @@ -221,7 +225,7 @@ afs_root(struct super_block *afsp) #else afsp->s_root = d_alloc_root(ip); #endif -#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) +#if !defined(HAVE_LINUX_SET_DEFAULT_D_OP) && !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) afsp->s_root->d_op = &afs_dentry_operations; #endif afs_DestroyAttr(vattr); diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index b525126c20a1..432643fe5583 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1844,7 +1844,7 @@ afs_linux_create(struct inode *dip, struct dentry *dp, int mode) afs_getattr(vcp, vattr, credp); afs_fill_inode(ip, vattr); insert_inode_hash(ip); -#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) +#if !defined(HAVE_LINUX_SET_DEFAULT_D_OP) && !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) dp->d_op = &afs_dentry_operations; #endif dp->d_time = parent_vcache_dv(dip, credp); @@ -1925,7 +1925,7 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp) afs_DestroyAttr(vattr); } -#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) +#if !defined(HAVE_LINUX_SET_DEFAULT_D_OP) && !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) dp->d_op = &afs_dentry_operations; #endif dp->d_time = parent_vcache_dv(dip, credp); @@ -2171,7 +2171,7 @@ afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode) afs_getattr(tvcp, vattr, credp); afs_fill_inode(ip, vattr); -#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) +#if !defined(HAVE_LINUX_SET_DEFAULT_D_OP) && !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP) dp->d_op = &afs_dentry_operations; #endif dp->d_time = parent_vcache_dv(dip, credp); diff --git a/src/cf/linux-kernel-func.m4 b/src/cf/linux-kernel-func.m4 index 0784262d70b9..6845c9918ad1 100644 --- a/src/cf/linux-kernel-func.m4 +++ b/src/cf/linux-kernel-func.m4 @@ -379,6 +379,16 @@ AC_CHECK_LINUX_FUNC([write_begin_end_kiocb], [[aops->write_begin(kiocb, mapping, 0, 0, &foliop, fsdata); aops->write_end(kiocb, mapping, 0, 0, 0, foliop, fsdata);]]) +dnl Linux 6.17 added a helper function set_default_d_op() to set the default +dnl dentry_operations for a super_block. The super_block member s_d_op is now +dnl a private member of the super_block. +AC_CHECK_LINUX_FUNC([set_default_d_op], + [#include + #include ], + [[static struct super_block sb; + static struct dentry_operations d_op; + set_default_d_op(&sb, &d_op);]]) + dnl Consequences - things which get set as a result of the dnl above tests AS_IF([test "x$ac_cv_linux_func_d_alloc_anon" = "xno"], diff --git a/src/cf/linux-kernel-struct.m4 b/src/cf/linux-kernel-struct.m4 index 24841e9f3245..46c23a25fbb8 100644 --- a/src/cf/linux-kernel-struct.m4 +++ b/src/cf/linux-kernel-struct.m4 @@ -44,6 +44,10 @@ AC_CHECK_LINUX_STRUCT([nameidata], [path], [namei.h]) AC_CHECK_LINUX_STRUCT([proc_dir_entry], [owner], [proc_fs.h]) AC_CHECK_LINUX_STRUCT([proc_ops], [proc_compat_ioctl], [proc_fs.h]) AC_CHECK_LINUX_STRUCT([super_block], [s_bdi], [fs.h]) +dnl Linux 2.6.38 added the s_d_op field to hold the default dentry ops. +dnl Linux 6.17 renamed s_d_op to a private member, requiring users to instead +dnl call set_default_d_op() to initialize the super_block with the default +dnl dentry ops. AC_CHECK_LINUX_STRUCT([super_block], [s_d_op], [fs.h]) AC_CHECK_LINUX_STRUCT([super_operations], [alloc_inode], [fs.h]) -- 2.52.0