]>
Commit | Line | Data |
---|---|---|
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 | ||
21 | static struct proc_dir_entry *proc_afs; | |
22 | ||
23 | ||
24 | static int afs_proc_cells_open(struct inode *inode, struct file *file); | |
25 | static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos); | |
26 | static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos); | |
27 | static void afs_proc_cells_stop(struct seq_file *p, void *v); | |
28 | static int afs_proc_cells_show(struct seq_file *m, void *v); | |
29 | static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |
30 | size_t size, loff_t *_pos); | |
31 | ||
32 | static 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 | 39 | static 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 | ||
47 | static int afs_proc_rootcell_open(struct inode *inode, struct file *file); | |
48 | static int afs_proc_rootcell_release(struct inode *inode, struct file *file); | |
49 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, | |
50 | size_t size, loff_t *_pos); | |
51 | static ssize_t afs_proc_rootcell_write(struct file *file, | |
52 | const char __user *buf, | |
53 | size_t size, loff_t *_pos); | |
54 | ||
4b6f5d20 | 55 | static 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 | ||
63 | static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); | |
64 | static int afs_proc_cell_volumes_release(struct inode *inode, | |
65 | struct file *file); | |
66 | static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); | |
67 | static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | |
68 | loff_t *pos); | |
69 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v); | |
70 | static int afs_proc_cell_volumes_show(struct seq_file *m, void *v); | |
71 | ||
72 | static 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 | 79 | static 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 | ||
86 | static int afs_proc_cell_vlservers_open(struct inode *inode, | |
87 | struct file *file); | |
88 | static int afs_proc_cell_vlservers_release(struct inode *inode, | |
89 | struct file *file); | |
90 | static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); | |
91 | static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | |
92 | loff_t *pos); | |
93 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v); | |
94 | static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v); | |
95 | ||
96 | static 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 | 103 | static 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 | ||
110 | static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); | |
111 | static int afs_proc_cell_servers_release(struct inode *inode, | |
112 | struct file *file); | |
113 | static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos); | |
114 | static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, | |
115 | loff_t *pos); | |
116 | static void afs_proc_cell_servers_stop(struct seq_file *p, void *v); | |
117 | static int afs_proc_cell_servers_show(struct seq_file *m, void *v); | |
118 | ||
119 | static 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 | 126 | static 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 | */ | |
136 | int 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 | 162 | error_rootcell: |
1da177e4 | 163 | remove_proc_entry("cells", proc_afs); |
ec26815a | 164 | error_cells: |
1da177e4 | 165 | remove_proc_entry("fs/afs", NULL); |
ec26815a | 166 | error_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 | */ | |
174 | void 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 | */ | |
184 | static 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 | */ | |
203 | static 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 | */ | |
227 | static 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 | */ | |
242 | static 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 | */ | |
250 | static 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 | */ | |
270 | static 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 | 329 | done: |
1da177e4 LT |
330 | kfree(kbuf); |
331 | _leave(" = %d", ret); | |
332 | return ret; | |
333 | ||
ec26815a | 334 | inval: |
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 | */ | |
343 | static int afs_proc_rootcell_open(struct inode *inode, struct file *file) | |
344 | { | |
345 | return 0; | |
346 | } | |
347 | ||
348 | static int afs_proc_rootcell_release(struct inode *inode, struct file *file) | |
349 | { | |
350 | return 0; | |
351 | } | |
352 | ||
353 | static 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 | */ | |
363 | static 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 | 396 | infault: |
1da177e4 | 397 | kfree(kbuf); |
ec26815a | 398 | nomem: |
1da177e4 LT |
399 | _leave(" = %d", ret); |
400 | return ret; | |
ec26815a | 401 | } |
1da177e4 | 402 | |
1da177e4 LT |
403 | /* |
404 | * initialise /proc/fs/afs/<cell>/ | |
405 | */ | |
406 | int 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 | 440 | error_volumes: |
1da177e4 | 441 | remove_proc_entry("vlservers", cell->proc_dir); |
ec26815a | 442 | error_vlservers: |
1da177e4 | 443 | remove_proc_entry("servers", cell->proc_dir); |
ec26815a | 444 | error_servers: |
1da177e4 | 445 | remove_proc_entry(cell->name, proc_afs); |
ec26815a | 446 | error_dir: |
1da177e4 LT |
447 | _leave(" = -ENOMEM"); |
448 | return -ENOMEM; | |
ec26815a | 449 | } |
1da177e4 | 450 | |
1da177e4 LT |
451 | /* |
452 | * remove /proc/fs/afs/<cell>/ | |
453 | */ | |
454 | void 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 | */ | |
469 | static 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 | */ | |
492 | static 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 | */ | |
507 | static 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 | */ | |
534 | static 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 | */ | |
553 | static 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 | */ | |
563 | static 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 | */ | |
589 | static 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 | */ | |
612 | static 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 | */ | |
628 | static 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 | */ | |
652 | static 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 | */ | |
671 | static 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 | */ | |
681 | static 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 | */ | |
700 | static 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 | */ | |
722 | static 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 | */ | |
738 | static 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 | */ | |
766 | static 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 | */ | |
785 | static 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 | */ | |
796 | static 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 | } |