summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/dcache_compat.h20
-rw-r--r--module/zfs/zpl_ctldir.c2
2 files changed, 22 insertions, 0 deletions
diff --git a/include/linux/dcache_compat.h b/include/linux/dcache_compat.h
index 271a0cbef..2b9e5c1c4 100644
--- a/include/linux/dcache_compat.h
+++ b/include/linux/dcache_compat.h
@@ -60,4 +60,24 @@ d_set_d_op(struct dentry *dentry, dentry_operations_t *op)
}
#endif /* HAVE_D_SET_D_OP */
+/*
+ * 2.6.38 API addition,
+ * Added d_clear_d_op() helper function which clears some flags and the
+ * registered dentry->d_op table. This is required because d_set_d_op()
+ * issues a warning when the dentry operations table is already set.
+ * For the .zfs control directory to work properly we must be able to
+ * override the default operations table and register custom .d_automount
+ * and .d_revalidate callbacks.
+ */
+static inline void
+d_clear_d_op(struct dentry *dentry)
+{
+#ifdef HAVE_D_SET_D_OP
+ dentry->d_op = NULL;
+ dentry->d_flags &=
+ ~(DCACHE_OP_HASH | DCACHE_OP_COMPARE |
+ DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE);
+#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 54bdbe409..089701707 100644
--- a/module/zfs/zpl_ctldir.c
+++ b/module/zfs/zpl_ctldir.c
@@ -267,6 +267,7 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
return ERR_PTR(error);
ASSERT(error == 0 || ip == NULL);
+ d_clear_d_op(dentry);
d_set_d_op(dentry, &zpl_dops_snapdirs);
return d_splice_alias(ip, dentry);
@@ -370,6 +371,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) {
+ d_clear_d_op(dentry);
d_set_d_op(dentry, &zpl_dops_snapdirs);
d_instantiate(dentry, ip);
}