Skip to content

Commit 0da0b7f

Browse files
committed
afs: Display manually added cells in dynamic root mount
Alter the dynroot mount so that cells created by manipulation of /proc/fs/afs/cells and /proc/fs/afs/rootcell and by specification of a root cell as a module parameter will cause directories for those cells to be created in the dynamic root superblock for the network namespace[*]. To this end: (1) Only one dynamic root superblock is now created per network namespace and this is shared between all attempts to mount it. This makes it easier to find the superblock to modify. (2) When a dynamic root superblock is created, the list of cells is walked and directories created for each cell already defined. (3) When a new cell is added, if a dynamic root superblock exists, a directory is created for it. (4) When a cell is destroyed, the directory is removed. (5) These directories are created by calling lookup_one_len() on the root dir which automatically creates them if they don't exist. [*] Inasmuch as network namespaces are currently supported here. Signed-off-by: David Howells <[email protected]>
1 parent c88d5a7 commit 0da0b7f

File tree

7 files changed

+200
-27
lines changed

7 files changed

+200
-27
lines changed

fs/afs/cell.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/dns_resolver.h>
1616
#include <linux/sched.h>
1717
#include <linux/inet.h>
18+
#include <linux/namei.h>
1819
#include <keys/rxrpc-type.h>
1920
#include "internal.h"
2021

@@ -531,9 +532,11 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
531532
ret = afs_proc_cell_setup(cell);
532533
if (ret < 0)
533534
return ret;
534-
spin_lock(&net->proc_cells_lock);
535+
536+
mutex_lock(&net->proc_cells_lock);
535537
list_add_tail(&cell->proc_link, &net->proc_cells);
536-
spin_unlock(&net->proc_cells_lock);
538+
afs_dynroot_mkdir(net, cell);
539+
mutex_unlock(&net->proc_cells_lock);
537540
return 0;
538541
}
539542

@@ -546,9 +549,10 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
546549

547550
afs_proc_cell_remove(cell);
548551

549-
spin_lock(&net->proc_cells_lock);
552+
mutex_lock(&net->proc_cells_lock);
550553
list_del_init(&cell->proc_link);
551-
spin_unlock(&net->proc_cells_lock);
554+
afs_dynroot_rmdir(net, cell);
555+
mutex_unlock(&net->proc_cells_lock);
552556

553557
#ifdef CONFIG_AFS_FSCACHE
554558
fscache_relinquish_cookie(cell->cache, NULL, false);

fs/afs/dynroot.c

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* dir.c: AFS dynamic root handling
1+
/* AFS dynamic root handling
22
*
33
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
44
* Written by David Howells ([email protected])
@@ -207,3 +207,125 @@ const struct dentry_operations afs_dynroot_dentry_operations = {
207207
.d_release = afs_d_release,
208208
.d_automount = afs_d_automount,
209209
};
210+
211+
/*
212+
* Create a manually added cell mount directory.
213+
* - The caller must hold net->proc_cells_lock
214+
*/
215+
int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
216+
{
217+
struct super_block *sb = net->dynroot_sb;
218+
struct dentry *root, *subdir;
219+
int ret;
220+
221+
if (!sb || atomic_read(&sb->s_active) == 0)
222+
return 0;
223+
224+
/* Let the ->lookup op do the creation */
225+
root = sb->s_root;
226+
inode_lock(root->d_inode);
227+
subdir = lookup_one_len(cell->name, root, cell->name_len);
228+
if (IS_ERR(subdir)) {
229+
ret = PTR_ERR(subdir);
230+
goto unlock;
231+
}
232+
233+
/* Note that we're retaining an extra ref on the dentry */
234+
subdir->d_fsdata = (void *)1UL;
235+
ret = 0;
236+
unlock:
237+
inode_unlock(root->d_inode);
238+
return ret;
239+
}
240+
241+
/*
242+
* Remove a manually added cell mount directory.
243+
* - The caller must hold net->proc_cells_lock
244+
*/
245+
void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
246+
{
247+
struct super_block *sb = net->dynroot_sb;
248+
struct dentry *root, *subdir;
249+
250+
if (!sb || atomic_read(&sb->s_active) == 0)
251+
return;
252+
253+
root = sb->s_root;
254+
inode_lock(root->d_inode);
255+
256+
/* Don't want to trigger a lookup call, which will re-add the cell */
257+
subdir = try_lookup_one_len(cell->name, root, cell->name_len);
258+
if (IS_ERR_OR_NULL(subdir)) {
259+
_debug("lookup %ld", PTR_ERR(subdir));
260+
goto no_dentry;
261+
}
262+
263+
_debug("rmdir %pd %u", subdir, d_count(subdir));
264+
265+
if (subdir->d_fsdata) {
266+
_debug("unpin %u", d_count(subdir));
267+
subdir->d_fsdata = NULL;
268+
dput(subdir);
269+
}
270+
dput(subdir);
271+
no_dentry:
272+
inode_unlock(root->d_inode);
273+
_leave("");
274+
}
275+
276+
/*
277+
* Populate a newly created dynamic root with cell names.
278+
*/
279+
int afs_dynroot_populate(struct super_block *sb)
280+
{
281+
struct afs_cell *cell;
282+
struct afs_net *net = afs_sb2net(sb);
283+
int ret;
284+
285+
if (mutex_lock_interruptible(&net->proc_cells_lock) < 0)
286+
return -ERESTARTSYS;
287+
288+
net->dynroot_sb = sb;
289+
list_for_each_entry(cell, &net->proc_cells, proc_link) {
290+
ret = afs_dynroot_mkdir(net, cell);
291+
if (ret < 0)
292+
goto error;
293+
}
294+
295+
ret = 0;
296+
out:
297+
mutex_unlock(&net->proc_cells_lock);
298+
return ret;
299+
300+
error:
301+
net->dynroot_sb = NULL;
302+
goto out;
303+
}
304+
305+
/*
306+
* When a dynamic root that's in the process of being destroyed, depopulate it
307+
* of pinned directories.
308+
*/
309+
void afs_dynroot_depopulate(struct super_block *sb)
310+
{
311+
struct afs_net *net = afs_sb2net(sb);
312+
struct dentry *root = sb->s_root, *subdir, *tmp;
313+
314+
/* Prevent more subdirs from being created */
315+
mutex_lock(&net->proc_cells_lock);
316+
if (net->dynroot_sb == sb)
317+
net->dynroot_sb = NULL;
318+
mutex_unlock(&net->proc_cells_lock);
319+
320+
inode_lock(root->d_inode);
321+
322+
/* Remove all the pins for dirs created for manually added cells */
323+
list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
324+
if (subdir->d_fsdata) {
325+
subdir->d_fsdata = NULL;
326+
dput(subdir);
327+
}
328+
}
329+
330+
inode_unlock(root->d_inode);
331+
}

fs/afs/internal.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ struct afs_net {
240240
atomic_t cells_outstanding;
241241
seqlock_t cells_lock;
242242

243-
spinlock_t proc_cells_lock;
243+
struct mutex proc_cells_lock;
244244
struct list_head proc_cells;
245245

246246
/* Known servers. Theoretically each fileserver can only be in one
@@ -264,6 +264,7 @@ struct afs_net {
264264
struct mutex lock_manager_mutex;
265265

266266
/* Misc */
267+
struct super_block *dynroot_sb; /* Dynamic root mount superblock */
267268
struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */
268269
struct afs_sysnames *sysnames;
269270
rwlock_t sysnames_lock;
@@ -722,6 +723,10 @@ extern const struct inode_operations afs_dynroot_inode_operations;
722723
extern const struct dentry_operations afs_dynroot_dentry_operations;
723724

724725
extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *);
726+
extern int afs_dynroot_mkdir(struct afs_net *, struct afs_cell *);
727+
extern void afs_dynroot_rmdir(struct afs_net *, struct afs_cell *);
728+
extern int afs_dynroot_populate(struct super_block *);
729+
extern void afs_dynroot_depopulate(struct super_block *);
725730

726731
/*
727732
* file.c

fs/afs/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static int __net_init afs_net_init(struct net *net_ns)
8686
INIT_WORK(&net->cells_manager, afs_manage_cells);
8787
timer_setup(&net->cells_timer, afs_cells_timer, 0);
8888

89-
spin_lock_init(&net->proc_cells_lock);
89+
mutex_init(&net->proc_cells_lock);
9090
INIT_LIST_HEAD(&net->proc_cells);
9191

9292
seqlock_init(&net->fs_lock);

fs/afs/super.c

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,17 @@ static int afs_test_super(struct super_block *sb, void *data)
355355

356356
return (as->net_ns == as1->net_ns &&
357357
as->volume &&
358-
as->volume->vid == as1->volume->vid);
358+
as->volume->vid == as1->volume->vid &&
359+
!as->dyn_root);
359360
}
360361

361362
static int afs_dynroot_test_super(struct super_block *sb, void *data)
362363
{
363-
return false;
364+
struct afs_super_info *as1 = data;
365+
struct afs_super_info *as = AFS_FS_S(sb);
366+
367+
return (as->net_ns == as1->net_ns &&
368+
as->dyn_root);
364369
}
365370

366371
static int afs_set_super(struct super_block *sb, void *data)
@@ -420,10 +425,14 @@ static int afs_fill_super(struct super_block *sb,
420425
if (!sb->s_root)
421426
goto error;
422427

423-
if (params->dyn_root)
428+
if (as->dyn_root) {
424429
sb->s_d_op = &afs_dynroot_dentry_operations;
425-
else
430+
ret = afs_dynroot_populate(sb);
431+
if (ret < 0)
432+
goto error;
433+
} else {
426434
sb->s_d_op = &afs_fs_dentry_operations;
435+
}
427436

428437
_leave(" = 0");
429438
return 0;
@@ -458,6 +467,25 @@ static void afs_destroy_sbi(struct afs_super_info *as)
458467
}
459468
}
460469

470+
static void afs_kill_super(struct super_block *sb)
471+
{
472+
struct afs_super_info *as = AFS_FS_S(sb);
473+
struct afs_net *net = afs_net(as->net_ns);
474+
475+
if (as->dyn_root)
476+
afs_dynroot_depopulate(sb);
477+
478+
/* Clear the callback interests (which will do ilookup5) before
479+
* deactivating the superblock.
480+
*/
481+
if (as->volume)
482+
afs_clear_callback_interests(net, as->volume->servers);
483+
kill_anon_super(sb);
484+
if (as->volume)
485+
afs_deactivate_volume(as->volume);
486+
afs_destroy_sbi(as);
487+
}
488+
461489
/*
462490
* get an AFS superblock
463491
*/
@@ -566,22 +594,6 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
566594
return ERR_PTR(ret);
567595
}
568596

569-
static void afs_kill_super(struct super_block *sb)
570-
{
571-
struct afs_super_info *as = AFS_FS_S(sb);
572-
573-
/* Clear the callback interests (which will do ilookup5) before
574-
* deactivating the superblock.
575-
*/
576-
if (as->volume)
577-
afs_clear_callback_interests(afs_net(as->net_ns),
578-
as->volume->servers);
579-
kill_anon_super(sb);
580-
if (as->volume)
581-
afs_deactivate_volume(as->volume);
582-
afs_destroy_sbi(as);
583-
}
584-
585597
/*
586598
* Initialise an inode cache slab element prior to any use. Note that
587599
* afs_alloc_inode() *must* reset anything that could incorrectly leak from one

fs/namei.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,6 +2463,35 @@ static int lookup_one_len_common(const char *name, struct dentry *base,
24632463
return inode_permission(base->d_inode, MAY_EXEC);
24642464
}
24652465

2466+
/**
2467+
* try_lookup_one_len - filesystem helper to lookup single pathname component
2468+
* @name: pathname component to lookup
2469+
* @base: base directory to lookup from
2470+
* @len: maximum length @len should be interpreted to
2471+
*
2472+
* Look up a dentry by name in the dcache, returning NULL if it does not
2473+
* currently exist. The function does not try to create a dentry.
2474+
*
2475+
* Note that this routine is purely a helper for filesystem usage and should
2476+
* not be called by generic code.
2477+
*
2478+
* The caller must hold base->i_mutex.
2479+
*/
2480+
struct dentry *try_lookup_one_len(const char *name, struct dentry *base, int len)
2481+
{
2482+
struct qstr this;
2483+
int err;
2484+
2485+
WARN_ON_ONCE(!inode_is_locked(base->d_inode));
2486+
2487+
err = lookup_one_len_common(name, base, len, &this);
2488+
if (err)
2489+
return ERR_PTR(err);
2490+
2491+
return lookup_dcache(&this, base, 0);
2492+
}
2493+
EXPORT_SYMBOL(try_lookup_one_len);
2494+
24662495
/**
24672496
* lookup_one_len - filesystem helper to lookup single pathname component
24682497
* @name: pathname component to lookup

include/linux/namei.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ extern void done_path_create(struct path *, struct dentry *);
8181
extern struct dentry *kern_path_locked(const char *, struct path *);
8282
extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
8383

84+
extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
8485
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
8586
extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
8687

0 commit comments

Comments
 (0)