]> Git Repo - linux.git/blame - fs/afs/proc.c
afs: Rearrange fs/afs/proc.c to move the show routines up
[linux.git] / fs / afs / proc.c
CommitLineData
ec26815a 1/* /proc interface for AFS
1da177e4
LT
2 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells ([email protected])
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
1da177e4
LT
12#include <linux/slab.h>
13#include <linux/module.h>
14#include <linux/proc_fs.h>
15#include <linux/seq_file.h>
e8edc6e0 16#include <linux/sched.h>
7c0f6ba6 17#include <linux/uaccess.h>
1da177e4
LT
18#include "internal.h"
19
f044c884
DH
20static inline struct afs_net *afs_proc2net(struct file *f)
21{
22 return &__afs_net;
23}
1da177e4 24
f044c884
DH
25static inline struct afs_net *afs_seq2net(struct seq_file *m)
26{
27 return &__afs_net; // TODO: use seq_file_net(m)
28}
1da177e4 29
1da177e4
LT
30static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
31static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
32static void afs_proc_cells_stop(struct seq_file *p, void *v);
33static int afs_proc_cells_show(struct seq_file *m, void *v);
1da177e4 34
88e9d34c 35static const struct seq_operations afs_proc_cells_ops = {
1da177e4
LT
36 .start = afs_proc_cells_start,
37 .next = afs_proc_cells_next,
38 .stop = afs_proc_cells_stop,
39 .show = afs_proc_cells_show,
40};
41
1da177e4
LT
42static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
43static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
44 loff_t *pos);
45static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
46static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
47
88e9d34c 48static const struct seq_operations afs_proc_cell_volumes_ops = {
1da177e4
LT
49 .start = afs_proc_cell_volumes_start,
50 .next = afs_proc_cell_volumes_next,
51 .stop = afs_proc_cell_volumes_stop,
52 .show = afs_proc_cell_volumes_show,
53};
54
1da177e4
LT
55static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
56static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
57 loff_t *pos);
58static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
59static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
60
88e9d34c 61static const struct seq_operations afs_proc_cell_vlservers_ops = {
1da177e4
LT
62 .start = afs_proc_cell_vlservers_start,
63 .next = afs_proc_cell_vlservers_next,
64 .stop = afs_proc_cell_vlservers_stop,
65 .show = afs_proc_cell_vlservers_show,
66};
67
d2ddc776
DH
68static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos);
69static void *afs_proc_servers_next(struct seq_file *p, void *v,
1da177e4 70 loff_t *pos);
d2ddc776
DH
71static void afs_proc_servers_stop(struct seq_file *p, void *v);
72static int afs_proc_servers_show(struct seq_file *m, void *v);
73
74static const struct seq_operations afs_proc_servers_ops = {
75 .start = afs_proc_servers_start,
76 .next = afs_proc_servers_next,
77 .stop = afs_proc_servers_stop,
78 .show = afs_proc_servers_show,
1da177e4
LT
79};
80
6f8880d8
DH
81static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
82static void *afs_proc_sysname_next(struct seq_file *p, void *v,
83 loff_t *pos);
84static void afs_proc_sysname_stop(struct seq_file *p, void *v);
85static int afs_proc_sysname_show(struct seq_file *m, void *v);
6f8880d8
DH
86
87static const struct seq_operations afs_proc_sysname_ops = {
88 .start = afs_proc_sysname_start,
89 .next = afs_proc_sysname_next,
90 .stop = afs_proc_sysname_stop,
91 .show = afs_proc_sysname_show,
92};
93
f0691689
DH
94/*
95 * display a header line followed by a load of cell lines
96 */
97static int afs_proc_cells_show(struct seq_file *m, void *v)
98{
99 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
100 struct afs_net *net = afs_seq2net(m);
101
102 if (v == &net->proc_cells) {
103 /* display header on line 1 */
104 seq_puts(m, "USE NAME\n");
105 return 0;
106 }
107
108 /* display one cell per line on subsequent lines */
109 seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
110 return 0;
111}
112
1da177e4
LT
113/*
114 * set up the iterator to start reading from the cells list and return the
115 * first item
116 */
117static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
fe342cf7 118 __acquires(rcu)
1da177e4 119{
f044c884
DH
120 struct afs_net *net = afs_seq2net(m);
121
989782dc 122 rcu_read_lock();
f044c884 123 return seq_list_start_head(&net->proc_cells, *_pos);
ec26815a 124}
1da177e4 125
1da177e4
LT
126/*
127 * move to next cell in cells list
128 */
f044c884 129static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
1da177e4 130{
f044c884
DH
131 struct afs_net *net = afs_seq2net(m);
132
133 return seq_list_next(v, &net->proc_cells, pos);
ec26815a 134}
1da177e4 135
1da177e4
LT
136/*
137 * clean up after reading from the cells list
138 */
f044c884 139static void afs_proc_cells_stop(struct seq_file *m, void *v)
fe342cf7 140 __releases(rcu)
1da177e4 141{
989782dc 142 rcu_read_unlock();
ec26815a 143}
1da177e4 144
1da177e4
LT
145/*
146 * handle writes to /proc/fs/afs/cells
147 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
148 */
149static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
150 size_t size, loff_t *_pos)
151{
f044c884 152 struct afs_net *net = afs_proc2net(file);
1da177e4
LT
153 char *kbuf, *name, *args;
154 int ret;
155
156 /* start by dragging the command into memory */
157 if (size <= 1 || size >= PAGE_SIZE)
158 return -EINVAL;
159
16e5c1fc
AV
160 kbuf = memdup_user_nul(buf, size);
161 if (IS_ERR(kbuf))
162 return PTR_ERR(kbuf);
1da177e4
LT
163
164 /* trim to first NL */
165 name = memchr(kbuf, '\n', size);
166 if (name)
167 *name = 0;
168
169 /* split into command, name and argslist */
170 name = strchr(kbuf, ' ');
171 if (!name)
172 goto inval;
173 do {
174 *name++ = 0;
175 } while(*name == ' ');
176 if (!*name)
177 goto inval;
178
179 args = strchr(name, ' ');
180 if (!args)
181 goto inval;
182 do {
183 *args++ = 0;
184 } while(*args == ' ');
185 if (!*args)
186 goto inval;
187
188 /* determine command to perform */
189 _debug("cmd=%s name=%s args=%s", kbuf, name, args);
190
191 if (strcmp(kbuf, "add") == 0) {
192 struct afs_cell *cell;
08e0e7c8 193
989782dc 194 cell = afs_lookup_cell(net, name, strlen(name), args, true);
08e0e7c8
DH
195 if (IS_ERR(cell)) {
196 ret = PTR_ERR(cell);
1da177e4 197 goto done;
08e0e7c8 198 }
1da177e4 199
17814aef
DH
200 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
201 afs_put_cell(net, cell);
1da177e4 202 printk("kAFS: Added new cell '%s'\n", name);
ec26815a 203 } else {
1da177e4
LT
204 goto inval;
205 }
206
207 ret = size;
208
ec26815a 209done:
1da177e4
LT
210 kfree(kbuf);
211 _leave(" = %d", ret);
212 return ret;
213
ec26815a 214inval:
1da177e4
LT
215 ret = -EINVAL;
216 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
217 goto done;
ec26815a 218}
1da177e4 219
22ade7e7
DH
220static int afs_proc_cells_open(struct inode *inode, struct file *file)
221{
222 return seq_open(file, &afs_proc_cells_ops);
223}
224
225static const struct file_operations afs_proc_cells_fops = {
226 .open = afs_proc_cells_open,
227 .read = seq_read,
228 .write = afs_proc_cells_write,
229 .llseek = seq_lseek,
230 .release = seq_release,
231};
232
1da177e4
LT
233static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
234 size_t size, loff_t *_pos)
235{
37ab6368
DH
236 struct afs_cell *cell;
237 struct afs_net *net = afs_proc2net(file);
238 unsigned int seq = 0;
239 char name[AFS_MAXCELLNAME + 1];
240 int len;
241
242 if (*_pos > 0)
243 return 0;
244 if (!net->ws_cell)
245 return 0;
246
247 rcu_read_lock();
248 do {
249 read_seqbegin_or_lock(&net->cells_lock, &seq);
250 len = 0;
251 cell = rcu_dereference_raw(net->ws_cell);
252 if (cell) {
253 len = cell->name_len;
254 memcpy(name, cell->name, len);
255 }
256 } while (need_seqretry(&net->cells_lock, seq));
257 done_seqretry(&net->cells_lock, seq);
258 rcu_read_unlock();
259
260 if (!len)
261 return 0;
262
263 name[len++] = '\n';
264 if (len > size)
265 len = size;
266 if (copy_to_user(buf, name, len) != 0)
267 return -EFAULT;
268 *_pos = 1;
269 return len;
1da177e4
LT
270}
271
1da177e4
LT
272/*
273 * handle writes to /proc/fs/afs/rootcell
274 * - to initialize rootcell: echo "cell.name:192.168.231.14"
275 */
276static ssize_t afs_proc_rootcell_write(struct file *file,
277 const char __user *buf,
278 size_t size, loff_t *_pos)
279{
f044c884 280 struct afs_net *net = afs_proc2net(file);
1da177e4
LT
281 char *kbuf, *s;
282 int ret;
283
284 /* start by dragging the command into memory */
285 if (size <= 1 || size >= PAGE_SIZE)
286 return -EINVAL;
287
16e5c1fc
AV
288 kbuf = memdup_user_nul(buf, size);
289 if (IS_ERR(kbuf))
290 return PTR_ERR(kbuf);
1da177e4 291
6f8880d8
DH
292 ret = -EINVAL;
293 if (kbuf[0] == '.')
294 goto out;
295 if (memchr(kbuf, '/', size))
296 goto out;
297
1da177e4
LT
298 /* trim to first NL */
299 s = memchr(kbuf, '\n', size);
300 if (s)
301 *s = 0;
302
303 /* determine command to perform */
304 _debug("rootcell=%s", kbuf);
305
f044c884 306 ret = afs_cell_init(net, kbuf);
1da177e4
LT
307 if (ret >= 0)
308 ret = size; /* consume everything, always */
309
6f8880d8 310out:
1da177e4 311 kfree(kbuf);
1da177e4
LT
312 _leave(" = %d", ret);
313 return ret;
ec26815a 314}
1da177e4 315
22ade7e7
DH
316static const struct file_operations afs_proc_rootcell_fops = {
317 .read = afs_proc_rootcell_read,
318 .write = afs_proc_rootcell_write,
319 .llseek = no_llseek,
320};
321
f0691689
DH
322static const char afs_vol_types[3][3] = {
323 [AFSVL_RWVOL] = "RW",
324 [AFSVL_ROVOL] = "RO",
325 [AFSVL_BACKVOL] = "BK",
326};
327
328/*
329 * display a header line followed by a load of volume lines
330 */
331static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
332{
333 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
334 struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
335
336 /* Display header on line 1 */
337 if (v == &cell->proc_volumes) {
338 seq_puts(m, "USE VID TY\n");
339 return 0;
340 }
341
342 seq_printf(m, "%3d %08x %s\n",
343 atomic_read(&vol->usage), vol->vid,
344 afs_vol_types[vol->type]);
345
346 return 0;
347}
348
1da177e4
LT
349/*
350 * set up the iterator to start reading from the cells list and return the
351 * first item
352 */
353static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
fe342cf7 354 __acquires(cell->proc_lock)
1da177e4 355{
353861cf 356 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4
LT
357
358 _enter("cell=%p pos=%Ld", cell, *_pos);
359
d2ddc776
DH
360 read_lock(&cell->proc_lock);
361 return seq_list_start_head(&cell->proc_volumes, *_pos);
ec26815a 362}
1da177e4 363
1da177e4
LT
364/*
365 * move to next cell in cells list
366 */
367static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
368 loff_t *_pos)
369{
353861cf 370 struct afs_cell *cell = PDE_DATA(file_inode(p->file));
1da177e4
LT
371
372 _enter("cell=%p pos=%Ld", cell, *_pos);
d2ddc776 373 return seq_list_next(v, &cell->proc_volumes, _pos);
ec26815a 374}
1da177e4 375
1da177e4
LT
376/*
377 * clean up after reading from the cells list
378 */
379static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
fe342cf7 380 __releases(cell->proc_lock)
1da177e4 381{
353861cf 382 struct afs_cell *cell = PDE_DATA(file_inode(p->file));
1da177e4 383
d2ddc776 384 read_unlock(&cell->proc_lock);
ec26815a 385}
1da177e4 386
1da177e4
LT
387/*
388 * display a header line followed by a load of volume lines
389 */
f0691689 390static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
1da177e4 391{
f0691689 392 struct sockaddr_rxrpc *addr = v;
1da177e4 393
f0691689
DH
394 /* display header on line 1 */
395 if (v == (void *)1) {
396 seq_puts(m, "ADDRESS\n");
1da177e4
LT
397 return 0;
398 }
399
f0691689
DH
400 /* display one cell per line on subsequent lines */
401 seq_printf(m, "%pISp\n", &addr->transport);
1da177e4 402 return 0;
ec26815a 403}
1da177e4 404
1da177e4
LT
405/*
406 * set up the iterator to start reading from the cells list and return the
407 * first item
408 */
409static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
fe342cf7 410 __acquires(rcu)
1da177e4 411{
8b2a464c 412 struct afs_addr_list *alist;
353861cf 413 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4
LT
414 loff_t pos = *_pos;
415
8b2a464c 416 rcu_read_lock();
1da177e4 417
8b2a464c 418 alist = rcu_dereference(cell->vl_addrs);
1da177e4
LT
419
420 /* allow for the header line */
421 if (!pos)
422 return (void *) 1;
423 pos--;
424
8b2a464c 425 if (!alist || pos >= alist->nr_addrs)
1da177e4
LT
426 return NULL;
427
8b2a464c 428 return alist->addrs + pos;
ec26815a 429}
1da177e4 430
1da177e4
LT
431/*
432 * move to next cell in cells list
433 */
434static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
435 loff_t *_pos)
436{
8b2a464c 437 struct afs_addr_list *alist;
353861cf 438 struct afs_cell *cell = PDE_DATA(file_inode(p->file));
1da177e4
LT
439 loff_t pos;
440
8b2a464c 441 alist = rcu_dereference(cell->vl_addrs);
1da177e4
LT
442
443 pos = *_pos;
444 (*_pos)++;
8b2a464c 445 if (!alist || pos >= alist->nr_addrs)
1da177e4
LT
446 return NULL;
447
8b2a464c 448 return alist->addrs + pos;
ec26815a 449}
1da177e4 450
1da177e4
LT
451/*
452 * clean up after reading from the cells list
453 */
454static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
fe342cf7 455 __releases(rcu)
1da177e4 456{
8b2a464c 457 rcu_read_unlock();
ec26815a 458}
1da177e4 459
1da177e4
LT
460/*
461 * display a header line followed by a load of volume lines
462 */
f0691689 463static int afs_proc_servers_show(struct seq_file *m, void *v)
1da177e4 464{
f0691689
DH
465 struct afs_server *server;
466 struct afs_addr_list *alist;
1da177e4 467
f0691689
DH
468 if (v == SEQ_START_TOKEN) {
469 seq_puts(m, "UUID USE ADDR\n");
1da177e4
LT
470 return 0;
471 }
472
f0691689
DH
473 server = list_entry(v, struct afs_server, proc_link);
474 alist = rcu_dereference(server->addresses);
475 seq_printf(m, "%pU %3d %pISp\n",
476 &server->uuid,
477 atomic_read(&server->usage),
478 &alist->addrs[alist->index].transport);
1da177e4 479 return 0;
ec26815a 480}
1da177e4 481
1da177e4 482/*
d2ddc776
DH
483 * Set up the iterator to start reading from the server list and return the
484 * first item.
1da177e4 485 */
d2ddc776 486static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
fe342cf7 487 __acquires(rcu)
1da177e4 488{
d2ddc776 489 struct afs_net *net = afs_seq2net(m);
1da177e4 490
d2ddc776
DH
491 rcu_read_lock();
492 return seq_hlist_start_head_rcu(&net->fs_proc, *_pos);
ec26815a 493}
1da177e4 494
1da177e4
LT
495/*
496 * move to next cell in cells list
497 */
d2ddc776 498static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
1da177e4 499{
d2ddc776 500 struct afs_net *net = afs_seq2net(m);
1da177e4 501
d2ddc776 502 return seq_hlist_next_rcu(v, &net->fs_proc, _pos);
ec26815a 503}
1da177e4 504
1da177e4
LT
505/*
506 * clean up after reading from the cells list
507 */
d2ddc776 508static void afs_proc_servers_stop(struct seq_file *p, void *v)
fe342cf7 509 __releases(rcu)
1da177e4 510{
d2ddc776 511 rcu_read_unlock();
ec26815a 512}
1da177e4 513
6f8880d8
DH
514void afs_put_sysnames(struct afs_sysnames *sysnames)
515{
516 int i;
517
518 if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
519 for (i = 0; i < sysnames->nr; i++)
520 if (sysnames->subs[i] != afs_init_sysname &&
521 sysnames->subs[i] != sysnames->blank)
522 kfree(sysnames->subs[i]);
523 }
524}
525
526/*
527 * Handle opening of /proc/fs/afs/sysname. If it is opened for writing, we
528 * assume the caller wants to change the substitution list and we allocate a
529 * buffer to hold the list.
530 */
531static int afs_proc_sysname_open(struct inode *inode, struct file *file)
532{
533 struct afs_sysnames *sysnames;
534 struct seq_file *m;
535 int ret;
536
537 ret = seq_open(file, &afs_proc_sysname_ops);
538 if (ret < 0)
539 return ret;
540
541 if (file->f_mode & FMODE_WRITE) {
542 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
543 if (!sysnames) {
544 seq_release(inode, file);
545 return -ENOMEM;
546 }
547
548 refcount_set(&sysnames->usage, 1);
549 m = file->private_data;
550 m->private = sysnames;
551 }
552
553 return 0;
554}
555
556/*
557 * Handle writes to /proc/fs/afs/sysname to set the @sys substitution.
558 */
559static ssize_t afs_proc_sysname_write(struct file *file,
560 const char __user *buf,
561 size_t size, loff_t *_pos)
562{
563 struct afs_sysnames *sysnames;
564 struct seq_file *m = file->private_data;
565 char *kbuf = NULL, *s, *p, *sub;
566 int ret, len;
567
568 sysnames = m->private;
569 if (!sysnames)
570 return -EINVAL;
571 if (sysnames->error)
572 return sysnames->error;
573
574 if (size >= PAGE_SIZE - 1) {
575 sysnames->error = -EINVAL;
576 return -EINVAL;
577 }
578 if (size == 0)
579 return 0;
580
581 kbuf = memdup_user_nul(buf, size);
582 if (IS_ERR(kbuf))
583 return PTR_ERR(kbuf);
584
585 inode_lock(file_inode(file));
586
587 p = kbuf;
588 while ((s = strsep(&p, " \t\n"))) {
589 len = strlen(s);
590 if (len == 0)
591 continue;
592 ret = -ENAMETOOLONG;
593 if (len >= AFSNAMEMAX)
594 goto error;
595
596 if (len >= 4 &&
597 s[len - 4] == '@' &&
598 s[len - 3] == 's' &&
599 s[len - 2] == 'y' &&
600 s[len - 1] == 's')
601 /* Protect against recursion */
602 goto invalid;
603
604 if (s[0] == '.' &&
605 (len < 2 || (len == 2 && s[1] == '.')))
606 goto invalid;
607
608 if (memchr(s, '/', len))
609 goto invalid;
610
611 ret = -EFBIG;
612 if (sysnames->nr >= AFS_NR_SYSNAME)
613 goto out;
614
615 if (strcmp(s, afs_init_sysname) == 0) {
616 sub = (char *)afs_init_sysname;
617 } else {
618 ret = -ENOMEM;
619 sub = kmemdup(s, len + 1, GFP_KERNEL);
620 if (!sub)
621 goto out;
622 }
623
624 sysnames->subs[sysnames->nr] = sub;
625 sysnames->nr++;
626 }
627
628 ret = size; /* consume everything, always */
629out:
630 inode_unlock(file_inode(file));
631 kfree(kbuf);
632 return ret;
633
634invalid:
635 ret = -EINVAL;
636error:
637 sysnames->error = ret;
638 goto out;
639}
640
641static int afs_proc_sysname_release(struct inode *inode, struct file *file)
642{
643 struct afs_sysnames *sysnames, *kill = NULL;
644 struct seq_file *m = file->private_data;
645 struct afs_net *net = afs_seq2net(m);
646
647 sysnames = m->private;
648 if (sysnames) {
649 if (!sysnames->error) {
650 kill = sysnames;
651 if (sysnames->nr == 0) {
652 sysnames->subs[0] = sysnames->blank;
653 sysnames->nr++;
654 }
655 write_lock(&net->sysnames_lock);
656 kill = net->sysnames;
657 net->sysnames = sysnames;
658 write_unlock(&net->sysnames_lock);
659 }
660 afs_put_sysnames(kill);
661 }
662
663 return seq_release(inode, file);
664}
665
f0691689
DH
666static int afs_proc_sysname_show(struct seq_file *m, void *v)
667{
668 struct afs_net *net = afs_seq2net(m);
669 struct afs_sysnames *sysnames = net->sysnames;
670 unsigned int i = (unsigned long)v - 1;
671
672 if (i < sysnames->nr)
673 seq_printf(m, "%s\n", sysnames->subs[i]);
674 return 0;
675}
676
6f8880d8
DH
677static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
678 __acquires(&net->sysnames_lock)
679{
680 struct afs_net *net = afs_seq2net(m);
681 struct afs_sysnames *names = net->sysnames;
682
683 read_lock(&net->sysnames_lock);
684
685 if (*pos >= names->nr)
686 return NULL;
687 return (void *)(unsigned long)(*pos + 1);
688}
689
690static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
691{
692 struct afs_net *net = afs_seq2net(m);
693 struct afs_sysnames *names = net->sysnames;
694
695 *pos += 1;
696 if (*pos >= names->nr)
697 return NULL;
698 return (void *)(unsigned long)(*pos + 1);
699}
700
701static void afs_proc_sysname_stop(struct seq_file *m, void *v)
702 __releases(&net->sysnames_lock)
703{
704 struct afs_net *net = afs_seq2net(m);
705
706 read_unlock(&net->sysnames_lock);
707}
708
22ade7e7
DH
709static const struct file_operations afs_proc_sysname_fops = {
710 .open = afs_proc_sysname_open,
711 .read = seq_read,
712 .llseek = seq_lseek,
713 .release = afs_proc_sysname_release,
714 .write = afs_proc_sysname_write,
715};
716
d55b4da4
DH
717/*
718 * Display general per-net namespace statistics
719 */
720static int afs_proc_stats_show(struct seq_file *m, void *v)
721{
722 struct afs_net *net = afs_seq2net(m);
723
724 seq_puts(m, "kAFS statistics\n");
725
f3ddee8d 726 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
d55b4da4
DH
727 atomic_read(&net->n_lookup),
728 atomic_read(&net->n_reval),
f3ddee8d
DH
729 atomic_read(&net->n_inval),
730 atomic_read(&net->n_relpg));
d55b4da4
DH
731
732 seq_printf(m, "dir-data: rdpg=%u\n",
733 atomic_read(&net->n_read_dir));
63a4681f
DH
734
735 seq_printf(m, "dir-edit: cr=%u rm=%u\n",
736 atomic_read(&net->n_dir_cr),
737 atomic_read(&net->n_dir_rm));
76a5cb6f
DH
738
739 seq_printf(m, "file-rd : n=%u nb=%lu\n",
740 atomic_read(&net->n_fetches),
741 atomic_long_read(&net->n_fetch_bytes));
742 seq_printf(m, "file-wr : n=%u nb=%lu\n",
743 atomic_read(&net->n_stores),
744 atomic_long_read(&net->n_store_bytes));
d55b4da4
DH
745 return 0;
746}
10495a00
DH
747
748/*
749 * initialise /proc/fs/afs/<cell>/
750 */
751int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
752{
753 struct proc_dir_entry *dir;
754
755 _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
756
757 dir = proc_mkdir(cell->name, net->proc_afs);
758 if (!dir)
759 goto error_dir;
760
761 if (!proc_create_seq_data("vlservers", 0, dir,
762 &afs_proc_cell_vlservers_ops, cell))
763 goto error_tree;
764 if (!proc_create_seq_data("volumes", 0, dir,
765 &afs_proc_cell_volumes_ops, cell))
766 goto error_tree;
767
768 _leave(" = 0");
769 return 0;
770
771error_tree:
772 remove_proc_subtree(cell->name, net->proc_afs);
773error_dir:
774 _leave(" = -ENOMEM");
775 return -ENOMEM;
776}
777
778/*
779 * remove /proc/fs/afs/<cell>/
780 */
781void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
782{
783 _enter("");
784
785 remove_proc_subtree(cell->name, net->proc_afs);
786
787 _leave("");
788}
789
790/*
791 * initialise the /proc/fs/afs/ directory
792 */
793int afs_proc_init(struct afs_net *net)
794{
795 _enter("");
796
797 net->proc_afs = proc_mkdir("fs/afs", NULL);
798 if (!net->proc_afs)
799 goto error_dir;
800
801 if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
802 !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) ||
803 !proc_create_seq("servers", 0644, net->proc_afs, &afs_proc_servers_ops) ||
804 !proc_create_single("stats", 0644, net->proc_afs, afs_proc_stats_show) ||
805 !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops))
806 goto error_tree;
807
808 _leave(" = 0");
809 return 0;
810
811error_tree:
812 proc_remove(net->proc_afs);
813error_dir:
814 _leave(" = -ENOMEM");
815 return -ENOMEM;
816}
817
818/*
819 * clean up the /proc/fs/afs/ directory
820 */
821void afs_proc_cleanup(struct afs_net *net)
822{
823 proc_remove(net->proc_afs);
824 net->proc_afs = NULL;
825}
This page took 0.931357 seconds and 4 git commands to generate.