@@ -185,50 +185,6 @@ struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
185
185
return ret == - ENOENT ? NULL : ERR_PTR (ret );
186
186
}
187
187
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
-
232
188
/*
233
189
* Look up an entry in a dynroot directory.
234
190
*/
@@ -247,10 +203,6 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
247
203
return ERR_PTR (- ENAMETOOLONG );
248
204
}
249
205
250
- if (dentry -> d_name .len == 5 &&
251
- memcmp (dentry -> d_name .name , "@cell" , 5 ) == 0 )
252
- return afs_lookup_atcell (dentry );
253
-
254
206
return d_splice_alias (afs_try_auto_mntpt (dentry , dir ), dentry );
255
207
}
256
208
@@ -343,6 +295,131 @@ void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
343
295
_leave ("" );
344
296
}
345
297
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
+
346
423
/*
347
424
* Populate a newly created dynamic root with cell names.
348
425
*/
@@ -355,6 +432,10 @@ int afs_dynroot_populate(struct super_block *sb)
355
432
mutex_lock (& net -> proc_cells_lock );
356
433
357
434
net -> dynroot_sb = sb ;
435
+ ret = afs_dynroot_symlink (net );
436
+ if (ret < 0 )
437
+ goto error ;
438
+
358
439
hlist_for_each_entry (cell , & net -> proc_cells , proc_link ) {
359
440
ret = afs_dynroot_mkdir (net , cell );
360
441
if (ret < 0 )
0 commit comments