]> Git Repo - linux.git/blob - fs/afs/proc.c
libbpf: Find correct module BTFs for struct_ops maps and progs.
[linux.git] / fs / afs / proc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* /proc interface for AFS
3  *
4  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells ([email protected])
6  */
7
8 #include <linux/slab.h>
9 #include <linux/module.h>
10 #include <linux/proc_fs.h>
11 #include <linux/seq_file.h>
12 #include <linux/sched.h>
13 #include <linux/uaccess.h>
14 #include "internal.h"
15
16 struct afs_vl_seq_net_private {
17         struct seq_net_private          seq;    /* Must be first */
18         struct afs_vlserver_list        *vllist;
19 };
20
21 static inline struct afs_net *afs_seq2net(struct seq_file *m)
22 {
23         return afs_net(seq_file_net(m));
24 }
25
26 static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
27 {
28         return afs_net(seq_file_single_net(m));
29 }
30
31 /*
32  * Display the list of cells known to the namespace.
33  */
34 static int afs_proc_cells_show(struct seq_file *m, void *v)
35 {
36         struct afs_vlserver_list *vllist;
37         struct afs_cell *cell;
38
39         if (v == SEQ_START_TOKEN) {
40                 /* display header on line 1 */
41                 seq_puts(m, "USE ACT    TTL SV ST NAME\n");
42                 return 0;
43         }
44
45         cell = list_entry(v, struct afs_cell, proc_link);
46         vllist = rcu_dereference(cell->vl_servers);
47
48         /* display one cell per line on subsequent lines */
49         seq_printf(m, "%3u %3u %6lld %2u %2u %s\n",
50                    refcount_read(&cell->ref),
51                    atomic_read(&cell->active),
52                    cell->dns_expiry - ktime_get_real_seconds(),
53                    vllist ? vllist->nr_servers : 0,
54                    cell->state,
55                    cell->name);
56         return 0;
57 }
58
59 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
60         __acquires(rcu)
61 {
62         rcu_read_lock();
63         return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos);
64 }
65
66 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
67 {
68         return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos);
69 }
70
71 static void afs_proc_cells_stop(struct seq_file *m, void *v)
72         __releases(rcu)
73 {
74         rcu_read_unlock();
75 }
76
77 static const struct seq_operations afs_proc_cells_ops = {
78         .start  = afs_proc_cells_start,
79         .next   = afs_proc_cells_next,
80         .stop   = afs_proc_cells_stop,
81         .show   = afs_proc_cells_show,
82 };
83
84 /*
85  * handle writes to /proc/fs/afs/cells
86  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
87  */
88 static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
89 {
90         struct seq_file *m = file->private_data;
91         struct afs_net *net = afs_seq2net(m);
92         char *name, *args;
93         int ret;
94
95         /* trim to first NL */
96         name = memchr(buf, '\n', size);
97         if (name)
98                 *name = 0;
99
100         /* split into command, name and argslist */
101         name = strchr(buf, ' ');
102         if (!name)
103                 goto inval;
104         do {
105                 *name++ = 0;
106         } while(*name == ' ');
107         if (!*name)
108                 goto inval;
109
110         args = strchr(name, ' ');
111         if (args) {
112                 do {
113                         *args++ = 0;
114                 } while(*args == ' ');
115                 if (!*args)
116                         goto inval;
117         }
118
119         /* determine command to perform */
120         _debug("cmd=%s name=%s args=%s", buf, name, args);
121
122         if (strcmp(buf, "add") == 0) {
123                 struct afs_cell *cell;
124
125                 cell = afs_lookup_cell(net, name, strlen(name), args, true);
126                 if (IS_ERR(cell)) {
127                         ret = PTR_ERR(cell);
128                         goto done;
129                 }
130
131                 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
132                         afs_unuse_cell(net, cell, afs_cell_trace_unuse_no_pin);
133         } else {
134                 goto inval;
135         }
136
137         ret = 0;
138
139 done:
140         _leave(" = %d", ret);
141         return ret;
142
143 inval:
144         ret = -EINVAL;
145         printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
146         goto done;
147 }
148
149 /*
150  * Display the list of addr_prefs known to the namespace.
151  */
152 static int afs_proc_addr_prefs_show(struct seq_file *m, void *v)
153 {
154         struct afs_addr_preference_list *preflist;
155         struct afs_addr_preference *pref;
156         struct afs_net *net = afs_seq2net_single(m);
157         union {
158                 struct sockaddr_in sin;
159                 struct sockaddr_in6 sin6;
160         } addr;
161         unsigned int i;
162         char buf[44]; /* Maximum ipv6 + max subnet is 43 */
163
164         rcu_read_lock();
165         preflist = rcu_dereference(net->address_prefs);
166
167         if (!preflist) {
168                 seq_puts(m, "NO PREFS\n");
169                 return 0;
170         }
171
172         seq_printf(m, "PROT SUBNET                                      PRIOR (v=%u n=%u/%u/%u)\n",
173                    preflist->version, preflist->ipv6_off, preflist->nr, preflist->max_prefs);
174
175         memset(&addr, 0, sizeof(addr));
176
177         for (i = 0; i < preflist->nr; i++) {
178                 pref = &preflist->prefs[i];
179
180                 addr.sin.sin_family = pref->family;
181                 if (pref->family == AF_INET) {
182                         memcpy(&addr.sin.sin_addr, &pref->ipv4_addr,
183                                sizeof(addr.sin.sin_addr));
184                         snprintf(buf, sizeof(buf), "%pISc/%u", &addr.sin, pref->subnet_mask);
185                         seq_printf(m, "UDP  %-43.43s %5u\n", buf, pref->prio);
186                 } else {
187                         memcpy(&addr.sin6.sin6_addr, &pref->ipv6_addr,
188                                sizeof(addr.sin6.sin6_addr));
189                         snprintf(buf, sizeof(buf), "%pISc/%u", &addr.sin6, pref->subnet_mask);
190                         seq_printf(m, "UDP  %-43.43s %5u\n", buf, pref->prio);
191                 }
192         }
193
194         rcu_read_lock();
195         return 0;
196 }
197
198 /*
199  * Display the name of the current workstation cell.
200  */
201 static int afs_proc_rootcell_show(struct seq_file *m, void *v)
202 {
203         struct afs_cell *cell;
204         struct afs_net *net;
205
206         net = afs_seq2net_single(m);
207         down_read(&net->cells_lock);
208         cell = net->ws_cell;
209         if (cell)
210                 seq_printf(m, "%s\n", cell->name);
211         up_read(&net->cells_lock);
212         return 0;
213 }
214
215 /*
216  * Set the current workstation cell and optionally supply its list of volume
217  * location servers.
218  *
219  *      echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
220  */
221 static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
222 {
223         struct seq_file *m = file->private_data;
224         struct afs_net *net = afs_seq2net_single(m);
225         char *s;
226         int ret;
227
228         ret = -EINVAL;
229         if (buf[0] == '.')
230                 goto out;
231         if (memchr(buf, '/', size))
232                 goto out;
233
234         /* trim to first NL */
235         s = memchr(buf, '\n', size);
236         if (s)
237                 *s = 0;
238
239         /* determine command to perform */
240         _debug("rootcell=%s", buf);
241
242         ret = afs_cell_init(net, buf);
243
244 out:
245         _leave(" = %d", ret);
246         return ret;
247 }
248
249 static const char afs_vol_types[3][3] = {
250         [AFSVL_RWVOL]   = "RW",
251         [AFSVL_ROVOL]   = "RO",
252         [AFSVL_BACKVOL] = "BK",
253 };
254
255 /*
256  * Display the list of volumes known to a cell.
257  */
258 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
259 {
260         struct afs_volume *vol = hlist_entry(v, struct afs_volume, proc_link);
261
262         /* Display header on line 1 */
263         if (v == SEQ_START_TOKEN) {
264                 seq_puts(m, "USE VID      TY NAME\n");
265                 return 0;
266         }
267
268         seq_printf(m, "%3d %08llx %s %s\n",
269                    refcount_read(&vol->ref), vol->vid,
270                    afs_vol_types[vol->type],
271                    vol->name);
272
273         return 0;
274 }
275
276 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
277         __acquires(cell->proc_lock)
278 {
279         struct afs_cell *cell = pde_data(file_inode(m->file));
280
281         rcu_read_lock();
282         return seq_hlist_start_head_rcu(&cell->proc_volumes, *_pos);
283 }
284
285 static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
286                                         loff_t *_pos)
287 {
288         struct afs_cell *cell = pde_data(file_inode(m->file));
289
290         return seq_hlist_next_rcu(v, &cell->proc_volumes, _pos);
291 }
292
293 static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
294         __releases(cell->proc_lock)
295 {
296         rcu_read_unlock();
297 }
298
299 static const struct seq_operations afs_proc_cell_volumes_ops = {
300         .start  = afs_proc_cell_volumes_start,
301         .next   = afs_proc_cell_volumes_next,
302         .stop   = afs_proc_cell_volumes_stop,
303         .show   = afs_proc_cell_volumes_show,
304 };
305
306 static const char *const dns_record_sources[NR__dns_record_source + 1] = {
307         [DNS_RECORD_UNAVAILABLE]        = "unav",
308         [DNS_RECORD_FROM_CONFIG]        = "cfg",
309         [DNS_RECORD_FROM_DNS_A]         = "A",
310         [DNS_RECORD_FROM_DNS_AFSDB]     = "AFSDB",
311         [DNS_RECORD_FROM_DNS_SRV]       = "SRV",
312         [DNS_RECORD_FROM_NSS]           = "nss",
313         [NR__dns_record_source]         = "[weird]"
314 };
315
316 static const char *const dns_lookup_statuses[NR__dns_lookup_status + 1] = {
317         [DNS_LOOKUP_NOT_DONE]           = "no-lookup",
318         [DNS_LOOKUP_GOOD]               = "good",
319         [DNS_LOOKUP_GOOD_WITH_BAD]      = "good/bad",
320         [DNS_LOOKUP_BAD]                = "bad",
321         [DNS_LOOKUP_GOT_NOT_FOUND]      = "not-found",
322         [DNS_LOOKUP_GOT_LOCAL_FAILURE]  = "local-failure",
323         [DNS_LOOKUP_GOT_TEMP_FAILURE]   = "temp-failure",
324         [DNS_LOOKUP_GOT_NS_FAILURE]     = "ns-failure",
325         [NR__dns_lookup_status]         = "[weird]"
326 };
327
328 /*
329  * Display the list of Volume Location servers we're using for a cell.
330  */
331 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
332 {
333         const struct afs_vl_seq_net_private *priv = m->private;
334         const struct afs_vlserver_list *vllist = priv->vllist;
335         const struct afs_vlserver_entry *entry;
336         const struct afs_vlserver *vlserver;
337         const struct afs_addr_list *alist;
338         int i;
339
340         if (v == SEQ_START_TOKEN) {
341                 seq_printf(m, "# source %s, status %s\n",
342                            dns_record_sources[vllist ? vllist->source : 0],
343                            dns_lookup_statuses[vllist ? vllist->status : 0]);
344                 return 0;
345         }
346
347         entry = v;
348         vlserver = entry->server;
349         alist = rcu_dereference(vlserver->addresses);
350
351         seq_printf(m, "%s [p=%hu w=%hu s=%s,%s]:\n",
352                    vlserver->name, entry->priority, entry->weight,
353                    dns_record_sources[alist ? alist->source : entry->source],
354                    dns_lookup_statuses[alist ? alist->status : entry->status]);
355         if (alist) {
356                 for (i = 0; i < alist->nr_addrs; i++)
357                         seq_printf(m, " %c %pISpc\n",
358                                    alist->preferred == i ? '>' : '-',
359                                    rxrpc_kernel_remote_addr(alist->addrs[i].peer));
360         }
361         seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt);
362         seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
363                    vlserver->probe.flags, vlserver->probe.error,
364                    vlserver->probe.abort_code,
365                    atomic_read(&vlserver->probe_outstanding));
366         return 0;
367 }
368
369 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
370         __acquires(rcu)
371 {
372         struct afs_vl_seq_net_private *priv = m->private;
373         struct afs_vlserver_list *vllist;
374         struct afs_cell *cell = pde_data(file_inode(m->file));
375         loff_t pos = *_pos;
376
377         rcu_read_lock();
378
379         vllist = rcu_dereference(cell->vl_servers);
380         priv->vllist = vllist;
381
382         if (pos < 0)
383                 *_pos = pos = 0;
384         if (pos == 0)
385                 return SEQ_START_TOKEN;
386
387         if (pos - 1 >= vllist->nr_servers)
388                 return NULL;
389
390         return &vllist->servers[pos - 1];
391 }
392
393 static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
394                                           loff_t *_pos)
395 {
396         struct afs_vl_seq_net_private *priv = m->private;
397         struct afs_vlserver_list *vllist = priv->vllist;
398         loff_t pos;
399
400         pos = *_pos;
401         pos++;
402         *_pos = pos;
403         if (!vllist || pos - 1 >= vllist->nr_servers)
404                 return NULL;
405
406         return &vllist->servers[pos - 1];
407 }
408
409 static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
410         __releases(rcu)
411 {
412         rcu_read_unlock();
413 }
414
415 static const struct seq_operations afs_proc_cell_vlservers_ops = {
416         .start  = afs_proc_cell_vlservers_start,
417         .next   = afs_proc_cell_vlservers_next,
418         .stop   = afs_proc_cell_vlservers_stop,
419         .show   = afs_proc_cell_vlservers_show,
420 };
421
422 /*
423  * Display the list of fileservers we're using within a namespace.
424  */
425 static int afs_proc_servers_show(struct seq_file *m, void *v)
426 {
427         struct afs_endpoint_state *estate;
428         struct afs_addr_list *alist;
429         struct afs_server *server;
430         unsigned long failed;
431         int i;
432
433         if (v == SEQ_START_TOKEN) {
434                 seq_puts(m, "UUID                                 REF ACT CELL\n");
435                 return 0;
436         }
437
438         server = list_entry(v, struct afs_server, proc_link);
439         estate = rcu_dereference(server->endpoint_state);
440         alist = estate->addresses;
441         seq_printf(m, "%pU %3d %3d %s\n",
442                    &server->uuid,
443                    refcount_read(&server->ref),
444                    atomic_read(&server->active),
445                    server->cell->name);
446         seq_printf(m, "  - info: fl=%lx rtt=%u\n",
447                    server->flags, server->rtt);
448         seq_printf(m, "  - probe: last=%d\n",
449                    (int)(jiffies - server->probed_at) / HZ);
450         failed = estate->failed_set;
451         seq_printf(m, "  - ESTATE pq=%x np=%u rsp=%lx f=%lx\n",
452                    estate->probe_seq, atomic_read(&estate->nr_probing),
453                    estate->responsive_set, estate->failed_set);
454         seq_printf(m, "  - ALIST v=%u ap=%u\n",
455                    alist->version, alist->addr_pref_version);
456         for (i = 0; i < alist->nr_addrs; i++) {
457                 const struct afs_address *addr = &alist->addrs[i];
458
459                 seq_printf(m, "    [%x] %pISpc%s rtt=%d err=%d p=%u\n",
460                            i, rxrpc_kernel_remote_addr(addr->peer),
461                            alist->preferred == i ? "*" :
462                            test_bit(i, &failed) ? "!" : "",
463                            rxrpc_kernel_get_srtt(addr->peer),
464                            addr->last_error, addr->prio);
465         }
466         return 0;
467 }
468
469 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
470         __acquires(rcu)
471 {
472         rcu_read_lock();
473         return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
474 }
475
476 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
477 {
478         return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
479 }
480
481 static void afs_proc_servers_stop(struct seq_file *m, void *v)
482         __releases(rcu)
483 {
484         rcu_read_unlock();
485 }
486
487 static const struct seq_operations afs_proc_servers_ops = {
488         .start  = afs_proc_servers_start,
489         .next   = afs_proc_servers_next,
490         .stop   = afs_proc_servers_stop,
491         .show   = afs_proc_servers_show,
492 };
493
494 /*
495  * Display the list of strings that may be substituted for the @sys pathname
496  * macro.
497  */
498 static int afs_proc_sysname_show(struct seq_file *m, void *v)
499 {
500         struct afs_net *net = afs_seq2net(m);
501         struct afs_sysnames *sysnames = net->sysnames;
502         unsigned int i = (unsigned long)v - 1;
503
504         if (i < sysnames->nr)
505                 seq_printf(m, "%s\n", sysnames->subs[i]);
506         return 0;
507 }
508
509 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
510         __acquires(&net->sysnames_lock)
511 {
512         struct afs_net *net = afs_seq2net(m);
513         struct afs_sysnames *names;
514
515         read_lock(&net->sysnames_lock);
516
517         names = net->sysnames;
518         if (*pos >= names->nr)
519                 return NULL;
520         return (void *)(unsigned long)(*pos + 1);
521 }
522
523 static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
524 {
525         struct afs_net *net = afs_seq2net(m);
526         struct afs_sysnames *names = net->sysnames;
527
528         *pos += 1;
529         if (*pos >= names->nr)
530                 return NULL;
531         return (void *)(unsigned long)(*pos + 1);
532 }
533
534 static void afs_proc_sysname_stop(struct seq_file *m, void *v)
535         __releases(&net->sysnames_lock)
536 {
537         struct afs_net *net = afs_seq2net(m);
538
539         read_unlock(&net->sysnames_lock);
540 }
541
542 static const struct seq_operations afs_proc_sysname_ops = {
543         .start  = afs_proc_sysname_start,
544         .next   = afs_proc_sysname_next,
545         .stop   = afs_proc_sysname_stop,
546         .show   = afs_proc_sysname_show,
547 };
548
549 /*
550  * Allow the @sys substitution to be configured.
551  */
552 static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
553 {
554         struct afs_sysnames *sysnames, *kill;
555         struct seq_file *m = file->private_data;
556         struct afs_net *net = afs_seq2net(m);
557         char *s, *p, *sub;
558         int ret, len;
559
560         sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
561         if (!sysnames)
562                 return -ENOMEM;
563         refcount_set(&sysnames->usage, 1);
564         kill = sysnames;
565
566         p = buf;
567         while ((s = strsep(&p, " \t\n"))) {
568                 len = strlen(s);
569                 if (len == 0)
570                         continue;
571                 ret = -ENAMETOOLONG;
572                 if (len >= AFSNAMEMAX)
573                         goto error;
574
575                 if (len >= 4 &&
576                     s[len - 4] == '@' &&
577                     s[len - 3] == 's' &&
578                     s[len - 2] == 'y' &&
579                     s[len - 1] == 's')
580                         /* Protect against recursion */
581                         goto invalid;
582
583                 if (s[0] == '.' &&
584                     (len < 2 || (len == 2 && s[1] == '.')))
585                         goto invalid;
586
587                 if (memchr(s, '/', len))
588                         goto invalid;
589
590                 ret = -EFBIG;
591                 if (sysnames->nr >= AFS_NR_SYSNAME)
592                         goto out;
593
594                 if (strcmp(s, afs_init_sysname) == 0) {
595                         sub = (char *)afs_init_sysname;
596                 } else {
597                         ret = -ENOMEM;
598                         sub = kmemdup(s, len + 1, GFP_KERNEL);
599                         if (!sub)
600                                 goto out;
601                 }
602
603                 sysnames->subs[sysnames->nr] = sub;
604                 sysnames->nr++;
605         }
606
607         if (sysnames->nr == 0) {
608                 sysnames->subs[0] = sysnames->blank;
609                 sysnames->nr++;
610         }
611
612         write_lock(&net->sysnames_lock);
613         kill = net->sysnames;
614         net->sysnames = sysnames;
615         write_unlock(&net->sysnames_lock);
616         ret = 0;
617 out:
618         afs_put_sysnames(kill);
619         return ret;
620
621 invalid:
622         ret = -EINVAL;
623 error:
624         goto out;
625 }
626
627 void afs_put_sysnames(struct afs_sysnames *sysnames)
628 {
629         int i;
630
631         if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
632                 for (i = 0; i < sysnames->nr; i++)
633                         if (sysnames->subs[i] != afs_init_sysname &&
634                             sysnames->subs[i] != sysnames->blank)
635                                 kfree(sysnames->subs[i]);
636                 kfree(sysnames);
637         }
638 }
639
640 /*
641  * Display general per-net namespace statistics
642  */
643 static int afs_proc_stats_show(struct seq_file *m, void *v)
644 {
645         struct afs_net *net = afs_seq2net_single(m);
646
647         seq_puts(m, "kAFS statistics\n");
648
649         seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
650                    atomic_read(&net->n_lookup),
651                    atomic_read(&net->n_reval),
652                    atomic_read(&net->n_inval),
653                    atomic_read(&net->n_relpg));
654
655         seq_printf(m, "dir-data: rdpg=%u\n",
656                    atomic_read(&net->n_read_dir));
657
658         seq_printf(m, "dir-edit: cr=%u rm=%u\n",
659                    atomic_read(&net->n_dir_cr),
660                    atomic_read(&net->n_dir_rm));
661
662         seq_printf(m, "file-rd : n=%u nb=%lu\n",
663                    atomic_read(&net->n_fetches),
664                    atomic_long_read(&net->n_fetch_bytes));
665         seq_printf(m, "file-wr : n=%u nb=%lu\n",
666                    atomic_read(&net->n_stores),
667                    atomic_long_read(&net->n_store_bytes));
668         return 0;
669 }
670
671 /*
672  * initialise /proc/fs/afs/<cell>/
673  */
674 int afs_proc_cell_setup(struct afs_cell *cell)
675 {
676         struct proc_dir_entry *dir;
677         struct afs_net *net = cell->net;
678
679         _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
680
681         dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
682         if (!dir)
683                 goto error_dir;
684
685         if (!proc_create_net_data("vlservers", 0444, dir,
686                                   &afs_proc_cell_vlservers_ops,
687                                   sizeof(struct afs_vl_seq_net_private),
688                                   cell) ||
689             !proc_create_net_data("volumes", 0444, dir,
690                                   &afs_proc_cell_volumes_ops,
691                                   sizeof(struct seq_net_private),
692                                   cell))
693                 goto error_tree;
694
695         _leave(" = 0");
696         return 0;
697
698 error_tree:
699         remove_proc_subtree(cell->name, net->proc_afs);
700 error_dir:
701         _leave(" = -ENOMEM");
702         return -ENOMEM;
703 }
704
705 /*
706  * remove /proc/fs/afs/<cell>/
707  */
708 void afs_proc_cell_remove(struct afs_cell *cell)
709 {
710         struct afs_net *net = cell->net;
711
712         _enter("");
713         remove_proc_subtree(cell->name, net->proc_afs);
714         _leave("");
715 }
716
717 /*
718  * initialise the /proc/fs/afs/ directory
719  */
720 int afs_proc_init(struct afs_net *net)
721 {
722         struct proc_dir_entry *p;
723
724         _enter("");
725
726         p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
727         if (!p)
728                 goto error_dir;
729
730         if (!proc_create_net_data_write("cells", 0644, p,
731                                         &afs_proc_cells_ops,
732                                         afs_proc_cells_write,
733                                         sizeof(struct seq_net_private),
734                                         NULL) ||
735             !proc_create_net_single_write("rootcell", 0644, p,
736                                           afs_proc_rootcell_show,
737                                           afs_proc_rootcell_write,
738                                           NULL) ||
739             !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
740                              sizeof(struct seq_net_private)) ||
741             !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
742             !proc_create_net_data_write("sysname", 0644, p,
743                                         &afs_proc_sysname_ops,
744                                         afs_proc_sysname_write,
745                                         sizeof(struct seq_net_private),
746                                         NULL) ||
747             !proc_create_net_single_write("addr_prefs", 0644, p,
748                                           afs_proc_addr_prefs_show,
749                                           afs_proc_addr_prefs_write,
750                                           NULL))
751                 goto error_tree;
752
753         net->proc_afs = p;
754         _leave(" = 0");
755         return 0;
756
757 error_tree:
758         proc_remove(p);
759 error_dir:
760         _leave(" = -ENOMEM");
761         return -ENOMEM;
762 }
763
764 /*
765  * clean up the /proc/fs/afs/ directory
766  */
767 void afs_proc_cleanup(struct afs_net *net)
768 {
769         proc_remove(net->proc_afs);
770         net->proc_afs = NULL;
771 }
This page took 0.071989 seconds and 4 git commands to generate.