aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-10-11 17:45:49 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-12 07:18:57 -0400
commit6b3944e42e2e554aa5a4be681ecd70dccd459114 (patch)
tree811bc9bccb4da48aed07bd73891b65181b6e5873 /fs/afs
parent4ea07abbfbdadb10bc67c2b78dc2dbfafa4b1009 (diff)
afs: Fix cell proc list
Access to the list of cells by /proc/net/afs/cells has a couple of problems: (1) It should be checking against SEQ_START_TOKEN for the keying the header line. (2) It's only holding the RCU read lock, so it can't just walk over the list without following the proper RCU methods. Fix these by using an hlist instead of an ordinary list and using the appropriate accessor functions to follow it with RCU. Since the code that adds a cell to the list must also necessarily change, sort the list on insertion whilst we're at it. Fixes: 989782dcdc91 ("afs: Overhaul cell database management") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/cell.c17
-rw-r--r--fs/afs/dynroot.c2
-rw-r--r--fs/afs/internal.h4
-rw-r--r--fs/afs/main.c2
-rw-r--r--fs/afs/proc.c7
5 files changed, 22 insertions, 10 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index f3d0bef16d78..6127f0fcd62c 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -514,6 +514,8 @@ static int afs_alloc_anon_key(struct afs_cell *cell)
514 */ 514 */
515static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell) 515static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
516{ 516{
517 struct hlist_node **p;
518 struct afs_cell *pcell;
517 int ret; 519 int ret;
518 520
519 if (!cell->anonymous_key) { 521 if (!cell->anonymous_key) {
@@ -534,7 +536,18 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
534 return ret; 536 return ret;
535 537
536 mutex_lock(&net->proc_cells_lock); 538 mutex_lock(&net->proc_cells_lock);
537 list_add_tail(&cell->proc_link, &net->proc_cells); 539 for (p = &net->proc_cells.first; *p; p = &(*p)->next) {
540 pcell = hlist_entry(*p, struct afs_cell, proc_link);
541 if (strcmp(cell->name, pcell->name) < 0)
542 break;
543 }
544
545 cell->proc_link.pprev = p;
546 cell->proc_link.next = *p;
547 rcu_assign_pointer(*p, &cell->proc_link.next);
548 if (cell->proc_link.next)
549 cell->proc_link.next->pprev = &cell->proc_link.next;
550
538 afs_dynroot_mkdir(net, cell); 551 afs_dynroot_mkdir(net, cell);
539 mutex_unlock(&net->proc_cells_lock); 552 mutex_unlock(&net->proc_cells_lock);
540 return 0; 553 return 0;
@@ -550,7 +563,7 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
550 afs_proc_cell_remove(cell); 563 afs_proc_cell_remove(cell);
551 564
552 mutex_lock(&net->proc_cells_lock); 565 mutex_lock(&net->proc_cells_lock);
553 list_del_init(&cell->proc_link); 566 hlist_del_rcu(&cell->proc_link);
554 afs_dynroot_rmdir(net, cell); 567 afs_dynroot_rmdir(net, cell);
555 mutex_unlock(&net->proc_cells_lock); 568 mutex_unlock(&net->proc_cells_lock);
556 569
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index 1cde710a8013..f29c6dade7f6 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -265,7 +265,7 @@ int afs_dynroot_populate(struct super_block *sb)
265 return -ERESTARTSYS; 265 return -ERESTARTSYS;
266 266
267 net->dynroot_sb = sb; 267 net->dynroot_sb = sb;
268 list_for_each_entry(cell, &net->proc_cells, proc_link) { 268 hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
269 ret = afs_dynroot_mkdir(net, cell); 269 ret = afs_dynroot_mkdir(net, cell);
270 if (ret < 0) 270 if (ret < 0)
271 goto error; 271 goto error;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 871a228d7f37..34c02fdcc25f 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -242,7 +242,7 @@ struct afs_net {
242 seqlock_t cells_lock; 242 seqlock_t cells_lock;
243 243
244 struct mutex proc_cells_lock; 244 struct mutex proc_cells_lock;
245 struct list_head proc_cells; 245 struct hlist_head proc_cells;
246 246
247 /* Known servers. Theoretically each fileserver can only be in one 247 /* Known servers. Theoretically each fileserver can only be in one
248 * cell, but in practice, people create aliases and subsets and there's 248 * cell, but in practice, people create aliases and subsets and there's
@@ -320,7 +320,7 @@ struct afs_cell {
320 struct afs_net *net; 320 struct afs_net *net;
321 struct key *anonymous_key; /* anonymous user key for this cell */ 321 struct key *anonymous_key; /* anonymous user key for this cell */
322 struct work_struct manager; /* Manager for init/deinit/dns */ 322 struct work_struct manager; /* Manager for init/deinit/dns */
323 struct list_head proc_link; /* /proc cell list link */ 323 struct hlist_node proc_link; /* /proc cell list link */
324#ifdef CONFIG_AFS_FSCACHE 324#ifdef CONFIG_AFS_FSCACHE
325 struct fscache_cookie *cache; /* caching cookie */ 325 struct fscache_cookie *cache; /* caching cookie */
326#endif 326#endif
diff --git a/fs/afs/main.c b/fs/afs/main.c
index e84fe822a960..107427688edd 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -87,7 +87,7 @@ static int __net_init afs_net_init(struct net *net_ns)
87 timer_setup(&net->cells_timer, afs_cells_timer, 0); 87 timer_setup(&net->cells_timer, afs_cells_timer, 0);
88 88
89 mutex_init(&net->proc_cells_lock); 89 mutex_init(&net->proc_cells_lock);
90 INIT_LIST_HEAD(&net->proc_cells); 90 INIT_HLIST_HEAD(&net->proc_cells);
91 91
92 seqlock_init(&net->fs_lock); 92 seqlock_init(&net->fs_lock);
93 net->fs_servers = RB_ROOT; 93 net->fs_servers = RB_ROOT;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 476dcbb79713..9101f62707af 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -33,9 +33,8 @@ static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
33static int afs_proc_cells_show(struct seq_file *m, void *v) 33static int afs_proc_cells_show(struct seq_file *m, void *v)
34{ 34{
35 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); 35 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
36 struct afs_net *net = afs_seq2net(m);
37 36
38 if (v == &net->proc_cells) { 37 if (v == SEQ_START_TOKEN) {
39 /* display header on line 1 */ 38 /* display header on line 1 */
40 seq_puts(m, "USE NAME\n"); 39 seq_puts(m, "USE NAME\n");
41 return 0; 40 return 0;
@@ -50,12 +49,12 @@ static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
50 __acquires(rcu) 49 __acquires(rcu)
51{ 50{
52 rcu_read_lock(); 51 rcu_read_lock();
53 return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos); 52 return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos);
54} 53}
55 54
56static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) 55static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
57{ 56{
58 return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos); 57 return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos);
59} 58}
60 59
61static void afs_proc_cells_stop(struct seq_file *m, void *v) 60static void afs_proc_cells_stop(struct seq_file *m, void *v)