Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

David Howells and committed by
Greg Kroah-Hartman
6b3944e4 4ea07abb

+22 -10
+15 -2
fs/afs/cell.c
··· 514 514 */ 515 515 static 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 519 int ret; 518 520 519 521 if (!cell->anonymous_key) { ··· 536 534 return ret; 537 535 538 536 mutex_lock(&net->proc_cells_lock); 539 - list_add_tail(&cell->proc_link, &net->proc_cells); 537 + for (p = &net->proc_cells.first; *p; p = &(*p)->next) { 538 + pcell = hlist_entry(*p, struct afs_cell, proc_link); 539 + if (strcmp(cell->name, pcell->name) < 0) 540 + break; 541 + } 542 + 543 + cell->proc_link.pprev = p; 544 + cell->proc_link.next = *p; 545 + rcu_assign_pointer(*p, &cell->proc_link.next); 546 + if (cell->proc_link.next) 547 + cell->proc_link.next->pprev = &cell->proc_link.next; 548 + 540 549 afs_dynroot_mkdir(net, cell); 541 550 mutex_unlock(&net->proc_cells_lock); 542 551 return 0; ··· 563 550 afs_proc_cell_remove(cell); 564 551 565 552 mutex_lock(&net->proc_cells_lock); 566 - list_del_init(&cell->proc_link); 553 + hlist_del_rcu(&cell->proc_link); 567 554 afs_dynroot_rmdir(net, cell); 568 555 mutex_unlock(&net->proc_cells_lock); 569 556
+1 -1
fs/afs/dynroot.c
··· 265 265 return -ERESTARTSYS; 266 266 267 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 269 ret = afs_dynroot_mkdir(net, cell); 270 270 if (ret < 0) 271 271 goto error;
+2 -2
fs/afs/internal.h
··· 242 242 seqlock_t cells_lock; 243 243 244 244 struct mutex proc_cells_lock; 245 - struct list_head proc_cells; 245 + struct hlist_head proc_cells; 246 246 247 247 /* Known servers. Theoretically each fileserver can only be in one 248 248 * cell, but in practice, people create aliases and subsets and there's ··· 320 320 struct afs_net *net; 321 321 struct key *anonymous_key; /* anonymous user key for this cell */ 322 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 324 #ifdef CONFIG_AFS_FSCACHE 325 325 struct fscache_cookie *cache; /* caching cookie */ 326 326 #endif
+1 -1
fs/afs/main.c
··· 87 87 timer_setup(&net->cells_timer, afs_cells_timer, 0); 88 88 89 89 mutex_init(&net->proc_cells_lock); 90 - INIT_LIST_HEAD(&net->proc_cells); 90 + INIT_HLIST_HEAD(&net->proc_cells); 91 91 92 92 seqlock_init(&net->fs_lock); 93 93 net->fs_servers = RB_ROOT;
+3 -4
fs/afs/proc.c
··· 33 33 static int afs_proc_cells_show(struct seq_file *m, void *v) 34 34 { 35 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 38 /* display header on line 1 */ 40 39 seq_puts(m, "USE NAME\n"); 41 40 return 0; ··· 49 50 __acquires(rcu) 50 51 { 51 52 rcu_read_lock(); 52 - return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos); 53 + return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos); 53 54 } 54 55 55 56 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) 56 57 { 57 - return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos); 58 + return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos); 58 59 } 59 60 60 61 static void afs_proc_cells_stop(struct seq_file *m, void *v)