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