@@ -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