@@ -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+
218263static struct dentry *
219264zpl_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