proc.c 21 KB

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