proc.c 18 KB

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