Skip to content

Commit 9b83cfc

Browse files
committed
Linux 6.17: d_set_d_op() is no longer available
We only have extremely narrow uses, so move it all into a single function that does only what we need, with and without d_set_d_op(). Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <[email protected]>
1 parent 5a1981a commit 9b83cfc

File tree

3 files changed

+55
-36
lines changed

3 files changed

+55
-36
lines changed

config/kernel-dentry-operations.m4

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ dnl #
2424
dnl # 2.6.38 API change
2525
dnl # Added d_set_d_op() helper function.
2626
dnl #
27+
dnl # 6.17 API change
28+
dnl # d_set_d_op() removed. No direct replacement.
29+
dnl #
2730
AC_DEFUN([ZFS_AC_KERNEL_SRC_D_SET_D_OP], [
2831
ZFS_LINUX_TEST_SRC([d_set_d_op], [
2932
#include <linux/dcache.h>
@@ -34,11 +37,12 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_D_SET_D_OP], [
3437

3538
AC_DEFUN([ZFS_AC_KERNEL_D_SET_D_OP], [
3639
AC_MSG_CHECKING([whether d_set_d_op() is available])
37-
ZFS_LINUX_TEST_RESULT_SYMBOL([d_set_d_op],
38-
[d_set_d_op], [fs/dcache.c], [
40+
ZFS_LINUX_TEST_RESULT([d_set_d_op], [
3941
AC_MSG_RESULT(yes)
42+
AC_DEFINE(HAVE_D_SET_D_OP, 1,
43+
[Define if d_set_d_op() is available])
4044
], [
41-
ZFS_LINUX_TEST_ERROR([d_set_d_op])
45+
AC_MSG_RESULT(no)
4246
])
4347
])
4448

include/os/linux/kernel/linux/dcache_compat.h

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -60,32 +60,6 @@
6060
} while (0)
6161
#endif
6262

63-
/*
64-
* 2.6.30 API change,
65-
* The const keyword was added to the 'struct dentry_operations' in
66-
* the dentry structure. To handle this we define an appropriate
67-
* dentry_operations_t typedef which can be used.
68-
*/
69-
typedef const struct dentry_operations dentry_operations_t;
70-
71-
/*
72-
* 2.6.38 API addition,
73-
* Added d_clear_d_op() helper function which clears some flags and the
74-
* registered dentry->d_op table. This is required because d_set_d_op()
75-
* issues a warning when the dentry operations table is already set.
76-
* For the .zfs control directory to work properly we must be able to
77-
* override the default operations table and register custom .d_automount
78-
* and .d_revalidate callbacks.
79-
*/
80-
static inline void
81-
d_clear_d_op(struct dentry *dentry)
82-
{
83-
dentry->d_op = NULL;
84-
dentry->d_flags &= ~(
85-
DCACHE_OP_HASH | DCACHE_OP_COMPARE |
86-
DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE);
87-
}
88-
8963
/*
9064
* Walk and invalidate all dentry aliases of an inode
9165
* unless it's a mountpoint

module/os/linux/zfs/zpl_ctldir.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ zpl_snapdir_revalidate(struct dentry *dentry, unsigned int flags)
202202
return (!!dentry->d_inode);
203203
}
204204

205-
static dentry_operations_t zpl_dops_snapdirs = {
205+
static const struct dentry_operations zpl_dops_snapdirs = {
206206
/*
207207
* Auto mounting of snapshots is only supported for 2.6.37 and
208208
* newer kernels. Prior to this kernel the ops->follow_link()
@@ -215,6 +215,51 @@ static dentry_operations_t zpl_dops_snapdirs = {
215215
.d_revalidate = zpl_snapdir_revalidate,
216216
};
217217

218+
/*
219+
* For the .zfs control directory to work properly we must be able to override
220+
* the default operations table and register custom .d_automount and
221+
* .d_revalidate callbacks.
222+
*/
223+
static void
224+
set_snapdir_dentry_ops(struct dentry *dentry, unsigned int extraflags) {
225+
static const unsigned int op_flags =
226+
DCACHE_OP_HASH | DCACHE_OP_COMPARE |
227+
DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE |
228+
DCACHE_OP_PRUNE | DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_REAL;
229+
230+
#ifdef HAVE_D_SET_D_OP
231+
/*
232+
* d_set_d_op() will set the DCACHE_OP_ flags according to what it
233+
* finds in the passed dentry_operations, so we don't have to.
234+
*
235+
* We clear the flags and the old op table before calling d_set_d_op()
236+
* because issues a warning when the dentry operations table is already
237+
* set.
238+
*/
239+
dentry->d_op = NULL;
240+
dentry->d_flags &= ~op_flags;
241+
d_set_d_op(dentry, &zpl_dops_snapdirs);
242+
dentry->d_flags |= extraflags;
243+
#else
244+
/*
245+
* Since 6.17 there's no exported way to modify dentry ops, so we have
246+
* to reach in and do it ourselves. This should be safe for our very
247+
* narrow use case, which is to create or splice in an entry to give
248+
* access to a snapshot.
249+
*
250+
* We need to set the op flags directly. We hardcode
251+
* DCACHE_OP_REVALIDATE because that's the only operation we have; if
252+
* we ever extend zpl_dops_snapdirs we will need to update the op flags
253+
* to match.
254+
*/
255+
spin_lock(&dentry->d_lock);
256+
dentry->d_op = &zpl_dops_snapdirs;
257+
dentry->d_flags &= ~op_flags;
258+
dentry->d_flags |= DCACHE_OP_REVALIDATE | extraflags;
259+
spin_unlock(&dentry->d_lock);
260+
#endif
261+
}
262+
218263
static struct dentry *
219264
zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
220265
unsigned int flags)
@@ -236,10 +281,7 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
236281
return (ERR_PTR(error));
237282

238283
ASSERT(error == 0 || ip == NULL);
239-
d_clear_d_op(dentry);
240-
d_set_d_op(dentry, &zpl_dops_snapdirs);
241-
dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
242-
284+
set_snapdir_dentry_ops(dentry, DCACHE_NEED_AUTOMOUNT);
243285
return (d_splice_alias(ip, dentry));
244286
}
245287

@@ -373,8 +415,7 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
373415

374416
error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0);
375417
if (error == 0) {
376-
d_clear_d_op(dentry);
377-
d_set_d_op(dentry, &zpl_dops_snapdirs);
418+
set_snapdir_dentry_ops(dentry, 0);
378419
d_instantiate(dentry, ip);
379420
}
380421

0 commit comments

Comments
 (0)