Skip to content

Commit 6b3944e

Browse files
dhowellsgregkh
authored andcommitted
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: 989782d ("afs: Overhaul cell database management") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 4ea07ab commit 6b3944e

File tree

5 files changed

+22
-10
lines changed

5 files changed

+22
-10
lines changed

fs/afs/cell.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@ static int afs_alloc_anon_key(struct afs_cell *cell)
514514
*/
515515
static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
516516
{
517+
struct hlist_node **p;
518+
struct afs_cell *pcell;
517519
int ret;
518520

519521
if (!cell->anonymous_key) {
@@ -534,7 +536,18 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
534536
return ret;
535537

536538
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+
538551
afs_dynroot_mkdir(net, cell);
539552
mutex_unlock(&net->proc_cells_lock);
540553
return 0;
@@ -550,7 +563,7 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
550563
afs_proc_cell_remove(cell);
551564

552565
mutex_lock(&net->proc_cells_lock);
553-
list_del_init(&cell->proc_link);
566+
hlist_del_rcu(&cell->proc_link);
554567
afs_dynroot_rmdir(net, cell);
555568
mutex_unlock(&net->proc_cells_lock);
556569

fs/afs/dynroot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ int afs_dynroot_populate(struct super_block *sb)
265265
return -ERESTARTSYS;
266266

267267
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) {
269269
ret = afs_dynroot_mkdir(net, cell);
270270
if (ret < 0)
271271
goto error;

fs/afs/internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ struct afs_net {
242242
seqlock_t cells_lock;
243243

244244
struct mutex proc_cells_lock;
245-
struct list_head proc_cells;
245+
struct hlist_head proc_cells;
246246

247247
/* Known servers. Theoretically each fileserver can only be in one
248248
* cell, but in practice, people create aliases and subsets and there's
@@ -320,7 +320,7 @@ struct afs_cell {
320320
struct afs_net *net;
321321
struct key *anonymous_key; /* anonymous user key for this cell */
322322
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 */
324324
#ifdef CONFIG_AFS_FSCACHE
325325
struct fscache_cookie *cache; /* caching cookie */
326326
#endif

fs/afs/main.c

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

8989
mutex_init(&net->proc_cells_lock);
90-
INIT_LIST_HEAD(&net->proc_cells);
90+
INIT_HLIST_HEAD(&net->proc_cells);
9191

9292
seqlock_init(&net->fs_lock);
9393
net->fs_servers = RB_ROOT;

fs/afs/proc.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
3333
static int afs_proc_cells_show(struct seq_file *m, void *v)
3434
{
3535
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
36-
struct afs_net *net = afs_seq2net(m);
3736

38-
if (v == &net->proc_cells) {
37+
if (v == SEQ_START_TOKEN) {
3938
/* display header on line 1 */
4039
seq_puts(m, "USE NAME\n");
4140
return 0;
@@ -50,12 +49,12 @@ static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
5049
__acquires(rcu)
5150
{
5251
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);
5453
}
5554

5655
static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
5756
{
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);
5958
}
6059

6160
static void afs_proc_cells_stop(struct seq_file *m, void *v)

0 commit comments

Comments
 (0)