[AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use
[deliverable/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 (dhowells@redhat.com)
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>
16#include "cell.h"
17#include "volume.h"
18#include <asm/uaccess.h>
19#include "internal.h"
20
21static struct proc_dir_entry *proc_afs;
22
23
24static int afs_proc_cells_open(struct inode *inode, struct file *file);
25static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
26static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
27static void afs_proc_cells_stop(struct seq_file *p, void *v);
28static int afs_proc_cells_show(struct seq_file *m, void *v);
29static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
30 size_t size, loff_t *_pos);
31
32static struct seq_operations afs_proc_cells_ops = {
33 .start = afs_proc_cells_start,
34 .next = afs_proc_cells_next,
35 .stop = afs_proc_cells_stop,
36 .show = afs_proc_cells_show,
37};
38
4b6f5d20 39static const struct file_operations afs_proc_cells_fops = {
1da177e4
LT
40 .open = afs_proc_cells_open,
41 .read = seq_read,
42 .write = afs_proc_cells_write,
43 .llseek = seq_lseek,
44 .release = seq_release,
45};
46
47static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
48static int afs_proc_rootcell_release(struct inode *inode, struct file *file);
49static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
50 size_t size, loff_t *_pos);
51static ssize_t afs_proc_rootcell_write(struct file *file,
52 const char __user *buf,
53 size_t size, loff_t *_pos);
54
4b6f5d20 55static const struct file_operations afs_proc_rootcell_fops = {
1da177e4
LT
56 .open = afs_proc_rootcell_open,
57 .read = afs_proc_rootcell_read,
58 .write = afs_proc_rootcell_write,
59 .llseek = no_llseek,
60 .release = afs_proc_rootcell_release
61};
62
63static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
64static int afs_proc_cell_volumes_release(struct inode *inode,
65 struct file *file);
66static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
67static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
68 loff_t *pos);
69static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
70static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
71
72static struct seq_operations afs_proc_cell_volumes_ops = {
73 .start = afs_proc_cell_volumes_start,
74 .next = afs_proc_cell_volumes_next,
75 .stop = afs_proc_cell_volumes_stop,
76 .show = afs_proc_cell_volumes_show,
77};
78
4b6f5d20 79static const struct file_operations afs_proc_cell_volumes_fops = {
1da177e4
LT
80 .open = afs_proc_cell_volumes_open,
81 .read = seq_read,
82 .llseek = seq_lseek,
83 .release = afs_proc_cell_volumes_release,
84};
85
86static int afs_proc_cell_vlservers_open(struct inode *inode,
87 struct file *file);
88static int afs_proc_cell_vlservers_release(struct inode *inode,
89 struct file *file);
90static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
91static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
92 loff_t *pos);
93static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
94static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
95
96static struct seq_operations afs_proc_cell_vlservers_ops = {
97 .start = afs_proc_cell_vlservers_start,
98 .next = afs_proc_cell_vlservers_next,
99 .stop = afs_proc_cell_vlservers_stop,
100 .show = afs_proc_cell_vlservers_show,
101};
102
4b6f5d20 103static const struct file_operations afs_proc_cell_vlservers_fops = {
1da177e4
LT
104 .open = afs_proc_cell_vlservers_open,
105 .read = seq_read,
106 .llseek = seq_lseek,
107 .release = afs_proc_cell_vlservers_release,
108};
109
110static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
111static int afs_proc_cell_servers_release(struct inode *inode,
112 struct file *file);
113static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
114static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
115 loff_t *pos);
116static void afs_proc_cell_servers_stop(struct seq_file *p, void *v);
117static int afs_proc_cell_servers_show(struct seq_file *m, void *v);
118
119static struct seq_operations afs_proc_cell_servers_ops = {
120 .start = afs_proc_cell_servers_start,
121 .next = afs_proc_cell_servers_next,
122 .stop = afs_proc_cell_servers_stop,
123 .show = afs_proc_cell_servers_show,
124};
125
4b6f5d20 126static const struct file_operations afs_proc_cell_servers_fops = {
1da177e4
LT
127 .open = afs_proc_cell_servers_open,
128 .read = seq_read,
129 .llseek = seq_lseek,
130 .release = afs_proc_cell_servers_release,
131};
132
1da177e4
LT
133/*
134 * initialise the /proc/fs/afs/ directory
135 */
136int afs_proc_init(void)
137{
138 struct proc_dir_entry *p;
139
140 _enter("");
141
142 proc_afs = proc_mkdir("fs/afs", NULL);
143 if (!proc_afs)
ec26815a 144 goto error_dir;
1da177e4
LT
145 proc_afs->owner = THIS_MODULE;
146
147 p = create_proc_entry("cells", 0, proc_afs);
148 if (!p)
ec26815a 149 goto error_cells;
1da177e4
LT
150 p->proc_fops = &afs_proc_cells_fops;
151 p->owner = THIS_MODULE;
152
153 p = create_proc_entry("rootcell", 0, proc_afs);
154 if (!p)
ec26815a 155 goto error_rootcell;
1da177e4
LT
156 p->proc_fops = &afs_proc_rootcell_fops;
157 p->owner = THIS_MODULE;
158
159 _leave(" = 0");
160 return 0;
161
ec26815a 162error_rootcell:
1da177e4 163 remove_proc_entry("cells", proc_afs);
ec26815a 164error_cells:
1da177e4 165 remove_proc_entry("fs/afs", NULL);
ec26815a 166error_dir:
1da177e4
LT
167 _leave(" = -ENOMEM");
168 return -ENOMEM;
ec26815a 169}
1da177e4 170
1da177e4
LT
171/*
172 * clean up the /proc/fs/afs/ directory
173 */
174void afs_proc_cleanup(void)
175{
ec26815a 176 remove_proc_entry("rootcell", proc_afs);
1da177e4 177 remove_proc_entry("cells", proc_afs);
1da177e4 178 remove_proc_entry("fs/afs", NULL);
ec26815a 179}
1da177e4 180
1da177e4
LT
181/*
182 * open "/proc/fs/afs/cells" which provides a summary of extant cells
183 */
184static int afs_proc_cells_open(struct inode *inode, struct file *file)
185{
186 struct seq_file *m;
187 int ret;
188
189 ret = seq_open(file, &afs_proc_cells_ops);
190 if (ret < 0)
191 return ret;
192
193 m = file->private_data;
194 m->private = PDE(inode)->data;
195
196 return 0;
ec26815a 197}
1da177e4 198
1da177e4
LT
199/*
200 * set up the iterator to start reading from the cells list and return the
201 * first item
202 */
203static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
204{
205 struct list_head *_p;
206 loff_t pos = *_pos;
207
208 /* lock the list against modification */
209 down_read(&afs_proc_cells_sem);
210
211 /* allow for the header line */
212 if (!pos)
213 return (void *) 1;
214 pos--;
215
216 /* find the n'th element in the list */
217 list_for_each(_p, &afs_proc_cells)
218 if (!pos--)
219 break;
220
221 return _p != &afs_proc_cells ? _p : NULL;
ec26815a 222}
1da177e4 223
1da177e4
LT
224/*
225 * move to next cell in cells list
226 */
227static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
228{
229 struct list_head *_p;
230
231 (*pos)++;
232
233 _p = v;
234 _p = v == (void *) 1 ? afs_proc_cells.next : _p->next;
235
236 return _p != &afs_proc_cells ? _p : NULL;
ec26815a 237}
1da177e4 238
1da177e4
LT
239/*
240 * clean up after reading from the cells list
241 */
242static void afs_proc_cells_stop(struct seq_file *p, void *v)
243{
244 up_read(&afs_proc_cells_sem);
ec26815a 245}
1da177e4 246
1da177e4
LT
247/*
248 * display a header line followed by a load of cell lines
249 */
250static int afs_proc_cells_show(struct seq_file *m, void *v)
251{
252 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
253
1da177e4 254 if (v == (void *) 1) {
ec26815a 255 /* display header on line 1 */
1da177e4
LT
256 seq_puts(m, "USE NAME\n");
257 return 0;
258 }
259
260 /* display one cell per line on subsequent lines */
ec26815a
DH
261 seq_printf(m, "%3d %s\n",
262 atomic_read(&cell->usage), cell->name);
1da177e4 263 return 0;
ec26815a 264}
1da177e4 265
1da177e4
LT
266/*
267 * handle writes to /proc/fs/afs/cells
268 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
269 */
270static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
271 size_t size, loff_t *_pos)
272{
273 char *kbuf, *name, *args;
274 int ret;
275
276 /* start by dragging the command into memory */
277 if (size <= 1 || size >= PAGE_SIZE)
278 return -EINVAL;
279
280 kbuf = kmalloc(size + 1, GFP_KERNEL);
281 if (!kbuf)
282 return -ENOMEM;
283
284 ret = -EFAULT;
285 if (copy_from_user(kbuf, buf, size) != 0)
286 goto done;
287 kbuf[size] = 0;
288
289 /* trim to first NL */
290 name = memchr(kbuf, '\n', size);
291 if (name)
292 *name = 0;
293
294 /* split into command, name and argslist */
295 name = strchr(kbuf, ' ');
296 if (!name)
297 goto inval;
298 do {
299 *name++ = 0;
300 } while(*name == ' ');
301 if (!*name)
302 goto inval;
303
304 args = strchr(name, ' ');
305 if (!args)
306 goto inval;
307 do {
308 *args++ = 0;
309 } while(*args == ' ');
310 if (!*args)
311 goto inval;
312
313 /* determine command to perform */
314 _debug("cmd=%s name=%s args=%s", kbuf, name, args);
315
316 if (strcmp(kbuf, "add") == 0) {
317 struct afs_cell *cell;
318 ret = afs_cell_create(name, args, &cell);
319 if (ret < 0)
320 goto done;
321
322 printk("kAFS: Added new cell '%s'\n", name);
ec26815a 323 } else {
1da177e4
LT
324 goto inval;
325 }
326
327 ret = size;
328
ec26815a 329done:
1da177e4
LT
330 kfree(kbuf);
331 _leave(" = %d", ret);
332 return ret;
333
ec26815a 334inval:
1da177e4
LT
335 ret = -EINVAL;
336 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
337 goto done;
ec26815a 338}
1da177e4 339
1da177e4
LT
340/*
341 * Stubs for /proc/fs/afs/rootcell
342 */
343static int afs_proc_rootcell_open(struct inode *inode, struct file *file)
344{
345 return 0;
346}
347
348static int afs_proc_rootcell_release(struct inode *inode, struct file *file)
349{
350 return 0;
351}
352
353static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
354 size_t size, loff_t *_pos)
355{
356 return 0;
357}
358
1da177e4
LT
359/*
360 * handle writes to /proc/fs/afs/rootcell
361 * - to initialize rootcell: echo "cell.name:192.168.231.14"
362 */
363static ssize_t afs_proc_rootcell_write(struct file *file,
364 const char __user *buf,
365 size_t size, loff_t *_pos)
366{
367 char *kbuf, *s;
368 int ret;
369
370 /* start by dragging the command into memory */
371 if (size <= 1 || size >= PAGE_SIZE)
372 return -EINVAL;
373
374 ret = -ENOMEM;
375 kbuf = kmalloc(size + 1, GFP_KERNEL);
376 if (!kbuf)
377 goto nomem;
378
379 ret = -EFAULT;
380 if (copy_from_user(kbuf, buf, size) != 0)
381 goto infault;
382 kbuf[size] = 0;
383
384 /* trim to first NL */
385 s = memchr(kbuf, '\n', size);
386 if (s)
387 *s = 0;
388
389 /* determine command to perform */
390 _debug("rootcell=%s", kbuf);
391
392 ret = afs_cell_init(kbuf);
393 if (ret >= 0)
394 ret = size; /* consume everything, always */
395
ec26815a 396infault:
1da177e4 397 kfree(kbuf);
ec26815a 398nomem:
1da177e4
LT
399 _leave(" = %d", ret);
400 return ret;
ec26815a 401}
1da177e4 402
1da177e4
LT
403/*
404 * initialise /proc/fs/afs/<cell>/
405 */
406int afs_proc_cell_setup(struct afs_cell *cell)
407{
408 struct proc_dir_entry *p;
409
410 _enter("%p{%s}", cell, cell->name);
411
412 cell->proc_dir = proc_mkdir(cell->name, proc_afs);
413 if (!cell->proc_dir)
ec26815a 414 goto error_dir;
1da177e4
LT
415
416 p = create_proc_entry("servers", 0, cell->proc_dir);
417 if (!p)
ec26815a 418 goto error_servers;
1da177e4
LT
419 p->proc_fops = &afs_proc_cell_servers_fops;
420 p->owner = THIS_MODULE;
421 p->data = cell;
422
423 p = create_proc_entry("vlservers", 0, cell->proc_dir);
424 if (!p)
ec26815a 425 goto error_vlservers;
1da177e4
LT
426 p->proc_fops = &afs_proc_cell_vlservers_fops;
427 p->owner = THIS_MODULE;
428 p->data = cell;
429
430 p = create_proc_entry("volumes", 0, cell->proc_dir);
431 if (!p)
ec26815a 432 goto error_volumes;
1da177e4
LT
433 p->proc_fops = &afs_proc_cell_volumes_fops;
434 p->owner = THIS_MODULE;
435 p->data = cell;
436
437 _leave(" = 0");
438 return 0;
439
ec26815a 440error_volumes:
1da177e4 441 remove_proc_entry("vlservers", cell->proc_dir);
ec26815a 442error_vlservers:
1da177e4 443 remove_proc_entry("servers", cell->proc_dir);
ec26815a 444error_servers:
1da177e4 445 remove_proc_entry(cell->name, proc_afs);
ec26815a 446error_dir:
1da177e4
LT
447 _leave(" = -ENOMEM");
448 return -ENOMEM;
ec26815a 449}
1da177e4 450
1da177e4
LT
451/*
452 * remove /proc/fs/afs/<cell>/
453 */
454void afs_proc_cell_remove(struct afs_cell *cell)
455{
456 _enter("");
457
458 remove_proc_entry("volumes", cell->proc_dir);
459 remove_proc_entry("vlservers", cell->proc_dir);
460 remove_proc_entry("servers", cell->proc_dir);
461 remove_proc_entry(cell->name, proc_afs);
462
463 _leave("");
ec26815a 464}
1da177e4 465
1da177e4
LT
466/*
467 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
468 */
469static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
470{
471 struct afs_cell *cell;
472 struct seq_file *m;
473 int ret;
474
475 cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data);
476 if (!cell)
477 return -ENOENT;
478
479 ret = seq_open(file, &afs_proc_cell_volumes_ops);
480 if (ret < 0)
481 return ret;
482
483 m = file->private_data;
484 m->private = cell;
485
486 return 0;
ec26815a 487}
1da177e4 488
1da177e4
LT
489/*
490 * close the file and release the ref to the cell
491 */
492static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
493{
494 struct afs_cell *cell = PDE(inode)->data;
495 int ret;
496
ec26815a 497 ret = seq_release(inode, file);
1da177e4
LT
498
499 afs_put_cell(cell);
1da177e4 500 return ret;
ec26815a 501}
1da177e4 502
1da177e4
LT
503/*
504 * set up the iterator to start reading from the cells list and return the
505 * first item
506 */
507static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
508{
509 struct list_head *_p;
510 struct afs_cell *cell = m->private;
511 loff_t pos = *_pos;
512
513 _enter("cell=%p pos=%Ld", cell, *_pos);
514
515 /* lock the list against modification */
516 down_read(&cell->vl_sem);
517
518 /* allow for the header line */
519 if (!pos)
520 return (void *) 1;
521 pos--;
522
523 /* find the n'th element in the list */
524 list_for_each(_p, &cell->vl_list)
525 if (!pos--)
526 break;
527
528 return _p != &cell->vl_list ? _p : NULL;
ec26815a 529}
1da177e4 530
1da177e4
LT
531/*
532 * move to next cell in cells list
533 */
534static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
535 loff_t *_pos)
536{
537 struct list_head *_p;
538 struct afs_cell *cell = p->private;
539
540 _enter("cell=%p pos=%Ld", cell, *_pos);
541
542 (*_pos)++;
543
544 _p = v;
ec26815a 545 _p = (v == (void *) 1) ? cell->vl_list.next : _p->next;
1da177e4 546
ec26815a
DH
547 return (_p != &cell->vl_list) ? _p : NULL;
548}
1da177e4 549
1da177e4
LT
550/*
551 * clean up after reading from the cells list
552 */
553static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
554{
555 struct afs_cell *cell = p->private;
556
557 up_read(&cell->vl_sem);
ec26815a 558}
1da177e4 559
1da177e4
LT
560/*
561 * display a header line followed by a load of volume lines
562 */
563static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
564{
565 struct afs_vlocation *vlocation =
566 list_entry(v, struct afs_vlocation, link);
567
568 /* display header on line 1 */
569 if (v == (void *) 1) {
570 seq_puts(m, "USE VLID[0] VLID[1] VLID[2] NAME\n");
571 return 0;
572 }
573
574 /* display one cell per line on subsequent lines */
575 seq_printf(m, "%3d %08x %08x %08x %s\n",
576 atomic_read(&vlocation->usage),
577 vlocation->vldb.vid[0],
578 vlocation->vldb.vid[1],
579 vlocation->vldb.vid[2],
ec26815a 580 vlocation->vldb.name);
1da177e4
LT
581
582 return 0;
ec26815a 583}
1da177e4 584
1da177e4
LT
585/*
586 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
587 * location server
588 */
589static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
590{
591 struct afs_cell *cell;
592 struct seq_file *m;
593 int ret;
594
595 cell = afs_get_cell_maybe((struct afs_cell**)&PDE(inode)->data);
596 if (!cell)
597 return -ENOENT;
598
599 ret = seq_open(file,&afs_proc_cell_vlservers_ops);
600 if (ret<0)
601 return ret;
602
603 m = file->private_data;
604 m->private = cell;
605
606 return 0;
ec26815a 607}
1da177e4 608
1da177e4
LT
609/*
610 * close the file and release the ref to the cell
611 */
612static int afs_proc_cell_vlservers_release(struct inode *inode,
613 struct file *file)
614{
615 struct afs_cell *cell = PDE(inode)->data;
616 int ret;
617
618 ret = seq_release(inode,file);
619
620 afs_put_cell(cell);
1da177e4 621 return ret;
ec26815a 622}
1da177e4 623
1da177e4
LT
624/*
625 * set up the iterator to start reading from the cells list and return the
626 * first item
627 */
628static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
629{
630 struct afs_cell *cell = m->private;
631 loff_t pos = *_pos;
632
633 _enter("cell=%p pos=%Ld", cell, *_pos);
634
635 /* lock the list against modification */
636 down_read(&cell->vl_sem);
637
638 /* allow for the header line */
639 if (!pos)
640 return (void *) 1;
641 pos--;
642
643 if (pos >= cell->vl_naddrs)
644 return NULL;
645
646 return &cell->vl_addrs[pos];
ec26815a 647}
1da177e4 648
1da177e4
LT
649/*
650 * move to next cell in cells list
651 */
652static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
653 loff_t *_pos)
654{
655 struct afs_cell *cell = p->private;
656 loff_t pos;
657
658 _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos);
659
660 pos = *_pos;
661 (*_pos)++;
662 if (pos >= cell->vl_naddrs)
663 return NULL;
664
665 return &cell->vl_addrs[pos];
ec26815a 666}
1da177e4 667
1da177e4
LT
668/*
669 * clean up after reading from the cells list
670 */
671static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
672{
673 struct afs_cell *cell = p->private;
674
675 up_read(&cell->vl_sem);
ec26815a 676}
1da177e4 677
1da177e4
LT
678/*
679 * display a header line followed by a load of volume lines
680 */
681static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
682{
683 struct in_addr *addr = v;
684
685 /* display header on line 1 */
686 if (v == (struct in_addr *) 1) {
687 seq_puts(m, "ADDRESS\n");
688 return 0;
689 }
690
691 /* display one cell per line on subsequent lines */
692 seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr));
1da177e4 693 return 0;
ec26815a 694}
1da177e4 695
1da177e4
LT
696/*
697 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
698 * servers
699 */
700static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
701{
702 struct afs_cell *cell;
703 struct seq_file *m;
704 int ret;
705
706 cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data);
707 if (!cell)
708 return -ENOENT;
709
710 ret = seq_open(file, &afs_proc_cell_servers_ops);
711 if (ret < 0)
712 return ret;
713
714 m = file->private_data;
715 m->private = cell;
1da177e4 716 return 0;
ec26815a 717}
1da177e4 718
1da177e4
LT
719/*
720 * close the file and release the ref to the cell
721 */
722static int afs_proc_cell_servers_release(struct inode *inode,
723 struct file *file)
724{
725 struct afs_cell *cell = PDE(inode)->data;
726 int ret;
727
728 ret = seq_release(inode, file);
729
730 afs_put_cell(cell);
1da177e4 731 return ret;
ec26815a 732}
1da177e4 733
1da177e4
LT
734/*
735 * set up the iterator to start reading from the cells list and return the
736 * first item
737 */
738static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
99fc7059 739 __acquires(m->private->sv_lock)
1da177e4
LT
740{
741 struct list_head *_p;
742 struct afs_cell *cell = m->private;
743 loff_t pos = *_pos;
744
745 _enter("cell=%p pos=%Ld", cell, *_pos);
746
747 /* lock the list against modification */
748 read_lock(&cell->sv_lock);
749
750 /* allow for the header line */
751 if (!pos)
752 return (void *) 1;
753 pos--;
754
755 /* find the n'th element in the list */
756 list_for_each(_p, &cell->sv_list)
757 if (!pos--)
758 break;
759
760 return _p != &cell->sv_list ? _p : NULL;
ec26815a 761}
1da177e4 762
1da177e4
LT
763/*
764 * move to next cell in cells list
765 */
766static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
767 loff_t *_pos)
768{
769 struct list_head *_p;
770 struct afs_cell *cell = p->private;
771
772 _enter("cell=%p pos=%Ld", cell, *_pos);
773
774 (*_pos)++;
775
776 _p = v;
777 _p = v == (void *) 1 ? cell->sv_list.next : _p->next;
778
779 return _p != &cell->sv_list ? _p : NULL;
ec26815a 780}
1da177e4 781
1da177e4
LT
782/*
783 * clean up after reading from the cells list
784 */
785static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
99fc7059 786 __releases(p->private->sv_lock)
1da177e4
LT
787{
788 struct afs_cell *cell = p->private;
789
790 read_unlock(&cell->sv_lock);
ec26815a 791}
1da177e4 792
1da177e4
LT
793/*
794 * display a header line followed by a load of volume lines
795 */
796static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
797{
798 struct afs_server *server = list_entry(v, struct afs_server, link);
799 char ipaddr[20];
800
801 /* display header on line 1 */
802 if (v == (void *) 1) {
803 seq_puts(m, "USE ADDR STATE\n");
804 return 0;
805 }
806
807 /* display one cell per line on subsequent lines */
808 sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr));
809 seq_printf(m, "%3d %-15.15s %5d\n",
ec26815a 810 atomic_read(&server->usage), ipaddr, server->fs_state);
1da177e4
LT
811
812 return 0;
ec26815a 813}
This page took 0.20897 seconds and 5 git commands to generate.