]>
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 ([email protected]) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | ||
1da177e4 LT |
12 | #include <linux/slab.h> |
13 | #include <linux/module.h> | |
14 | #include <linux/proc_fs.h> | |
15 | #include <linux/seq_file.h> | |
e8edc6e0 | 16 | #include <linux/sched.h> |
1da177e4 LT |
17 | #include <asm/uaccess.h> |
18 | #include "internal.h" | |
19 | ||
20 | static struct proc_dir_entry *proc_afs; | |
21 | ||
22 | ||
23 | static int afs_proc_cells_open(struct inode *inode, struct file *file); | |
24 | static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos); | |
25 | static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos); | |
26 | static void afs_proc_cells_stop(struct seq_file *p, void *v); | |
27 | static int afs_proc_cells_show(struct seq_file *m, void *v); | |
28 | static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |
29 | size_t size, loff_t *_pos); | |
30 | ||
88e9d34c | 31 | static const struct seq_operations afs_proc_cells_ops = { |
1da177e4 LT |
32 | .start = afs_proc_cells_start, |
33 | .next = afs_proc_cells_next, | |
34 | .stop = afs_proc_cells_stop, | |
35 | .show = afs_proc_cells_show, | |
36 | }; | |
37 | ||
4b6f5d20 | 38 | static const struct file_operations afs_proc_cells_fops = { |
1da177e4 LT |
39 | .open = afs_proc_cells_open, |
40 | .read = seq_read, | |
41 | .write = afs_proc_cells_write, | |
42 | .llseek = seq_lseek, | |
43 | .release = seq_release, | |
44 | }; | |
45 | ||
1da177e4 LT |
46 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, |
47 | size_t size, loff_t *_pos); | |
48 | static ssize_t afs_proc_rootcell_write(struct file *file, | |
49 | const char __user *buf, | |
50 | size_t size, loff_t *_pos); | |
51 | ||
4b6f5d20 | 52 | static const struct file_operations afs_proc_rootcell_fops = { |
1da177e4 LT |
53 | .read = afs_proc_rootcell_read, |
54 | .write = afs_proc_rootcell_write, | |
55 | .llseek = no_llseek, | |
1da177e4 LT |
56 | }; |
57 | ||
58 | static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); | |
1da177e4 LT |
59 | static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); |
60 | static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | |
61 | loff_t *pos); | |
62 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v); | |
63 | static int afs_proc_cell_volumes_show(struct seq_file *m, void *v); | |
64 | ||
88e9d34c | 65 | static const struct seq_operations afs_proc_cell_volumes_ops = { |
1da177e4 LT |
66 | .start = afs_proc_cell_volumes_start, |
67 | .next = afs_proc_cell_volumes_next, | |
68 | .stop = afs_proc_cell_volumes_stop, | |
69 | .show = afs_proc_cell_volumes_show, | |
70 | }; | |
71 | ||
4b6f5d20 | 72 | static const struct file_operations afs_proc_cell_volumes_fops = { |
1da177e4 LT |
73 | .open = afs_proc_cell_volumes_open, |
74 | .read = seq_read, | |
75 | .llseek = seq_lseek, | |
b42d570c | 76 | .release = seq_release, |
1da177e4 LT |
77 | }; |
78 | ||
79 | static int afs_proc_cell_vlservers_open(struct inode *inode, | |
80 | struct file *file); | |
1da177e4 LT |
81 | static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); |
82 | static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | |
83 | loff_t *pos); | |
84 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v); | |
85 | static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v); | |
86 | ||
88e9d34c | 87 | static const struct seq_operations afs_proc_cell_vlservers_ops = { |
1da177e4 LT |
88 | .start = afs_proc_cell_vlservers_start, |
89 | .next = afs_proc_cell_vlservers_next, | |
90 | .stop = afs_proc_cell_vlservers_stop, | |
91 | .show = afs_proc_cell_vlservers_show, | |
92 | }; | |
93 | ||
4b6f5d20 | 94 | static const struct file_operations afs_proc_cell_vlservers_fops = { |
1da177e4 LT |
95 | .open = afs_proc_cell_vlservers_open, |
96 | .read = seq_read, | |
97 | .llseek = seq_lseek, | |
b42d570c | 98 | .release = seq_release, |
1da177e4 LT |
99 | }; |
100 | ||
101 | static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); | |
1da177e4 LT |
102 | static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos); |
103 | static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, | |
104 | loff_t *pos); | |
105 | static void afs_proc_cell_servers_stop(struct seq_file *p, void *v); | |
106 | static int afs_proc_cell_servers_show(struct seq_file *m, void *v); | |
107 | ||
88e9d34c | 108 | static const struct seq_operations afs_proc_cell_servers_ops = { |
1da177e4 LT |
109 | .start = afs_proc_cell_servers_start, |
110 | .next = afs_proc_cell_servers_next, | |
111 | .stop = afs_proc_cell_servers_stop, | |
112 | .show = afs_proc_cell_servers_show, | |
113 | }; | |
114 | ||
4b6f5d20 | 115 | static const struct file_operations afs_proc_cell_servers_fops = { |
1da177e4 LT |
116 | .open = afs_proc_cell_servers_open, |
117 | .read = seq_read, | |
118 | .llseek = seq_lseek, | |
b42d570c | 119 | .release = seq_release, |
1da177e4 LT |
120 | }; |
121 | ||
1da177e4 LT |
122 | /* |
123 | * initialise the /proc/fs/afs/ directory | |
124 | */ | |
125 | int afs_proc_init(void) | |
126 | { | |
1da177e4 LT |
127 | _enter(""); |
128 | ||
129 | proc_afs = proc_mkdir("fs/afs", NULL); | |
130 | if (!proc_afs) | |
ec26815a | 131 | goto error_dir; |
1da177e4 | 132 | |
1bda2ac0 PR |
133 | if (!proc_create("cells", 0644, proc_afs, &afs_proc_cells_fops) || |
134 | !proc_create("rootcell", 0644, proc_afs, &afs_proc_rootcell_fops)) | |
b42d570c | 135 | goto error_tree; |
1da177e4 LT |
136 | |
137 | _leave(" = 0"); | |
138 | return 0; | |
139 | ||
b42d570c AV |
140 | error_tree: |
141 | remove_proc_subtree("fs/afs", NULL); | |
ec26815a | 142 | error_dir: |
1da177e4 LT |
143 | _leave(" = -ENOMEM"); |
144 | return -ENOMEM; | |
ec26815a | 145 | } |
1da177e4 | 146 | |
1da177e4 LT |
147 | /* |
148 | * clean up the /proc/fs/afs/ directory | |
149 | */ | |
150 | void afs_proc_cleanup(void) | |
151 | { | |
b42d570c | 152 | remove_proc_subtree("fs/afs", NULL); |
ec26815a | 153 | } |
1da177e4 | 154 | |
1da177e4 LT |
155 | /* |
156 | * open "/proc/fs/afs/cells" which provides a summary of extant cells | |
157 | */ | |
158 | static int afs_proc_cells_open(struct inode *inode, struct file *file) | |
159 | { | |
160 | struct seq_file *m; | |
161 | int ret; | |
162 | ||
163 | ret = seq_open(file, &afs_proc_cells_ops); | |
164 | if (ret < 0) | |
165 | return ret; | |
166 | ||
167 | m = file->private_data; | |
d9dda78b | 168 | m->private = PDE_DATA(inode); |
1da177e4 LT |
169 | |
170 | return 0; | |
ec26815a | 171 | } |
1da177e4 | 172 | |
1da177e4 LT |
173 | /* |
174 | * set up the iterator to start reading from the cells list and return the | |
175 | * first item | |
176 | */ | |
177 | static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) | |
178 | { | |
1da177e4 LT |
179 | /* lock the list against modification */ |
180 | down_read(&afs_proc_cells_sem); | |
a6a8bd6d | 181 | return seq_list_start_head(&afs_proc_cells, *_pos); |
ec26815a | 182 | } |
1da177e4 | 183 | |
1da177e4 LT |
184 | /* |
185 | * move to next cell in cells list | |
186 | */ | |
187 | static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos) | |
188 | { | |
a6a8bd6d | 189 | return seq_list_next(v, &afs_proc_cells, pos); |
ec26815a | 190 | } |
1da177e4 | 191 | |
1da177e4 LT |
192 | /* |
193 | * clean up after reading from the cells list | |
194 | */ | |
195 | static void afs_proc_cells_stop(struct seq_file *p, void *v) | |
196 | { | |
197 | up_read(&afs_proc_cells_sem); | |
ec26815a | 198 | } |
1da177e4 | 199 | |
1da177e4 LT |
200 | /* |
201 | * display a header line followed by a load of cell lines | |
202 | */ | |
203 | static int afs_proc_cells_show(struct seq_file *m, void *v) | |
204 | { | |
205 | struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); | |
206 | ||
a6a8bd6d | 207 | if (v == &afs_proc_cells) { |
ec26815a | 208 | /* display header on line 1 */ |
1da177e4 LT |
209 | seq_puts(m, "USE NAME\n"); |
210 | return 0; | |
211 | } | |
212 | ||
213 | /* display one cell per line on subsequent lines */ | |
ec26815a DH |
214 | seq_printf(m, "%3d %s\n", |
215 | atomic_read(&cell->usage), cell->name); | |
1da177e4 | 216 | return 0; |
ec26815a | 217 | } |
1da177e4 | 218 | |
1da177e4 LT |
219 | /* |
220 | * handle writes to /proc/fs/afs/cells | |
221 | * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" | |
222 | */ | |
223 | static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |
224 | size_t size, loff_t *_pos) | |
225 | { | |
226 | char *kbuf, *name, *args; | |
227 | int ret; | |
228 | ||
229 | /* start by dragging the command into memory */ | |
230 | if (size <= 1 || size >= PAGE_SIZE) | |
231 | return -EINVAL; | |
232 | ||
16e5c1fc AV |
233 | kbuf = memdup_user_nul(buf, size); |
234 | if (IS_ERR(kbuf)) | |
235 | return PTR_ERR(kbuf); | |
1da177e4 LT |
236 | |
237 | /* trim to first NL */ | |
238 | name = memchr(kbuf, '\n', size); | |
239 | if (name) | |
240 | *name = 0; | |
241 | ||
242 | /* split into command, name and argslist */ | |
243 | name = strchr(kbuf, ' '); | |
244 | if (!name) | |
245 | goto inval; | |
246 | do { | |
247 | *name++ = 0; | |
248 | } while(*name == ' '); | |
249 | if (!*name) | |
250 | goto inval; | |
251 | ||
252 | args = strchr(name, ' '); | |
253 | if (!args) | |
254 | goto inval; | |
255 | do { | |
256 | *args++ = 0; | |
257 | } while(*args == ' '); | |
258 | if (!*args) | |
259 | goto inval; | |
260 | ||
261 | /* determine command to perform */ | |
262 | _debug("cmd=%s name=%s args=%s", kbuf, name, args); | |
263 | ||
264 | if (strcmp(kbuf, "add") == 0) { | |
265 | struct afs_cell *cell; | |
08e0e7c8 | 266 | |
bec5eb61 | 267 | cell = afs_cell_create(name, strlen(name), args, false); |
08e0e7c8 DH |
268 | if (IS_ERR(cell)) { |
269 | ret = PTR_ERR(cell); | |
1da177e4 | 270 | goto done; |
08e0e7c8 | 271 | } |
1da177e4 | 272 | |
08e0e7c8 | 273 | afs_put_cell(cell); |
1da177e4 | 274 | printk("kAFS: Added new cell '%s'\n", name); |
ec26815a | 275 | } else { |
1da177e4 LT |
276 | goto inval; |
277 | } | |
278 | ||
279 | ret = size; | |
280 | ||
ec26815a | 281 | done: |
1da177e4 LT |
282 | kfree(kbuf); |
283 | _leave(" = %d", ret); | |
284 | return ret; | |
285 | ||
ec26815a | 286 | inval: |
1da177e4 LT |
287 | ret = -EINVAL; |
288 | printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); | |
289 | goto done; | |
ec26815a | 290 | } |
1da177e4 | 291 | |
1da177e4 LT |
292 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, |
293 | size_t size, loff_t *_pos) | |
294 | { | |
295 | return 0; | |
296 | } | |
297 | ||
1da177e4 LT |
298 | /* |
299 | * handle writes to /proc/fs/afs/rootcell | |
300 | * - to initialize rootcell: echo "cell.name:192.168.231.14" | |
301 | */ | |
302 | static ssize_t afs_proc_rootcell_write(struct file *file, | |
303 | const char __user *buf, | |
304 | size_t size, loff_t *_pos) | |
305 | { | |
306 | char *kbuf, *s; | |
307 | int ret; | |
308 | ||
309 | /* start by dragging the command into memory */ | |
310 | if (size <= 1 || size >= PAGE_SIZE) | |
311 | return -EINVAL; | |
312 | ||
16e5c1fc AV |
313 | kbuf = memdup_user_nul(buf, size); |
314 | if (IS_ERR(kbuf)) | |
315 | return PTR_ERR(kbuf); | |
1da177e4 LT |
316 | |
317 | /* trim to first NL */ | |
318 | s = memchr(kbuf, '\n', size); | |
319 | if (s) | |
320 | *s = 0; | |
321 | ||
322 | /* determine command to perform */ | |
323 | _debug("rootcell=%s", kbuf); | |
324 | ||
325 | ret = afs_cell_init(kbuf); | |
326 | if (ret >= 0) | |
327 | ret = size; /* consume everything, always */ | |
328 | ||
1da177e4 | 329 | kfree(kbuf); |
1da177e4 LT |
330 | _leave(" = %d", ret); |
331 | return ret; | |
ec26815a | 332 | } |
1da177e4 | 333 | |
1da177e4 LT |
334 | /* |
335 | * initialise /proc/fs/afs/<cell>/ | |
336 | */ | |
337 | int afs_proc_cell_setup(struct afs_cell *cell) | |
338 | { | |
b42d570c | 339 | struct proc_dir_entry *dir; |
1da177e4 LT |
340 | |
341 | _enter("%p{%s}", cell, cell->name); | |
342 | ||
b42d570c AV |
343 | dir = proc_mkdir(cell->name, proc_afs); |
344 | if (!dir) | |
ec26815a | 345 | goto error_dir; |
1da177e4 | 346 | |
b42d570c AV |
347 | if (!proc_create_data("servers", 0, dir, |
348 | &afs_proc_cell_servers_fops, cell) || | |
349 | !proc_create_data("vlservers", 0, dir, | |
350 | &afs_proc_cell_vlservers_fops, cell) || | |
351 | !proc_create_data("volumes", 0, dir, | |
352 | &afs_proc_cell_volumes_fops, cell)) | |
353 | goto error_tree; | |
1da177e4 LT |
354 | |
355 | _leave(" = 0"); | |
356 | return 0; | |
357 | ||
b42d570c AV |
358 | error_tree: |
359 | remove_proc_subtree(cell->name, proc_afs); | |
ec26815a | 360 | error_dir: |
1da177e4 LT |
361 | _leave(" = -ENOMEM"); |
362 | return -ENOMEM; | |
ec26815a | 363 | } |
1da177e4 | 364 | |
1da177e4 LT |
365 | /* |
366 | * remove /proc/fs/afs/<cell>/ | |
367 | */ | |
368 | void afs_proc_cell_remove(struct afs_cell *cell) | |
369 | { | |
370 | _enter(""); | |
371 | ||
b42d570c | 372 | remove_proc_subtree(cell->name, proc_afs); |
1da177e4 LT |
373 | |
374 | _leave(""); | |
ec26815a | 375 | } |
1da177e4 | 376 | |
1da177e4 LT |
377 | /* |
378 | * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells | |
379 | */ | |
380 | static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) | |
381 | { | |
382 | struct afs_cell *cell; | |
383 | struct seq_file *m; | |
384 | int ret; | |
385 | ||
d9dda78b | 386 | cell = PDE_DATA(inode); |
1da177e4 LT |
387 | if (!cell) |
388 | return -ENOENT; | |
389 | ||
390 | ret = seq_open(file, &afs_proc_cell_volumes_ops); | |
391 | if (ret < 0) | |
392 | return ret; | |
393 | ||
394 | m = file->private_data; | |
395 | m->private = cell; | |
396 | ||
397 | return 0; | |
ec26815a | 398 | } |
1da177e4 | 399 | |
1da177e4 LT |
400 | /* |
401 | * set up the iterator to start reading from the cells list and return the | |
402 | * first item | |
403 | */ | |
404 | static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) | |
405 | { | |
1da177e4 | 406 | struct afs_cell *cell = m->private; |
1da177e4 LT |
407 | |
408 | _enter("cell=%p pos=%Ld", cell, *_pos); | |
409 | ||
410 | /* lock the list against modification */ | |
411 | down_read(&cell->vl_sem); | |
a6a8bd6d | 412 | return seq_list_start_head(&cell->vl_list, *_pos); |
ec26815a | 413 | } |
1da177e4 | 414 | |
1da177e4 LT |
415 | /* |
416 | * move to next cell in cells list | |
417 | */ | |
418 | static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | |
419 | loff_t *_pos) | |
420 | { | |
1da177e4 LT |
421 | struct afs_cell *cell = p->private; |
422 | ||
423 | _enter("cell=%p pos=%Ld", cell, *_pos); | |
a6a8bd6d | 424 | return seq_list_next(v, &cell->vl_list, _pos); |
ec26815a | 425 | } |
1da177e4 | 426 | |
1da177e4 LT |
427 | /* |
428 | * clean up after reading from the cells list | |
429 | */ | |
430 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) | |
431 | { | |
432 | struct afs_cell *cell = p->private; | |
433 | ||
434 | up_read(&cell->vl_sem); | |
ec26815a | 435 | } |
1da177e4 | 436 | |
c1206a2c | 437 | static const char afs_vlocation_states[][4] = { |
08e0e7c8 DH |
438 | [AFS_VL_NEW] = "New", |
439 | [AFS_VL_CREATING] = "Crt", | |
440 | [AFS_VL_VALID] = "Val", | |
441 | [AFS_VL_NO_VOLUME] = "NoV", | |
442 | [AFS_VL_UPDATING] = "Upd", | |
443 | [AFS_VL_VOLUME_DELETED] = "Del", | |
444 | [AFS_VL_UNCERTAIN] = "Unc", | |
445 | }; | |
446 | ||
1da177e4 LT |
447 | /* |
448 | * display a header line followed by a load of volume lines | |
449 | */ | |
450 | static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) | |
451 | { | |
a6a8bd6d | 452 | struct afs_cell *cell = m->private; |
1da177e4 LT |
453 | struct afs_vlocation *vlocation = |
454 | list_entry(v, struct afs_vlocation, link); | |
455 | ||
456 | /* display header on line 1 */ | |
a6a8bd6d | 457 | if (v == &cell->vl_list) { |
08e0e7c8 | 458 | seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n"); |
1da177e4 LT |
459 | return 0; |
460 | } | |
461 | ||
462 | /* display one cell per line on subsequent lines */ | |
08e0e7c8 | 463 | seq_printf(m, "%3d %s %08x %08x %08x %s\n", |
1da177e4 | 464 | atomic_read(&vlocation->usage), |
08e0e7c8 | 465 | afs_vlocation_states[vlocation->state], |
1da177e4 LT |
466 | vlocation->vldb.vid[0], |
467 | vlocation->vldb.vid[1], | |
468 | vlocation->vldb.vid[2], | |
ec26815a | 469 | vlocation->vldb.name); |
1da177e4 LT |
470 | |
471 | return 0; | |
ec26815a | 472 | } |
1da177e4 | 473 | |
1da177e4 LT |
474 | /* |
475 | * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume | |
476 | * location server | |
477 | */ | |
478 | static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) | |
479 | { | |
480 | struct afs_cell *cell; | |
481 | struct seq_file *m; | |
482 | int ret; | |
483 | ||
d9dda78b | 484 | cell = PDE_DATA(inode); |
1da177e4 LT |
485 | if (!cell) |
486 | return -ENOENT; | |
487 | ||
08e0e7c8 | 488 | ret = seq_open(file, &afs_proc_cell_vlservers_ops); |
1da177e4 LT |
489 | if (ret<0) |
490 | return ret; | |
491 | ||
492 | m = file->private_data; | |
493 | m->private = cell; | |
494 | ||
495 | return 0; | |
ec26815a | 496 | } |
1da177e4 | 497 | |
1da177e4 LT |
498 | /* |
499 | * set up the iterator to start reading from the cells list and return the | |
500 | * first item | |
501 | */ | |
502 | static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) | |
503 | { | |
504 | struct afs_cell *cell = m->private; | |
505 | loff_t pos = *_pos; | |
506 | ||
507 | _enter("cell=%p pos=%Ld", cell, *_pos); | |
508 | ||
509 | /* lock the list against modification */ | |
510 | down_read(&cell->vl_sem); | |
511 | ||
512 | /* allow for the header line */ | |
513 | if (!pos) | |
514 | return (void *) 1; | |
515 | pos--; | |
516 | ||
517 | if (pos >= cell->vl_naddrs) | |
518 | return NULL; | |
519 | ||
520 | return &cell->vl_addrs[pos]; | |
ec26815a | 521 | } |
1da177e4 | 522 | |
1da177e4 LT |
523 | /* |
524 | * move to next cell in cells list | |
525 | */ | |
526 | static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | |
527 | loff_t *_pos) | |
528 | { | |
529 | struct afs_cell *cell = p->private; | |
530 | loff_t pos; | |
531 | ||
532 | _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos); | |
533 | ||
534 | pos = *_pos; | |
535 | (*_pos)++; | |
536 | if (pos >= cell->vl_naddrs) | |
537 | return NULL; | |
538 | ||
539 | return &cell->vl_addrs[pos]; | |
ec26815a | 540 | } |
1da177e4 | 541 | |
1da177e4 LT |
542 | /* |
543 | * clean up after reading from the cells list | |
544 | */ | |
545 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) | |
546 | { | |
547 | struct afs_cell *cell = p->private; | |
548 | ||
549 | up_read(&cell->vl_sem); | |
ec26815a | 550 | } |
1da177e4 | 551 | |
1da177e4 LT |
552 | /* |
553 | * display a header line followed by a load of volume lines | |
554 | */ | |
555 | static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) | |
556 | { | |
557 | struct in_addr *addr = v; | |
558 | ||
559 | /* display header on line 1 */ | |
560 | if (v == (struct in_addr *) 1) { | |
561 | seq_puts(m, "ADDRESS\n"); | |
562 | return 0; | |
563 | } | |
564 | ||
565 | /* display one cell per line on subsequent lines */ | |
be859405 | 566 | seq_printf(m, "%pI4\n", &addr->s_addr); |
1da177e4 | 567 | return 0; |
ec26815a | 568 | } |
1da177e4 | 569 | |
1da177e4 LT |
570 | /* |
571 | * open "/proc/fs/afs/<cell>/servers" which provides a summary of active | |
572 | * servers | |
573 | */ | |
574 | static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) | |
575 | { | |
576 | struct afs_cell *cell; | |
577 | struct seq_file *m; | |
578 | int ret; | |
579 | ||
d9dda78b | 580 | cell = PDE_DATA(inode); |
1da177e4 LT |
581 | if (!cell) |
582 | return -ENOENT; | |
583 | ||
584 | ret = seq_open(file, &afs_proc_cell_servers_ops); | |
585 | if (ret < 0) | |
586 | return ret; | |
587 | ||
588 | m = file->private_data; | |
589 | m->private = cell; | |
1da177e4 | 590 | return 0; |
ec26815a | 591 | } |
1da177e4 | 592 | |
1da177e4 LT |
593 | /* |
594 | * set up the iterator to start reading from the cells list and return the | |
595 | * first item | |
596 | */ | |
597 | static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) | |
08e0e7c8 | 598 | __acquires(m->private->servers_lock) |
1da177e4 | 599 | { |
1da177e4 | 600 | struct afs_cell *cell = m->private; |
1da177e4 LT |
601 | |
602 | _enter("cell=%p pos=%Ld", cell, *_pos); | |
603 | ||
604 | /* lock the list against modification */ | |
08e0e7c8 | 605 | read_lock(&cell->servers_lock); |
a6a8bd6d | 606 | return seq_list_start_head(&cell->servers, *_pos); |
ec26815a | 607 | } |
1da177e4 | 608 | |
1da177e4 LT |
609 | /* |
610 | * move to next cell in cells list | |
611 | */ | |
612 | static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, | |
613 | loff_t *_pos) | |
614 | { | |
1da177e4 LT |
615 | struct afs_cell *cell = p->private; |
616 | ||
617 | _enter("cell=%p pos=%Ld", cell, *_pos); | |
a6a8bd6d | 618 | return seq_list_next(v, &cell->servers, _pos); |
ec26815a | 619 | } |
1da177e4 | 620 | |
1da177e4 LT |
621 | /* |
622 | * clean up after reading from the cells list | |
623 | */ | |
624 | static void afs_proc_cell_servers_stop(struct seq_file *p, void *v) | |
08e0e7c8 | 625 | __releases(p->private->servers_lock) |
1da177e4 LT |
626 | { |
627 | struct afs_cell *cell = p->private; | |
628 | ||
08e0e7c8 | 629 | read_unlock(&cell->servers_lock); |
ec26815a | 630 | } |
1da177e4 | 631 | |
1da177e4 LT |
632 | /* |
633 | * display a header line followed by a load of volume lines | |
634 | */ | |
635 | static int afs_proc_cell_servers_show(struct seq_file *m, void *v) | |
636 | { | |
a6a8bd6d | 637 | struct afs_cell *cell = m->private; |
1da177e4 LT |
638 | struct afs_server *server = list_entry(v, struct afs_server, link); |
639 | char ipaddr[20]; | |
640 | ||
641 | /* display header on line 1 */ | |
a6a8bd6d | 642 | if (v == &cell->servers) { |
1da177e4 LT |
643 | seq_puts(m, "USE ADDR STATE\n"); |
644 | return 0; | |
645 | } | |
646 | ||
647 | /* display one cell per line on subsequent lines */ | |
be859405 | 648 | sprintf(ipaddr, "%pI4", &server->addr); |
1da177e4 | 649 | seq_printf(m, "%3d %-15.15s %5d\n", |
ec26815a | 650 | atomic_read(&server->usage), ipaddr, server->fs_state); |
1da177e4 LT |
651 | |
652 | return 0; | |
ec26815a | 653 | } |