From bb740d66de2b03a24bd7bfc9cef1844ad3e22a74 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 4 Apr 2025 16:59:15 +1100 Subject: [PATCH] Linux 6.15: mkdir now returns struct dentry * The intent is that the filesystem may have a reference to an "old" version of the new directory, eg if it was keeping it alive because a remote NFS client still had it open. We don't need anything like that, so this really just changes things so we return error codes encoded in pointers. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Reviewed-by: Tony Hutter Reviewed-by: Pavel Snajdr Signed-off-by: Rob Norris Closes #17229 --- config/kernel-mkdir.m4 | 57 +++++++++++++++++++++++--------- module/os/linux/zfs/zpl_ctldir.c | 12 ++++++- module/os/linux/zfs/zpl_inode.c | 21 +++++++++--- 3 files changed, 70 insertions(+), 20 deletions(-) diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4 index 8e084443c..c1aebc387 100644 --- a/config/kernel-mkdir.m4 +++ b/config/kernel-mkdir.m4 @@ -2,6 +2,22 @@ dnl # dnl # Supported mkdir() interfaces checked newest to oldest. dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [ + dnl # + dnl # 6.15 API change + dnl # mkdir() returns struct dentry * + dnl # + ZFS_LINUX_TEST_SRC([mkdir_return_dentry], [ + #include + + static struct dentry *mkdir(struct mnt_idmap *idmap, + struct inode *inode, struct dentry *dentry, + umode_t umode) { return dentry; } + static const struct inode_operations + iops __attribute__ ((unused)) = { + .mkdir = mkdir, + }; + ],[]) + dnl # dnl # 6.3 API change dnl # mkdir() takes struct mnt_idmap * as the first arg @@ -59,29 +75,40 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [ AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [ dnl # - dnl # 6.3 API change - dnl # mkdir() takes struct mnt_idmap * as the first arg + dnl # 6.15 API change + dnl # mkdir() returns struct dentry * dnl # - AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*]) - ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [ + AC_MSG_CHECKING([whether iops->mkdir() returns struct dentry*]) + ZFS_LINUX_TEST_RESULT([mkdir_return_dentry], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1, - [iops->mkdir() takes struct mnt_idmap*]) + AC_DEFINE(HAVE_IOPS_MKDIR_DENTRY, 1, + [iops->mkdir() returns struct dentry*]) ],[ - AC_MSG_RESULT(no) - dnl # - dnl # 5.12 API change - dnl # The struct user_namespace arg was added as the first argument to - dnl # mkdir() of the iops structure. + dnl # 6.3 API change + dnl # mkdir() takes struct mnt_idmap * as the first arg dnl # - AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*]) - ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [ + AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*]) + ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1, - [iops->mkdir() takes struct user_namespace*]) + AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1, + [iops->mkdir() takes struct mnt_idmap*]) ],[ AC_MSG_RESULT(no) + + dnl # + dnl # 5.12 API change + dnl # The struct user_namespace arg was added as the first argument to + dnl # mkdir() of the iops structure. + dnl # + AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1, + [iops->mkdir() takes struct user_namespace*]) + ],[ + AC_MSG_RESULT(no) + ]) ]) ]) ]) diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index 0b04ec686..48dae79a2 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -341,14 +341,20 @@ zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry) return (error); } +#if defined(HAVE_IOPS_MKDIR_USERNS) static int -#ifdef HAVE_IOPS_MKDIR_USERNS zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip, struct dentry *dentry, umode_t mode) #elif defined(HAVE_IOPS_MKDIR_IDMAP) +static int +zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip, + struct dentry *dentry, umode_t mode) +#elif defined(HAVE_IOPS_MKDIR_DENTRY) +static struct dentry * zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip, struct dentry *dentry, umode_t mode) #else +static int zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) #endif { @@ -376,7 +382,11 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) ASSERT3S(error, <=, 0); crfree(cr); +#if defined(HAVE_IOPS_MKDIR_DENTRY) + return (ERR_PTR(error)); +#else return (error); +#endif } /* diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 85df9b9ac..f9f6406f8 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -374,14 +374,20 @@ zpl_unlink(struct inode *dir, struct dentry *dentry) return (error); } +#if defined(HAVE_IOPS_MKDIR_USERNS) static int -#ifdef HAVE_IOPS_MKDIR_USERNS zpl_mkdir(struct user_namespace *user_ns, struct inode *dir, struct dentry *dentry, umode_t mode) #elif defined(HAVE_IOPS_MKDIR_IDMAP) +static int +zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir, + struct dentry *dentry, umode_t mode) +#elif defined(HAVE_IOPS_MKDIR_DENTRY) +static struct dentry * zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir, struct dentry *dentry, umode_t mode) #else +static int zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) #endif { @@ -390,12 +396,14 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) znode_t *zp; int error; fstrans_cookie_t cookie; -#if !(defined(HAVE_IOPS_MKDIR_USERNS) || defined(HAVE_IOPS_MKDIR_IDMAP)) +#if !(defined(HAVE_IOPS_MKDIR_USERNS) || \ + defined(HAVE_IOPS_MKDIR_IDMAP) || defined(HAVE_IOPS_MKDIR_DENTRY)) zidmap_t *user_ns = kcred->user_ns; #endif if (is_nametoolong(dentry)) { - return (-ENAMETOOLONG); + error = -ENAMETOOLONG; + goto err; } crhold(cr); @@ -422,9 +430,14 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) spl_fstrans_unmark(cookie); kmem_free(vap, sizeof (vattr_t)); crfree(cr); - ASSERT3S(error, <=, 0); +err: + ASSERT3S(error, <=, 0); +#if defined(HAVE_IOPS_MKDIR_DENTRY) + return (error != 0 ? ERR_PTR(error) : NULL); +#else return (error); +#endif } static int