]> Git Repo - linux.git/blame - fs/afs/proc.c
afs: Handle CONFIG_PROC_FS=n
[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
5b86d4ff 20static inline struct afs_net *afs_seq2net(struct seq_file *m)
f044c884 21{
5b86d4ff 22 return afs_net(seq_file_net(m));
f044c884 23}
1da177e4 24
5b86d4ff 25static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
f044c884 26{
5b86d4ff 27 return afs_net(seq_file_single_net(m));
f044c884 28}
1da177e4 29
f0691689 30/*
5d9de25d 31 * Display the list of cells known to the namespace.
f0691689
DH
32 */
33static int afs_proc_cells_show(struct seq_file *m, void *v)
34{
35 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
36 struct afs_net *net = afs_seq2net(m);
37
38 if (v == &net->proc_cells) {
39 /* display header on line 1 */
40 seq_puts(m, "USE NAME\n");
41 return 0;
42 }
43
44 /* display one cell per line on subsequent lines */
45 seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
46 return 0;
47}
48
1da177e4 49static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
fe342cf7 50 __acquires(rcu)
1da177e4 51{
989782dc 52 rcu_read_lock();
5d9de25d 53 return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos);
ec26815a 54}
1da177e4 55
f044c884 56static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
1da177e4 57{
5d9de25d 58 return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos);
ec26815a 59}
1da177e4 60
f044c884 61static void afs_proc_cells_stop(struct seq_file *m, void *v)
fe342cf7 62 __releases(rcu)
1da177e4 63{
989782dc 64 rcu_read_unlock();
ec26815a 65}
1da177e4 66
5d9de25d
DH
67static const struct seq_operations afs_proc_cells_ops = {
68 .start = afs_proc_cells_start,
69 .next = afs_proc_cells_next,
70 .stop = afs_proc_cells_stop,
71 .show = afs_proc_cells_show,
72};
73
1da177e4
LT
74/*
75 * handle writes to /proc/fs/afs/cells
76 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
77 */
5b86d4ff 78static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
1da177e4 79{
5b86d4ff
DH
80 struct seq_file *m = file->private_data;
81 struct afs_net *net = afs_seq2net(m);
82 char *name, *args;
1da177e4
LT
83 int ret;
84
1da177e4 85 /* trim to first NL */
5b86d4ff 86 name = memchr(buf, '\n', size);
1da177e4
LT
87 if (name)
88 *name = 0;
89
90 /* split into command, name and argslist */
5b86d4ff 91 name = strchr(buf, ' ');
1da177e4
LT
92 if (!name)
93 goto inval;
94 do {
95 *name++ = 0;
96 } while(*name == ' ');
97 if (!*name)
98 goto inval;
99
100 args = strchr(name, ' ');
101 if (!args)
102 goto inval;
103 do {
104 *args++ = 0;
105 } while(*args == ' ');
106 if (!*args)
107 goto inval;
108
109 /* determine command to perform */
5b86d4ff 110 _debug("cmd=%s name=%s args=%s", buf, name, args);
1da177e4 111
5b86d4ff 112 if (strcmp(buf, "add") == 0) {
1da177e4 113 struct afs_cell *cell;
08e0e7c8 114
989782dc 115 cell = afs_lookup_cell(net, name, strlen(name), args, true);
08e0e7c8
DH
116 if (IS_ERR(cell)) {
117 ret = PTR_ERR(cell);
1da177e4 118 goto done;
08e0e7c8 119 }
1da177e4 120
17814aef
DH
121 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
122 afs_put_cell(net, cell);
1da177e4 123 printk("kAFS: Added new cell '%s'\n", name);
ec26815a 124 } else {
1da177e4
LT
125 goto inval;
126 }
127
5b86d4ff 128 ret = 0;
1da177e4 129
ec26815a 130done:
1da177e4
LT
131 _leave(" = %d", ret);
132 return ret;
133
ec26815a 134inval:
1da177e4
LT
135 ret = -EINVAL;
136 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
137 goto done;
ec26815a 138}
1da177e4 139
5d9de25d 140/*
5b86d4ff 141 * Display the name of the current workstation cell.
5d9de25d 142 */
5b86d4ff 143static int afs_proc_rootcell_show(struct seq_file *m, void *v)
1da177e4 144{
37ab6368 145 struct afs_cell *cell;
5b86d4ff
DH
146 struct afs_net *net;
147
148 net = afs_seq2net_single(m);
149 if (rcu_access_pointer(net->ws_cell)) {
150 rcu_read_lock();
151 cell = rcu_dereference(net->ws_cell);
152 if (cell)
153 seq_printf(m, "%s\n", cell->name);
154 rcu_read_unlock();
155 }
156 return 0;
1da177e4
LT
157}
158
1da177e4 159/*
5d9de25d
DH
160 * Set the current workstation cell and optionally supply its list of volume
161 * location servers.
162 *
163 * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
1da177e4 164 */
5b86d4ff 165static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
1da177e4 166{
5b86d4ff
DH
167 struct seq_file *m = file->private_data;
168 struct afs_net *net = afs_seq2net_single(m);
169 char *s;
1da177e4
LT
170 int ret;
171
6f8880d8 172 ret = -EINVAL;
5b86d4ff 173 if (buf[0] == '.')
6f8880d8 174 goto out;
5b86d4ff 175 if (memchr(buf, '/', size))
6f8880d8
DH
176 goto out;
177
1da177e4 178 /* trim to first NL */
5b86d4ff 179 s = memchr(buf, '\n', size);
1da177e4
LT
180 if (s)
181 *s = 0;
182
183 /* determine command to perform */
5b86d4ff 184 _debug("rootcell=%s", buf);
1da177e4 185
5b86d4ff 186 ret = afs_cell_init(net, buf);
1da177e4 187
6f8880d8 188out:
1da177e4
LT
189 _leave(" = %d", ret);
190 return ret;
ec26815a 191}
1da177e4 192
f0691689
DH
193static const char afs_vol_types[3][3] = {
194 [AFSVL_RWVOL] = "RW",
195 [AFSVL_ROVOL] = "RO",
196 [AFSVL_BACKVOL] = "BK",
197};
198
199/*
5d9de25d 200 * Display the list of volumes known to a cell.
f0691689
DH
201 */
202static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
203{
204 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
205 struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
206
207 /* Display header on line 1 */
208 if (v == &cell->proc_volumes) {
209 seq_puts(m, "USE VID TY\n");
210 return 0;
211 }
212
213 seq_printf(m, "%3d %08x %s\n",
214 atomic_read(&vol->usage), vol->vid,
215 afs_vol_types[vol->type]);
216
217 return 0;
218}
219
1da177e4 220static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
fe342cf7 221 __acquires(cell->proc_lock)
1da177e4 222{
353861cf 223 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4 224
d2ddc776
DH
225 read_lock(&cell->proc_lock);
226 return seq_list_start_head(&cell->proc_volumes, *_pos);
ec26815a 227}
1da177e4 228
5b86d4ff 229static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
1da177e4
LT
230 loff_t *_pos)
231{
5b86d4ff 232 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4 233
d2ddc776 234 return seq_list_next(v, &cell->proc_volumes, _pos);
ec26815a 235}
1da177e4 236
5b86d4ff 237static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
fe342cf7 238 __releases(cell->proc_lock)
1da177e4 239{
5b86d4ff 240 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4 241
d2ddc776 242 read_unlock(&cell->proc_lock);
ec26815a 243}
1da177e4 244
5d9de25d
DH
245static const struct seq_operations afs_proc_cell_volumes_ops = {
246 .start = afs_proc_cell_volumes_start,
247 .next = afs_proc_cell_volumes_next,
248 .stop = afs_proc_cell_volumes_stop,
249 .show = afs_proc_cell_volumes_show,
250};
251
1da177e4 252/*
5d9de25d 253 * Display the list of Volume Location servers we're using for a cell.
1da177e4 254 */
f0691689 255static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
1da177e4 256{
f0691689 257 struct sockaddr_rxrpc *addr = v;
1da177e4 258
f0691689
DH
259 /* display header on line 1 */
260 if (v == (void *)1) {
261 seq_puts(m, "ADDRESS\n");
1da177e4
LT
262 return 0;
263 }
264
f0691689
DH
265 /* display one cell per line on subsequent lines */
266 seq_printf(m, "%pISp\n", &addr->transport);
1da177e4 267 return 0;
ec26815a 268}
1da177e4 269
1da177e4 270static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
fe342cf7 271 __acquires(rcu)
1da177e4 272{
8b2a464c 273 struct afs_addr_list *alist;
353861cf 274 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4
LT
275 loff_t pos = *_pos;
276
8b2a464c 277 rcu_read_lock();
1da177e4 278
8b2a464c 279 alist = rcu_dereference(cell->vl_addrs);
1da177e4
LT
280
281 /* allow for the header line */
282 if (!pos)
283 return (void *) 1;
284 pos--;
285
8b2a464c 286 if (!alist || pos >= alist->nr_addrs)
1da177e4
LT
287 return NULL;
288
8b2a464c 289 return alist->addrs + pos;
ec26815a 290}
1da177e4 291
5b86d4ff 292static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
1da177e4
LT
293 loff_t *_pos)
294{
8b2a464c 295 struct afs_addr_list *alist;
5b86d4ff 296 struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4
LT
297 loff_t pos;
298
8b2a464c 299 alist = rcu_dereference(cell->vl_addrs);
1da177e4
LT
300
301 pos = *_pos;
302 (*_pos)++;
8b2a464c 303 if (!alist || pos >= alist->nr_addrs)
1da177e4
LT
304 return NULL;
305
8b2a464c 306 return alist->addrs + pos;
ec26815a 307}
1da177e4 308
5b86d4ff 309static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
fe342cf7 310 __releases(rcu)
1da177e4 311{
8b2a464c 312 rcu_read_unlock();
ec26815a 313}
1da177e4 314
5d9de25d
DH
315static const struct seq_operations afs_proc_cell_vlservers_ops = {
316 .start = afs_proc_cell_vlservers_start,
317 .next = afs_proc_cell_vlservers_next,
318 .stop = afs_proc_cell_vlservers_stop,
319 .show = afs_proc_cell_vlservers_show,
320};
321
1da177e4 322/*
5d9de25d 323 * Display the list of fileservers we're using within a namespace.
1da177e4 324 */
f0691689 325static int afs_proc_servers_show(struct seq_file *m, void *v)
1da177e4 326{
f0691689
DH
327 struct afs_server *server;
328 struct afs_addr_list *alist;
1da177e4 329
f0691689
DH
330 if (v == SEQ_START_TOKEN) {
331 seq_puts(m, "UUID USE ADDR\n");
1da177e4
LT
332 return 0;
333 }
334
f0691689
DH
335 server = list_entry(v, struct afs_server, proc_link);
336 alist = rcu_dereference(server->addresses);
337 seq_printf(m, "%pU %3d %pISp\n",
338 &server->uuid,
339 atomic_read(&server->usage),
340 &alist->addrs[alist->index].transport);
1da177e4 341 return 0;
ec26815a 342}
1da177e4 343
d2ddc776 344static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
fe342cf7 345 __acquires(rcu)
1da177e4 346{
d2ddc776 347 rcu_read_lock();
5d9de25d 348 return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
ec26815a 349}
1da177e4 350
d2ddc776 351static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
1da177e4 352{
5d9de25d 353 return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
ec26815a 354}
1da177e4 355
5b86d4ff 356static void afs_proc_servers_stop(struct seq_file *m, void *v)
fe342cf7 357 __releases(rcu)
1da177e4 358{
d2ddc776 359 rcu_read_unlock();
ec26815a 360}
1da177e4 361
5d9de25d
DH
362static const struct seq_operations afs_proc_servers_ops = {
363 .start = afs_proc_servers_start,
364 .next = afs_proc_servers_next,
365 .stop = afs_proc_servers_stop,
366 .show = afs_proc_servers_show,
367};
6f8880d8 368
6f8880d8 369/*
5d9de25d
DH
370 * Display the list of strings that may be substituted for the @sys pathname
371 * macro.
6f8880d8 372 */
5d9de25d 373static int afs_proc_sysname_show(struct seq_file *m, void *v)
6f8880d8 374{
5d9de25d
DH
375 struct afs_net *net = afs_seq2net(m);
376 struct afs_sysnames *sysnames = net->sysnames;
377 unsigned int i = (unsigned long)v - 1;
6f8880d8 378
5d9de25d
DH
379 if (i < sysnames->nr)
380 seq_printf(m, "%s\n", sysnames->subs[i]);
381 return 0;
382}
6f8880d8 383
5d9de25d
DH
384static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
385 __acquires(&net->sysnames_lock)
386{
387 struct afs_net *net = afs_seq2net(m);
5b86d4ff 388 struct afs_sysnames *names;
6f8880d8 389
5d9de25d 390 read_lock(&net->sysnames_lock);
6f8880d8 391
5b86d4ff 392 names = net->sysnames;
5d9de25d
DH
393 if (*pos >= names->nr)
394 return NULL;
395 return (void *)(unsigned long)(*pos + 1);
396}
397
398static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
399{
400 struct afs_net *net = afs_seq2net(m);
401 struct afs_sysnames *names = net->sysnames;
402
403 *pos += 1;
404 if (*pos >= names->nr)
405 return NULL;
406 return (void *)(unsigned long)(*pos + 1);
407}
408
409static void afs_proc_sysname_stop(struct seq_file *m, void *v)
410 __releases(&net->sysnames_lock)
411{
412 struct afs_net *net = afs_seq2net(m);
413
414 read_unlock(&net->sysnames_lock);
6f8880d8
DH
415}
416
5d9de25d
DH
417static const struct seq_operations afs_proc_sysname_ops = {
418 .start = afs_proc_sysname_start,
419 .next = afs_proc_sysname_next,
420 .stop = afs_proc_sysname_stop,
421 .show = afs_proc_sysname_show,
422};
423
6f8880d8 424/*
5d9de25d 425 * Allow the @sys substitution to be configured.
6f8880d8 426 */
5b86d4ff 427static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
6f8880d8 428{
5b86d4ff 429 struct afs_sysnames *sysnames, *kill;
6f8880d8 430 struct seq_file *m = file->private_data;
5b86d4ff
DH
431 struct afs_net *net = afs_seq2net(m);
432 char *s, *p, *sub;
6f8880d8
DH
433 int ret, len;
434
5b86d4ff 435 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
6f8880d8 436 if (!sysnames)
5b86d4ff
DH
437 return -ENOMEM;
438 refcount_set(&sysnames->usage, 1);
439 kill = sysnames;
6f8880d8 440
5b86d4ff 441 p = buf;
6f8880d8
DH
442 while ((s = strsep(&p, " \t\n"))) {
443 len = strlen(s);
444 if (len == 0)
445 continue;
446 ret = -ENAMETOOLONG;
447 if (len >= AFSNAMEMAX)
448 goto error;
449
450 if (len >= 4 &&
451 s[len - 4] == '@' &&
452 s[len - 3] == 's' &&
453 s[len - 2] == 'y' &&
454 s[len - 1] == 's')
455 /* Protect against recursion */
456 goto invalid;
457
458 if (s[0] == '.' &&
459 (len < 2 || (len == 2 && s[1] == '.')))
460 goto invalid;
461
462 if (memchr(s, '/', len))
463 goto invalid;
464
465 ret = -EFBIG;
466 if (sysnames->nr >= AFS_NR_SYSNAME)
467 goto out;
468
469 if (strcmp(s, afs_init_sysname) == 0) {
470 sub = (char *)afs_init_sysname;
471 } else {
472 ret = -ENOMEM;
473 sub = kmemdup(s, len + 1, GFP_KERNEL);
474 if (!sub)
475 goto out;
476 }
477
478 sysnames->subs[sysnames->nr] = sub;
479 sysnames->nr++;
480 }
481
5b86d4ff
DH
482 if (sysnames->nr == 0) {
483 sysnames->subs[0] = sysnames->blank;
484 sysnames->nr++;
485 }
486
487 write_lock(&net->sysnames_lock);
488 kill = net->sysnames;
489 net->sysnames = sysnames;
490 write_unlock(&net->sysnames_lock);
491 ret = 0;
6f8880d8 492out:
5b86d4ff 493 afs_put_sysnames(kill);
6f8880d8
DH
494 return ret;
495
496invalid:
497 ret = -EINVAL;
498error:
6f8880d8
DH
499 goto out;
500}
501
5d9de25d
DH
502void afs_put_sysnames(struct afs_sysnames *sysnames)
503{
504 int i;
505
506 if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
507 for (i = 0; i < sysnames->nr; i++)
508 if (sysnames->subs[i] != afs_init_sysname &&
509 sysnames->subs[i] != sysnames->blank)
510 kfree(sysnames->subs[i]);
511 }
512}
513
d55b4da4
DH
514/*
515 * Display general per-net namespace statistics
516 */
517static int afs_proc_stats_show(struct seq_file *m, void *v)
518{
5b86d4ff 519 struct afs_net *net = afs_seq2net_single(m);
d55b4da4
DH
520
521 seq_puts(m, "kAFS statistics\n");
522
f3ddee8d 523 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
d55b4da4
DH
524 atomic_read(&net->n_lookup),
525 atomic_read(&net->n_reval),
f3ddee8d
DH
526 atomic_read(&net->n_inval),
527 atomic_read(&net->n_relpg));
d55b4da4
DH
528
529 seq_printf(m, "dir-data: rdpg=%u\n",
530 atomic_read(&net->n_read_dir));
63a4681f
DH
531
532 seq_printf(m, "dir-edit: cr=%u rm=%u\n",
533 atomic_read(&net->n_dir_cr),
534 atomic_read(&net->n_dir_rm));
76a5cb6f
DH
535
536 seq_printf(m, "file-rd : n=%u nb=%lu\n",
537 atomic_read(&net->n_fetches),
538 atomic_long_read(&net->n_fetch_bytes));
539 seq_printf(m, "file-wr : n=%u nb=%lu\n",
540 atomic_read(&net->n_stores),
541 atomic_long_read(&net->n_store_bytes));
d55b4da4
DH
542 return 0;
543}
10495a00
DH
544
545/*
546 * initialise /proc/fs/afs/<cell>/
547 */
5b86d4ff 548int afs_proc_cell_setup(struct afs_cell *cell)
10495a00
DH
549{
550 struct proc_dir_entry *dir;
5b86d4ff 551 struct afs_net *net = cell->net;
10495a00
DH
552
553 _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
554
5b86d4ff 555 dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
10495a00
DH
556 if (!dir)
557 goto error_dir;
558
5b86d4ff
DH
559 if (!proc_create_net_data("vlservers", 0444, dir,
560 &afs_proc_cell_vlservers_ops,
561 sizeof(struct seq_net_private),
562 cell) ||
563 !proc_create_net_data("volumes", 0444, dir,
564 &afs_proc_cell_volumes_ops,
565 sizeof(struct seq_net_private),
566 cell))
10495a00
DH
567 goto error_tree;
568
569 _leave(" = 0");
570 return 0;
571
572error_tree:
573 remove_proc_subtree(cell->name, net->proc_afs);
574error_dir:
575 _leave(" = -ENOMEM");
576 return -ENOMEM;
577}
578
579/*
580 * remove /proc/fs/afs/<cell>/
581 */
5b86d4ff 582void afs_proc_cell_remove(struct afs_cell *cell)
10495a00 583{
5b86d4ff 584 struct afs_net *net = cell->net;
10495a00 585
5b86d4ff 586 _enter("");
10495a00 587 remove_proc_subtree(cell->name, net->proc_afs);
10495a00
DH
588 _leave("");
589}
590
591/*
592 * initialise the /proc/fs/afs/ directory
593 */
594int afs_proc_init(struct afs_net *net)
595{
5b86d4ff
DH
596 struct proc_dir_entry *p;
597
10495a00
DH
598 _enter("");
599
5b86d4ff
DH
600 p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
601 if (!p)
10495a00
DH
602 goto error_dir;
603
5b86d4ff
DH
604 if (!proc_create_net_data_write("cells", 0644, p,
605 &afs_proc_cells_ops,
606 afs_proc_cells_write,
607 sizeof(struct seq_net_private),
608 NULL) ||
609 !proc_create_net_single_write("rootcell", 0644, p,
610 afs_proc_rootcell_show,
611 afs_proc_rootcell_write,
612 NULL) ||
613 !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
614 sizeof(struct seq_net_private)) ||
615 !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
616 !proc_create_net_data_write("sysname", 0644, p,
617 &afs_proc_sysname_ops,
618 afs_proc_sysname_write,
619 sizeof(struct seq_net_private),
620 NULL))
10495a00
DH
621 goto error_tree;
622
5b86d4ff 623 net->proc_afs = p;
10495a00
DH
624 _leave(" = 0");
625 return 0;
626
627error_tree:
5b86d4ff 628 proc_remove(p);
10495a00
DH
629error_dir:
630 _leave(" = -ENOMEM");
631 return -ENOMEM;
632}
633
634/*
635 * clean up the /proc/fs/afs/ directory
636 */
637void afs_proc_cleanup(struct afs_net *net)
638{
639 proc_remove(net->proc_afs);
640 net->proc_afs = NULL;
641}
This page took 0.911301 seconds and 4 git commands to generate.