diff options
-rw-r--r-- | config/kernel-dentry-operations.m4 | 64 | ||||
-rw-r--r-- | config/kernel.m4 | 3 | ||||
-rw-r--r-- | include/linux/dcache_compat.h | 25 | ||||
-rw-r--r-- | module/zfs/zpl_ctldir.c | 124 |
4 files changed, 158 insertions, 58 deletions
diff --git a/config/kernel-dentry-operations.m4 b/config/kernel-dentry-operations.m4 new file mode 100644 index 000000000..5685b7d6f --- /dev/null +++ b/config/kernel-dentry-operations.m4 @@ -0,0 +1,64 @@ +dnl # +dnl # 3.6 API change +dnl # +AC_DEFUN([ZFS_AC_KERNEL_D_REVALIDATE_NAMEIDATA], [ + AC_MSG_CHECKING([whether dops->d_revalidate() takes struct nameidata]) + ZFS_LINUX_TRY_COMPILE([ + #include <linux/dcache.h> + ],[ + int (*revalidate) (struct dentry *, struct nameidata *) = NULL; + struct dentry_operations dops __attribute__ ((unused)) = { + .d_revalidate = revalidate, + }; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_D_REVALIDATE_NAMEIDATA, 1, + [dops->d_revalidate() operation takes nameidata]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + +dnl # +dnl # 2.6.30 API change +dnl # The 'struct dentry_operations' was constified in the dentry structure. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_CONST_DENTRY_OPERATIONS], [ + AC_MSG_CHECKING([whether dentry uses const struct dentry_operations]) + ZFS_LINUX_TRY_COMPILE([ + #include <linux/dcache.h> + + const struct dentry_operations test_d_op = { + .d_revalidate = NULL, + }; + ],[ + struct dentry d __attribute__ ((unused)); + + d.d_op = &test_d_op; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_CONST_DENTRY_OPERATIONS, 1, + [dentry uses const struct dentry_operations]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + +dnl # +dnl # 2.6.38 API change +dnl # Added d_set_d_op() helper function. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_D_SET_D_OP], + [AC_MSG_CHECKING([whether d_set_d_op() is available]) + ZFS_LINUX_TRY_COMPILE_SYMBOL([ + #include <linux/dcache.h> + ], [ + d_set_d_op(NULL, NULL); + ], [d_set_d_op], [fs/dcache.c], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_D_SET_D_OP, 1, + [d_set_d_op() is available]) + ], [ + AC_MSG_RESULT(no) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index aab3a167b..58a808011 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -62,6 +62,9 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [ ZFS_AC_KERNEL_INSERT_INODE_LOCKED ZFS_AC_KERNEL_D_MAKE_ROOT ZFS_AC_KERNEL_D_OBTAIN_ALIAS + ZFS_AC_KERNEL_D_SET_D_OP + ZFS_AC_KERNEL_D_REVALIDATE_NAMEIDATA + ZFS_AC_KERNEL_CONST_DENTRY_OPERATIONS ZFS_AC_KERNEL_CHECK_DISK_SIZE_CHANGE ZFS_AC_KERNEL_TRUNCATE_SETSIZE ZFS_AC_KERNEL_6ARGS_SECURITY_INODE_INIT_SECURITY diff --git a/include/linux/dcache_compat.h b/include/linux/dcache_compat.h index a42356276..271a0cbef 100644 --- a/include/linux/dcache_compat.h +++ b/include/linux/dcache_compat.h @@ -35,4 +35,29 @@ #define d_make_root(inode) d_alloc_root(inode) #endif /* HAVE_D_MAKE_ROOT */ +/* + * 2.6.30 API change, + * The const keyword was added to the 'struct dentry_operations' in + * the dentry structure. To handle this we define an appropriate + * dentry_operations_t typedef which can be used. + */ +#ifdef HAVE_CONST_DENTRY_OPERATIONS +typedef const struct dentry_operations dentry_operations_t; +#else +typedef struct dentry_operations dentry_operations_t; +#endif + +/* + * 2.6.38 API change, + * Added d_set_d_op() helper function which sets some flags in + * dentry->d_flags based on which operations are defined. + */ +#ifndef HAVE_D_SET_D_OP +static inline void +d_set_d_op(struct dentry *dentry, dentry_operations_t *op) +{ + dentry->d_op = op; +} +#endif /* HAVE_D_SET_D_OP */ + #endif /* _ZFS_DCACHE_H */ diff --git a/module/zfs/zpl_ctldir.c b/module/zfs/zpl_ctldir.c index 7dfaf6ebc..2e5209f8c 100644 --- a/module/zfs/zpl_ctldir.c +++ b/module/zfs/zpl_ctldir.c @@ -183,6 +183,66 @@ const struct inode_operations zpl_ops_root = { .getattr = zpl_root_getattr, }; +#ifdef HAVE_AUTOMOUNT +static struct vfsmount * +zpl_snapdir_automount(struct path *path) +{ + struct dentry *dentry = path->dentry; + int error; + + /* + * We must briefly disable automounts for this dentry because the + * user space mount utility will trigger another lookup on this + * directory. That will result in zpl_snapdir_automount() being + * called repeatedly. The DCACHE_NEED_AUTOMOUNT flag can be + * safely reset once the mount completes. + */ + dentry->d_flags &= ~DCACHE_NEED_AUTOMOUNT; + error = -zfsctl_mount_snapshot(path, 0); + dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; + if (error) + return ERR_PTR(error); + + /* + * Rather than returning the new vfsmount for the snapshot we must + * return NULL to indicate a mount collision. This is done because + * the user space mount calls do_add_mount() which adds the vfsmount + * to the name space. If we returned the new mount here it would be + * added again to the vfsmount list resulting in list corruption. + */ + return (NULL); +} +#endif /* HAVE_AUTOMOUNT */ + +/* + * Revalidate any dentry in the snapshot directory on lookup, since a snapshot + * having the same name have been created or destroyed since it was cached. + */ +static int +#ifdef HAVE_D_REVALIDATE_NAMEIDATA +zpl_snapdir_revalidate(struct dentry *dentry, struct nameidata *i) +#else +zpl_snapdir_revalidate(struct dentry *dentry, unsigned int flags) +#endif +{ + return 0; +} + +dentry_operations_t zpl_dops_snapdirs = { +/* + * Auto mounting of snapshots is only supported for 2.6.37 and + * newer kernels. Prior to this kernel the ops->follow_link() + * callback was used as a hack to trigger the mount. The + * resulting vfsmount was then explicitly grafted in to the + * name space. While it might be possible to add compatibility + * code to accomplish this it would require considerable care. + */ +#ifdef HAVE_AUTOMOUNT + .d_automount = zpl_snapdir_automount, +#endif /* HAVE_AUTOMOUNT */ + .d_revalidate = zpl_snapdir_revalidate, +}; + static struct dentry * #ifdef HAVE_LOOKUP_NAMEIDATA zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, @@ -194,7 +254,7 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, { cred_t *cr = CRED(); - struct inode *ip; + struct inode *ip = NULL; int error; crhold(cr); @@ -203,24 +263,11 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, ASSERT3S(error, <=, 0); crfree(cr); - if (error) { - if (error == -ENOENT) - return d_splice_alias(NULL, dentry); - else - return ERR_PTR(error); - } + if (error && error != -ENOENT) + return ERR_PTR(error); - /* - * Auto mounting of snapshots is only supported for 2.6.37 and - * newer kernels. Prior to this kernel the ops->follow_link() - * callback was used as a hack to trigger the mount. The - * resulting vfsmount was then explicitly grafted in to the - * name space. While it might be possible to add compatibility - * code to accomplish this it would require considerable care. - */ -#ifdef HAVE_AUTOMOUNT - dentry->d_op = &zpl_dops_snapdirs; -#endif /* HAVE_AUTOMOUNT */ + ASSERT(error == 0 || ip == NULL); + d_set_d_op(dentry, &zpl_dops_snapdirs); return d_splice_alias(ip, dentry); } @@ -323,9 +370,7 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode) error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0); if (error == 0) { -#ifdef HAVE_AUTOMOUNT - dentry->d_op = &zpl_dops_snapdirs; -#endif /* HAVE_AUTOMOUNT */ + d_set_d_op(dentry, &zpl_dops_snapdirs); d_instantiate(dentry, ip); } @@ -336,37 +381,6 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode) return (error); } -#ifdef HAVE_AUTOMOUNT -static struct vfsmount * -zpl_snapdir_automount(struct path *path) -{ - struct dentry *dentry = path->dentry; - int error; - - /* - * We must briefly disable automounts for this dentry because the - * user space mount utility will trigger another lookup on this - * directory. That will result in zpl_snapdir_automount() being - * called repeatedly. The DCACHE_NEED_AUTOMOUNT flag can be - * safely reset once the mount completes. - */ - dentry->d_flags &= ~DCACHE_NEED_AUTOMOUNT; - error = -zfsctl_mount_snapshot(path, 0); - dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; - if (error) - return ERR_PTR(error); - - /* - * Rather than returning the new vfsmount for the snapshot we must - * return NULL to indicate a mount collision. This is done because - * the user space mount calls do_add_mount() which adds the vfsmount - * to the name space. If we returned the new mount here it would be - * added again to the vfsmount list resulting in list corruption. - */ - return (NULL); -} -#endif /* HAVE_AUTOMOUNT */ - /* * Get snapshot directory attributes. */ @@ -413,12 +427,6 @@ const struct inode_operations zpl_ops_snapdir = { .mkdir = zpl_snapdir_mkdir, }; -#ifdef HAVE_AUTOMOUNT -const struct dentry_operations zpl_dops_snapdirs = { - .d_automount = zpl_snapdir_automount, -}; -#endif /* HAVE_AUTOMOUNT */ - static struct dentry * #ifdef HAVE_LOOKUP_NAMEIDATA zpl_shares_lookup(struct inode *dip, struct dentry *dentry, |