@@ -185,50 +185,6 @@ struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
185185 return ret == - ENOENT ? NULL : ERR_PTR (ret );
186186}
187187
188- /*
189- * Look up @cell in a dynroot directory. This is a substitution for the
190- * local cell name for the net namespace.
191- */
192- static struct dentry * afs_lookup_atcell (struct dentry * dentry )
193- {
194- struct afs_cell * cell ;
195- struct afs_net * net = afs_d2net (dentry );
196- struct dentry * ret ;
197- char * name ;
198- int len ;
199-
200- if (!net -> ws_cell )
201- return ERR_PTR (- ENOENT );
202-
203- ret = ERR_PTR (- ENOMEM );
204- name = kmalloc (AFS_MAXCELLNAME + 1 , GFP_KERNEL );
205- if (!name )
206- goto out_p ;
207-
208- down_read (& net -> cells_lock );
209- cell = net -> ws_cell ;
210- if (cell ) {
211- len = cell -> name_len ;
212- memcpy (name , cell -> name , len + 1 );
213- }
214- up_read (& net -> cells_lock );
215-
216- ret = ERR_PTR (- ENOENT );
217- if (!cell )
218- goto out_n ;
219-
220- ret = lookup_one_len (name , dentry -> d_parent , len );
221-
222- /* We don't want to d_add() the @cell dentry here as we don't want to
223- * the cached dentry to hide changes to the local cell name.
224- */
225-
226- out_n :
227- kfree (name );
228- out_p :
229- return ret ;
230- }
231-
232188/*
233189 * Look up an entry in a dynroot directory.
234190 */
@@ -247,10 +203,6 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
247203 return ERR_PTR (- ENAMETOOLONG );
248204 }
249205
250- if (dentry -> d_name .len == 5 &&
251- memcmp (dentry -> d_name .name , "@cell" , 5 ) == 0 )
252- return afs_lookup_atcell (dentry );
253-
254206 return d_splice_alias (afs_try_auto_mntpt (dentry , dir ), dentry );
255207}
256208
@@ -343,6 +295,131 @@ void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
343295 _leave ("" );
344296}
345297
298+ static void afs_atcell_delayed_put_cell (void * arg )
299+ {
300+ struct afs_cell * cell = arg ;
301+
302+ afs_put_cell (cell , afs_cell_trace_put_atcell );
303+ }
304+
305+ /*
306+ * Read @cell or .@cell symlinks.
307+ */
308+ static const char * afs_atcell_get_link (struct dentry * dentry , struct inode * inode ,
309+ struct delayed_call * done )
310+ {
311+ struct afs_vnode * vnode = AFS_FS_I (inode );
312+ struct afs_cell * cell ;
313+ struct afs_net * net = afs_i2net (inode );
314+ const char * name ;
315+ bool dotted = vnode -> fid .vnode == 3 ;
316+
317+ if (!net -> ws_cell )
318+ return ERR_PTR (- ENOENT );
319+
320+ down_read (& net -> cells_lock );
321+
322+ cell = net -> ws_cell ;
323+ if (dotted )
324+ name = cell -> name - 1 ;
325+ else
326+ name = cell -> name ;
327+ afs_get_cell (cell , afs_cell_trace_get_atcell );
328+ set_delayed_call (done , afs_atcell_delayed_put_cell , cell );
329+
330+ up_read (& net -> cells_lock );
331+ return name ;
332+ }
333+
334+ static const struct inode_operations afs_atcell_inode_operations = {
335+ .get_link = afs_atcell_get_link ,
336+ };
337+
338+ /*
339+ * Look up @cell or .@cell in a dynroot directory. This is a substitution for
340+ * the local cell name for the net namespace.
341+ */
342+ static struct dentry * afs_dynroot_create_symlink (struct dentry * root , const char * name )
343+ {
344+ struct afs_vnode * vnode ;
345+ struct afs_fid fid = { .vnode = 2 , .unique = 1 , };
346+ struct dentry * dentry ;
347+ struct inode * inode ;
348+
349+ if (name [0 ] == '.' )
350+ fid .vnode = 3 ;
351+
352+ dentry = d_alloc_name (root , name );
353+ if (!dentry )
354+ return ERR_PTR (- ENOMEM );
355+
356+ inode = iget5_locked (dentry -> d_sb , fid .vnode ,
357+ afs_iget5_pseudo_test , afs_iget5_pseudo_set , & fid );
358+ if (!inode ) {
359+ dput (dentry );
360+ return ERR_PTR (- ENOMEM );
361+ }
362+
363+ vnode = AFS_FS_I (inode );
364+
365+ /* there shouldn't be an existing inode */
366+ if (WARN_ON_ONCE (!(inode -> i_state & I_NEW ))) {
367+ iput (inode );
368+ dput (dentry );
369+ return ERR_PTR (- EIO );
370+ }
371+
372+ netfs_inode_init (& vnode -> netfs , NULL , false);
373+ simple_inode_init_ts (inode );
374+ set_nlink (inode , 1 );
375+ inode -> i_size = 0 ;
376+ inode -> i_mode = S_IFLNK | 0555 ;
377+ inode -> i_op = & afs_atcell_inode_operations ;
378+ inode -> i_uid = GLOBAL_ROOT_UID ;
379+ inode -> i_gid = GLOBAL_ROOT_GID ;
380+ inode -> i_blocks = 0 ;
381+ inode -> i_generation = 0 ;
382+ inode -> i_flags |= S_NOATIME ;
383+
384+ unlock_new_inode (inode );
385+ d_splice_alias (inode , dentry );
386+ return dentry ;
387+ }
388+
389+ /*
390+ * Create @cell and .@cell symlinks.
391+ */
392+ static int afs_dynroot_symlink (struct afs_net * net )
393+ {
394+ struct super_block * sb = net -> dynroot_sb ;
395+ struct dentry * root , * symlink , * dsymlink ;
396+ int ret ;
397+
398+ /* Let the ->lookup op do the creation */
399+ root = sb -> s_root ;
400+ inode_lock (root -> d_inode );
401+ symlink = afs_dynroot_create_symlink (root , "@cell" );
402+ if (IS_ERR (symlink )) {
403+ ret = PTR_ERR (symlink );
404+ goto unlock ;
405+ }
406+
407+ dsymlink = afs_dynroot_create_symlink (root , ".@cell" );
408+ if (IS_ERR (dsymlink )) {
409+ ret = PTR_ERR (dsymlink );
410+ dput (symlink );
411+ goto unlock ;
412+ }
413+
414+ /* Note that we're retaining extra refs on the dentries. */
415+ symlink -> d_fsdata = (void * )1UL ;
416+ dsymlink -> d_fsdata = (void * )1UL ;
417+ ret = 0 ;
418+ unlock :
419+ inode_unlock (root -> d_inode );
420+ return ret ;
421+ }
422+
346423/*
347424 * Populate a newly created dynamic root with cell names.
348425 */
@@ -355,6 +432,10 @@ int afs_dynroot_populate(struct super_block *sb)
355432 mutex_lock (& net -> proc_cells_lock );
356433
357434 net -> dynroot_sb = sb ;
435+ ret = afs_dynroot_symlink (net );
436+ if (ret < 0 )
437+ goto error ;
438+
358439 hlist_for_each_entry (cell , & net -> proc_cells , proc_link ) {
359440 ret = afs_dynroot_mkdir (net , cell );
360441 if (ret < 0 )
0 commit comments