aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-06-15 10:19:22 -0400
committerDavid Howells <dhowells@redhat.com>2018-06-15 10:27:09 -0400
commit0da0b7fd73e4f20e1a987dfade0b36bb4813cf10 (patch)
treee0b6e920d546fc0dbf0d813418ad3e4b0d61eabe
parentc88d5a7fff2ef9aeed8aebb06f59d565693d0634 (diff)
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 <dhowells@redhat.com>
-rw-r--r--fs/afs/cell.c12
-rw-r--r--fs/afs/dynroot.c124
-rw-r--r--fs/afs/internal.h7
-rw-r--r--fs/afs/main.c2
-rw-r--r--fs/afs/super.c52
-rw-r--r--fs/namei.c29
-rw-r--r--include/linux/namei.h1
7 files changed, 200 insertions, 27 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index bb92b54d2a4a..f3d0bef16d78 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -15,6 +15,7 @@
15#include <linux/dns_resolver.h> 15#include <linux/dns_resolver.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/inet.h> 17#include <linux/inet.h>
18#include <linux/namei.h>
18#include <keys/rxrpc-type.h> 19#include <keys/rxrpc-type.h>
19#include "internal.h" 20#include "internal.h"
20 21
@@ -531,9 +532,11 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
531 ret = afs_proc_cell_setup(cell); 532 ret = afs_proc_cell_setup(cell);
532 if (ret < 0) 533 if (ret < 0)
533 return ret; 534 return ret;
534 spin_lock(&net->proc_cells_lock); 535
536 mutex_lock(&net->proc_cells_lock);
535 list_add_tail(&cell->proc_link, &net->proc_cells); 537 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);
537 return 0; 540 return 0;
538} 541}
539 542
@@ -546,9 +549,10 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
546 549
547 afs_proc_cell_remove(cell); 550 afs_proc_cell_remove(cell);
548 551
549 spin_lock(&net->proc_cells_lock); 552 mutex_lock(&net->proc_cells_lock);
550 list_del_init(&cell->proc_link); 553 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);
552 556
553#ifdef CONFIG_AFS_FSCACHE 557#ifdef CONFIG_AFS_FSCACHE
554 fscache_relinquish_cookie(cell->cache, NULL, false); 558 fscache_relinquish_cookie(cell->cache, NULL, false);
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index 7425f416ed73..174e843f0633 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -1,4 +1,4 @@
1/* dir.c: AFS dynamic root handling 1/* AFS dynamic root handling
2 * 2 *
3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
@@ -207,3 +207,125 @@ const struct dentry_operations afs_dynroot_dentry_operations = {
207 .d_release = afs_d_release, 207 .d_release = afs_d_release,
208 .d_automount = afs_d_automount, 208 .d_automount = afs_d_automount,
209}; 209};
210
211/*
212 * Create a manually added cell mount directory.
213 * - The caller must hold net->proc_cells_lock
214 */
215int 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;
236unlock:
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 */
245void 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);
271no_dentry:
272 inode_unlock(root->d_inode);
273 _leave("");
274}
275
276/*
277 * Populate a newly created dynamic root with cell names.
278 */
279int 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;
296out:
297 mutex_unlock(&net->proc_cells_lock);
298 return ret;
299
300error:
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 */
309void 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}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 209e04ffa6c3..5d8260b4c2b3 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -240,7 +240,7 @@ struct afs_net {
240 atomic_t cells_outstanding; 240 atomic_t cells_outstanding;
241 seqlock_t cells_lock; 241 seqlock_t cells_lock;
242 242
243 spinlock_t proc_cells_lock; 243 struct mutex proc_cells_lock;
244 struct list_head proc_cells; 244 struct list_head proc_cells;
245 245
246 /* Known servers. Theoretically each fileserver can only be in one 246 /* Known servers. Theoretically each fileserver can only be in one
@@ -264,6 +264,7 @@ struct afs_net {
264 struct mutex lock_manager_mutex; 264 struct mutex lock_manager_mutex;
265 265
266 /* Misc */ 266 /* Misc */
267 struct super_block *dynroot_sb; /* Dynamic root mount superblock */
267 struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */ 268 struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */
268 struct afs_sysnames *sysnames; 269 struct afs_sysnames *sysnames;
269 rwlock_t sysnames_lock; 270 rwlock_t sysnames_lock;
@@ -722,6 +723,10 @@ extern const struct inode_operations afs_dynroot_inode_operations;
722extern const struct dentry_operations afs_dynroot_dentry_operations; 723extern const struct dentry_operations afs_dynroot_dentry_operations;
723 724
724extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *); 725extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *);
726extern int afs_dynroot_mkdir(struct afs_net *, struct afs_cell *);
727extern void afs_dynroot_rmdir(struct afs_net *, struct afs_cell *);
728extern int afs_dynroot_populate(struct super_block *);
729extern void afs_dynroot_depopulate(struct super_block *);
725 730
726/* 731/*
727 * file.c 732 * file.c
diff --git a/fs/afs/main.c b/fs/afs/main.c
index 7d2c1354e2ca..e84fe822a960 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -86,7 +86,7 @@ static int __net_init afs_net_init(struct net *net_ns)
86 INIT_WORK(&net->cells_manager, afs_manage_cells); 86 INIT_WORK(&net->cells_manager, afs_manage_cells);
87 timer_setup(&net->cells_timer, afs_cells_timer, 0); 87 timer_setup(&net->cells_timer, afs_cells_timer, 0);
88 88
89 spin_lock_init(&net->proc_cells_lock); 89 mutex_init(&net->proc_cells_lock);
90 INIT_LIST_HEAD(&net->proc_cells); 90 INIT_LIST_HEAD(&net->proc_cells);
91 91
92 seqlock_init(&net->fs_lock); 92 seqlock_init(&net->fs_lock);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 8707d867334e..4d3e274207fb 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -355,12 +355,17 @@ static int afs_test_super(struct super_block *sb, void *data)
355 355
356 return (as->net_ns == as1->net_ns && 356 return (as->net_ns == as1->net_ns &&
357 as->volume && 357 as->volume &&
358 as->volume->vid == as1->volume->vid); 358 as->volume->vid == as1->volume->vid &&
359 !as->dyn_root);
359} 360}
360 361
361static int afs_dynroot_test_super(struct super_block *sb, void *data) 362static int afs_dynroot_test_super(struct super_block *sb, void *data)
362{ 363{
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);
364} 369}
365 370
366static int afs_set_super(struct super_block *sb, void *data) 371static int afs_set_super(struct super_block *sb, void *data)
@@ -420,10 +425,14 @@ static int afs_fill_super(struct super_block *sb,
420 if (!sb->s_root) 425 if (!sb->s_root)
421 goto error; 426 goto error;
422 427
423 if (params->dyn_root) 428 if (as->dyn_root) {
424 sb->s_d_op = &afs_dynroot_dentry_operations; 429 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 {
426 sb->s_d_op = &afs_fs_dentry_operations; 434 sb->s_d_op = &afs_fs_dentry_operations;
435 }
427 436
428 _leave(" = 0"); 437 _leave(" = 0");
429 return 0; 438 return 0;
@@ -458,6 +467,25 @@ static void afs_destroy_sbi(struct afs_super_info *as)
458 } 467 }
459} 468}
460 469
470static 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
461/* 489/*
462 * get an AFS superblock 490 * get an AFS superblock
463 */ 491 */
@@ -566,22 +594,6 @@ error:
566 return ERR_PTR(ret); 594 return ERR_PTR(ret);
567} 595}
568 596
569static 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
585/* 597/*
586 * Initialise an inode cache slab element prior to any use. Note that 598 * Initialise an inode cache slab element prior to any use. Note that
587 * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 599 * afs_alloc_inode() *must* reset anything that could incorrectly leak from one
diff --git a/fs/namei.c b/fs/namei.c
index 186bd2464fd5..2e0a1c5729f1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2464,6 +2464,35 @@ static int lookup_one_len_common(const char *name, struct dentry *base,
2464} 2464}
2465 2465
2466/** 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 */
2480struct 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}
2493EXPORT_SYMBOL(try_lookup_one_len);
2494
2495/**
2467 * lookup_one_len - filesystem helper to lookup single pathname component 2496 * lookup_one_len - filesystem helper to lookup single pathname component
2468 * @name: pathname component to lookup 2497 * @name: pathname component to lookup
2469 * @base: base directory to lookup from 2498 * @base: base directory to lookup from
diff --git a/include/linux/namei.h b/include/linux/namei.h
index a982bb7cd480..a78606e8e3df 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -81,6 +81,7 @@ extern void done_path_create(struct path *, struct dentry *);
81extern struct dentry *kern_path_locked(const char *, struct path *); 81extern struct dentry *kern_path_locked(const char *, struct path *);
82extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int); 82extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
83 83
84extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
84extern struct dentry *lookup_one_len(const char *, struct dentry *, int); 85extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
85extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int); 86extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
86 87