proc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  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 <linux/sched.h>
  16. #include <linux/uaccess.h>
  17. #include "internal.h"
  18. static inline struct afs_net *afs_seq2net(struct seq_file *m)
  19. {
  20. return afs_net(seq_file_net(m));
  21. }
  22. static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
  23. {
  24. return afs_net(seq_file_single_net(m));
  25. }
  26. /*
  27. * Display the list of cells known to the namespace.
  28. */
  29. static int afs_proc_cells_show(struct seq_file *m, void *v)
  30. {
  31. struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
  32. if (v == SEQ_START_TOKEN) {
  33. /* display header on line 1 */
  34. seq_puts(m, "USE NAME\n");
  35. return 0;
  36. }
  37. /* display one cell per line on subsequent lines */
  38. seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
  39. return 0;
  40. }
  41. static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
  42. __acquires(rcu)
  43. {
  44. rcu_read_lock();
  45. return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos);
  46. }
  47. static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
  48. {
  49. return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos);
  50. }
  51. static void afs_proc_cells_stop(struct seq_file *m, void *v)
  52. __releases(rcu)
  53. {
  54. rcu_read_unlock();
  55. }
  56. static const struct seq_operations afs_proc_cells_ops = {
  57. .start = afs_proc_cells_start,
  58. .next = afs_proc_cells_next,
  59. .stop = afs_proc_cells_stop,
  60. .show = afs_proc_cells_show,
  61. };
  62. /*
  63. * handle writes to /proc/fs/afs/cells
  64. * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
  65. */
  66. static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
  67. {
  68. struct seq_file *m = file->private_data;
  69. struct afs_net *net = afs_seq2net(m);
  70. char *name, *args;
  71. int ret;
  72. /* trim to first NL */
  73. name = memchr(buf, '\n', size);
  74. if (name)
  75. *name = 0;
  76. /* split into command, name and argslist */
  77. name = strchr(buf, ' ');
  78. if (!name)
  79. goto inval;
  80. do {
  81. *name++ = 0;
  82. } while(*name == ' ');
  83. if (!*name)
  84. goto inval;
  85. args = strchr(name, ' ');
  86. if (args) {
  87. do {
  88. *args++ = 0;
  89. } while(*args == ' ');
  90. if (!*args)
  91. goto inval;
  92. }
  93. /* determine command to perform */
  94. _debug("cmd=%s name=%s args=%s", buf, name, args);
  95. if (strcmp(buf, "add") == 0) {
  96. struct afs_cell *cell;
  97. cell = afs_lookup_cell(net, name, strlen(name), args, true);
  98. if (IS_ERR(cell)) {
  99. ret = PTR_ERR(cell);
  100. goto done;
  101. }
  102. if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
  103. afs_put_cell(net, cell);
  104. } else {
  105. goto inval;
  106. }
  107. ret = 0;
  108. done:
  109. _leave(" = %d", ret);
  110. return ret;
  111. inval:
  112. ret = -EINVAL;
  113. printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
  114. goto done;
  115. }
  116. /*
  117. * Display the name of the current workstation cell.
  118. */
  119. static int afs_proc_rootcell_show(struct seq_file *m, void *v)
  120. {
  121. struct afs_cell *cell;
  122. struct afs_net *net;
  123. net = afs_seq2net_single(m);
  124. if (rcu_access_pointer(net->ws_cell)) {
  125. rcu_read_lock();
  126. cell = rcu_dereference(net->ws_cell);
  127. if (cell)
  128. seq_printf(m, "%s\n", cell->name);
  129. rcu_read_unlock();
  130. }
  131. return 0;
  132. }
  133. /*
  134. * Set the current workstation cell and optionally supply its list of volume
  135. * location servers.
  136. *
  137. * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
  138. */
  139. static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
  140. {
  141. struct seq_file *m = file->private_data;
  142. struct afs_net *net = afs_seq2net_single(m);
  143. char *s;
  144. int ret;
  145. ret = -EINVAL;
  146. if (buf[0] == '.')
  147. goto out;
  148. if (memchr(buf, '/', size))
  149. goto out;
  150. /* trim to first NL */
  151. s = memchr(buf, '\n', size);
  152. if (s)
  153. *s = 0;
  154. /* determine command to perform */
  155. _debug("rootcell=%s", buf);
  156. ret = afs_cell_init(net, buf);
  157. out:
  158. _leave(" = %d", ret);
  159. return ret;
  160. }
  161. static const char afs_vol_types[3][3] = {
  162. [AFSVL_RWVOL] = "RW",
  163. [AFSVL_ROVOL] = "RO",
  164. [AFSVL_BACKVOL] = "BK",
  165. };
  166. /*
  167. * Display the list of volumes known to a cell.
  168. */
  169. static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
  170. {
  171. struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  172. struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
  173. /* Display header on line 1 */
  174. if (v == &cell->proc_volumes) {
  175. seq_puts(m, "USE VID TY\n");
  176. return 0;
  177. }
  178. seq_printf(m, "%3d %08x %s\n",
  179. atomic_read(&vol->usage), vol->vid,
  180. afs_vol_types[vol->type]);
  181. return 0;
  182. }
  183. static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
  184. __acquires(cell->proc_lock)
  185. {
  186. struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  187. read_lock(&cell->proc_lock);
  188. return seq_list_start_head(&cell->proc_volumes, *_pos);
  189. }
  190. static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
  191. loff_t *_pos)
  192. {
  193. struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  194. return seq_list_next(v, &cell->proc_volumes, _pos);
  195. }
  196. static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
  197. __releases(cell->proc_lock)
  198. {
  199. struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  200. read_unlock(&cell->proc_lock);
  201. }
  202. static const struct seq_operations afs_proc_cell_volumes_ops = {
  203. .start = afs_proc_cell_volumes_start,
  204. .next = afs_proc_cell_volumes_next,
  205. .stop = afs_proc_cell_volumes_stop,
  206. .show = afs_proc_cell_volumes_show,
  207. };
  208. /*
  209. * Display the list of Volume Location servers we're using for a cell.
  210. */
  211. static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
  212. {
  213. struct sockaddr_rxrpc *addr = v;
  214. /* display header on line 1 */
  215. if (v == (void *)1) {
  216. seq_puts(m, "ADDRESS\n");
  217. return 0;
  218. }
  219. /* display one cell per line on subsequent lines */
  220. seq_printf(m, "%pISp\n", &addr->transport);
  221. return 0;
  222. }
  223. static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
  224. __acquires(rcu)
  225. {
  226. struct afs_addr_list *alist;
  227. struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  228. loff_t pos = *_pos;
  229. rcu_read_lock();
  230. alist = rcu_dereference(cell->vl_addrs);
  231. /* allow for the header line */
  232. if (!pos)
  233. return (void *) 1;
  234. pos--;
  235. if (!alist || pos >= alist->nr_addrs)
  236. return NULL;
  237. return alist->addrs + pos;
  238. }
  239. static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
  240. loff_t *_pos)
  241. {
  242. struct afs_addr_list *alist;
  243. struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  244. loff_t pos;
  245. alist = rcu_dereference(cell->vl_addrs);
  246. pos = *_pos;
  247. (*_pos)++;
  248. if (!alist || pos >= alist->nr_addrs)
  249. return NULL;
  250. return alist->addrs + pos;
  251. }
  252. static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
  253. __releases(rcu)
  254. {
  255. rcu_read_unlock();
  256. }
  257. static const struct seq_operations afs_proc_cell_vlservers_ops = {
  258. .start = afs_proc_cell_vlservers_start,
  259. .next = afs_proc_cell_vlservers_next,
  260. .stop = afs_proc_cell_vlservers_stop,
  261. .show = afs_proc_cell_vlservers_show,
  262. };
  263. /*
  264. * Display the list of fileservers we're using within a namespace.
  265. */
  266. static int afs_proc_servers_show(struct seq_file *m, void *v)
  267. {
  268. struct afs_server *server;
  269. struct afs_addr_list *alist;
  270. int i;
  271. if (v == SEQ_START_TOKEN) {
  272. seq_puts(m, "UUID USE ADDR\n");
  273. return 0;
  274. }
  275. server = list_entry(v, struct afs_server, proc_link);
  276. alist = rcu_dereference(server->addresses);
  277. seq_printf(m, "%pU %3d %pISpc%s\n",
  278. &server->uuid,
  279. atomic_read(&server->usage),
  280. &alist->addrs[0].transport,
  281. alist->index == 0 ? "*" : "");
  282. for (i = 1; i < alist->nr_addrs; i++)
  283. seq_printf(m, " %pISpc%s\n",
  284. &alist->addrs[i].transport,
  285. alist->index == i ? "*" : "");
  286. return 0;
  287. }
  288. static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
  289. __acquires(rcu)
  290. {
  291. rcu_read_lock();
  292. return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
  293. }
  294. static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
  295. {
  296. return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
  297. }
  298. static void afs_proc_servers_stop(struct seq_file *m, void *v)
  299. __releases(rcu)
  300. {
  301. rcu_read_unlock();
  302. }
  303. static const struct seq_operations afs_proc_servers_ops = {
  304. .start = afs_proc_servers_start,
  305. .next = afs_proc_servers_next,
  306. .stop = afs_proc_servers_stop,
  307. .show = afs_proc_servers_show,
  308. };
  309. /*
  310. * Display the list of strings that may be substituted for the @sys pathname
  311. * macro.
  312. */
  313. static int afs_proc_sysname_show(struct seq_file *m, void *v)
  314. {
  315. struct afs_net *net = afs_seq2net(m);
  316. struct afs_sysnames *sysnames = net->sysnames;
  317. unsigned int i = (unsigned long)v - 1;
  318. if (i < sysnames->nr)
  319. seq_printf(m, "%s\n", sysnames->subs[i]);
  320. return 0;
  321. }
  322. static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
  323. __acquires(&net->sysnames_lock)
  324. {
  325. struct afs_net *net = afs_seq2net(m);
  326. struct afs_sysnames *names;
  327. read_lock(&net->sysnames_lock);
  328. names = net->sysnames;
  329. if (*pos >= names->nr)
  330. return NULL;
  331. return (void *)(unsigned long)(*pos + 1);
  332. }
  333. static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
  334. {
  335. struct afs_net *net = afs_seq2net(m);
  336. struct afs_sysnames *names = net->sysnames;
  337. *pos += 1;
  338. if (*pos >= names->nr)
  339. return NULL;
  340. return (void *)(unsigned long)(*pos + 1);
  341. }
  342. static void afs_proc_sysname_stop(struct seq_file *m, void *v)
  343. __releases(&net->sysnames_lock)
  344. {
  345. struct afs_net *net = afs_seq2net(m);
  346. read_unlock(&net->sysnames_lock);
  347. }
  348. static const struct seq_operations afs_proc_sysname_ops = {
  349. .start = afs_proc_sysname_start,
  350. .next = afs_proc_sysname_next,
  351. .stop = afs_proc_sysname_stop,
  352. .show = afs_proc_sysname_show,
  353. };
  354. /*
  355. * Allow the @sys substitution to be configured.
  356. */
  357. static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
  358. {
  359. struct afs_sysnames *sysnames, *kill;
  360. struct seq_file *m = file->private_data;
  361. struct afs_net *net = afs_seq2net(m);
  362. char *s, *p, *sub;
  363. int ret, len;
  364. sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
  365. if (!sysnames)
  366. return -ENOMEM;
  367. refcount_set(&sysnames->usage, 1);
  368. kill = sysnames;
  369. p = buf;
  370. while ((s = strsep(&p, " \t\n"))) {
  371. len = strlen(s);
  372. if (len == 0)
  373. continue;
  374. ret = -ENAMETOOLONG;
  375. if (len >= AFSNAMEMAX)
  376. goto error;
  377. if (len >= 4 &&
  378. s[len - 4] == '@' &&
  379. s[len - 3] == 's' &&
  380. s[len - 2] == 'y' &&
  381. s[len - 1] == 's')
  382. /* Protect against recursion */
  383. goto invalid;
  384. if (s[0] == '.' &&
  385. (len < 2 || (len == 2 && s[1] == '.')))
  386. goto invalid;
  387. if (memchr(s, '/', len))
  388. goto invalid;
  389. ret = -EFBIG;
  390. if (sysnames->nr >= AFS_NR_SYSNAME)
  391. goto out;
  392. if (strcmp(s, afs_init_sysname) == 0) {
  393. sub = (char *)afs_init_sysname;
  394. } else {
  395. ret = -ENOMEM;
  396. sub = kmemdup(s, len + 1, GFP_KERNEL);
  397. if (!sub)
  398. goto out;
  399. }
  400. sysnames->subs[sysnames->nr] = sub;
  401. sysnames->nr++;
  402. }
  403. if (sysnames->nr == 0) {
  404. sysnames->subs[0] = sysnames->blank;
  405. sysnames->nr++;
  406. }
  407. write_lock(&net->sysnames_lock);
  408. kill = net->sysnames;
  409. net->sysnames = sysnames;
  410. write_unlock(&net->sysnames_lock);
  411. ret = 0;
  412. out:
  413. afs_put_sysnames(kill);
  414. return ret;
  415. invalid:
  416. ret = -EINVAL;
  417. error:
  418. goto out;
  419. }
  420. void afs_put_sysnames(struct afs_sysnames *sysnames)
  421. {
  422. int i;
  423. if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
  424. for (i = 0; i < sysnames->nr; i++)
  425. if (sysnames->subs[i] != afs_init_sysname &&
  426. sysnames->subs[i] != sysnames->blank)
  427. kfree(sysnames->subs[i]);
  428. }
  429. }
  430. /*
  431. * Display general per-net namespace statistics
  432. */
  433. static int afs_proc_stats_show(struct seq_file *m, void *v)
  434. {
  435. struct afs_net *net = afs_seq2net_single(m);
  436. seq_puts(m, "kAFS statistics\n");
  437. seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
  438. atomic_read(&net->n_lookup),
  439. atomic_read(&net->n_reval),
  440. atomic_read(&net->n_inval),
  441. atomic_read(&net->n_relpg));
  442. seq_printf(m, "dir-data: rdpg=%u\n",
  443. atomic_read(&net->n_read_dir));
  444. seq_printf(m, "dir-edit: cr=%u rm=%u\n",
  445. atomic_read(&net->n_dir_cr),
  446. atomic_read(&net->n_dir_rm));
  447. seq_printf(m, "file-rd : n=%u nb=%lu\n",
  448. atomic_read(&net->n_fetches),
  449. atomic_long_read(&net->n_fetch_bytes));
  450. seq_printf(m, "file-wr : n=%u nb=%lu\n",
  451. atomic_read(&net->n_stores),
  452. atomic_long_read(&net->n_store_bytes));
  453. return 0;
  454. }
  455. /*
  456. * initialise /proc/fs/afs/<cell>/
  457. */
  458. int afs_proc_cell_setup(struct afs_cell *cell)
  459. {
  460. struct proc_dir_entry *dir;
  461. struct afs_net *net = cell->net;
  462. _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
  463. dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
  464. if (!dir)
  465. goto error_dir;
  466. if (!proc_create_net_data("vlservers", 0444, dir,
  467. &afs_proc_cell_vlservers_ops,
  468. sizeof(struct seq_net_private),
  469. cell) ||
  470. !proc_create_net_data("volumes", 0444, dir,
  471. &afs_proc_cell_volumes_ops,
  472. sizeof(struct seq_net_private),
  473. cell))
  474. goto error_tree;
  475. _leave(" = 0");
  476. return 0;
  477. error_tree:
  478. remove_proc_subtree(cell->name, net->proc_afs);
  479. error_dir:
  480. _leave(" = -ENOMEM");
  481. return -ENOMEM;
  482. }
  483. /*
  484. * remove /proc/fs/afs/<cell>/
  485. */
  486. void afs_proc_cell_remove(struct afs_cell *cell)
  487. {
  488. struct afs_net *net = cell->net;
  489. _enter("");
  490. remove_proc_subtree(cell->name, net->proc_afs);
  491. _leave("");
  492. }
  493. /*
  494. * initialise the /proc/fs/afs/ directory
  495. */
  496. int afs_proc_init(struct afs_net *net)
  497. {
  498. struct proc_dir_entry *p;
  499. _enter("");
  500. p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
  501. if (!p)
  502. goto error_dir;
  503. if (!proc_create_net_data_write("cells", 0644, p,
  504. &afs_proc_cells_ops,
  505. afs_proc_cells_write,
  506. sizeof(struct seq_net_private),
  507. NULL) ||
  508. !proc_create_net_single_write("rootcell", 0644, p,
  509. afs_proc_rootcell_show,
  510. afs_proc_rootcell_write,
  511. NULL) ||
  512. !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
  513. sizeof(struct seq_net_private)) ||
  514. !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
  515. !proc_create_net_data_write("sysname", 0644, p,
  516. &afs_proc_sysname_ops,
  517. afs_proc_sysname_write,
  518. sizeof(struct seq_net_private),
  519. NULL))
  520. goto error_tree;
  521. net->proc_afs = p;
  522. _leave(" = 0");
  523. return 0;
  524. error_tree:
  525. proc_remove(p);
  526. error_dir:
  527. _leave(" = -ENOMEM");
  528. return -ENOMEM;
  529. }
  530. /*
  531. * clean up the /proc/fs/afs/ directory
  532. */
  533. void afs_proc_cleanup(struct afs_net *net)
  534. {
  535. proc_remove(net->proc_afs);
  536. net->proc_afs = NULL;
  537. }