v9fs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * This file contains functions assisting in mapping VFS to 9P2000
  4. *
  5. * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
  6. * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  7. */
  8. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9. #include <linux/module.h>
  10. #include <linux/errno.h>
  11. #include <linux/fs.h>
  12. #include <linux/sched.h>
  13. #include <linux/cred.h>
  14. #include <linux/fs_parser.h>
  15. #include <linux/fs_context.h>
  16. #include <linux/slab.h>
  17. #include <linux/seq_file.h>
  18. #include <net/9p/9p.h>
  19. #include <net/9p/client.h>
  20. #include <net/9p/transport.h>
  21. #include "v9fs.h"
  22. #include "v9fs_vfs.h"
  23. #include "cache.h"
  24. static DEFINE_SPINLOCK(v9fs_sessionlist_lock);
  25. static LIST_HEAD(v9fs_sessionlist);
  26. struct kmem_cache *v9fs_inode_cache;
  27. /*
  28. * Option Parsing (code inspired by NFS code)
  29. * NOTE: each transport will parse its own options
  30. */
  31. enum {
  32. /* Mount-point source, we need to handle this explicitly because
  33. * the code below accepts unknown args and the vfs layer only handles
  34. * source if we rejected it as EINVAL */
  35. Opt_source,
  36. /* Options that take integer arguments */
  37. Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
  38. /* String options */
  39. Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag,
  40. /* Options that take no arguments */
  41. Opt_nodevmap, Opt_noxattr, Opt_directio, Opt_ignoreqv,
  42. /* Access options */
  43. Opt_access, Opt_posixacl,
  44. /* Lock timeout option */
  45. Opt_locktimeout,
  46. /* Client options */
  47. Opt_msize, Opt_trans, Opt_legacy, Opt_version,
  48. /* fd transport options */
  49. /* Options that take integer arguments */
  50. Opt_rfdno, Opt_wfdno,
  51. /* Options that take no arguments */
  52. /* rdma transport options */
  53. /* Options that take integer arguments */
  54. Opt_rq_depth, Opt_sq_depth, Opt_timeout,
  55. /* Options for both fd and rdma transports */
  56. Opt_port, Opt_privport,
  57. };
  58. static const struct constant_table p9_versions[] = {
  59. { "9p2000", p9_proto_legacy },
  60. { "9p2000.u", p9_proto_2000u },
  61. { "9p2000.L", p9_proto_2000L },
  62. {}
  63. };
  64. /*
  65. * This structure contains all parameters used for the core code,
  66. * the client, and all the transports.
  67. */
  68. const struct fs_parameter_spec v9fs_param_spec[] = {
  69. fsparam_string ("source", Opt_source),
  70. fsparam_u32hex ("debug", Opt_debug),
  71. fsparam_uid ("dfltuid", Opt_dfltuid),
  72. fsparam_gid ("dfltgid", Opt_dfltgid),
  73. fsparam_u32 ("afid", Opt_afid),
  74. fsparam_string ("uname", Opt_uname),
  75. fsparam_string ("aname", Opt_remotename),
  76. fsparam_flag ("nodevmap", Opt_nodevmap),
  77. fsparam_flag ("noxattr", Opt_noxattr),
  78. fsparam_flag ("directio", Opt_directio),
  79. fsparam_flag ("ignoreqv", Opt_ignoreqv),
  80. fsparam_string ("cache", Opt_cache),
  81. fsparam_string ("cachetag", Opt_cachetag),
  82. fsparam_string ("access", Opt_access),
  83. fsparam_flag ("posixacl", Opt_posixacl),
  84. fsparam_u32 ("locktimeout", Opt_locktimeout),
  85. /* client options */
  86. fsparam_u32 ("msize", Opt_msize),
  87. fsparam_flag ("noextend", Opt_legacy),
  88. fsparam_string ("trans", Opt_trans),
  89. fsparam_enum ("version", Opt_version, p9_versions),
  90. /* fd transport options */
  91. fsparam_u32 ("rfdno", Opt_rfdno),
  92. fsparam_u32 ("wfdno", Opt_wfdno),
  93. /* rdma transport options */
  94. fsparam_u32 ("sq", Opt_sq_depth),
  95. fsparam_u32 ("rq", Opt_rq_depth),
  96. fsparam_u32 ("timeout", Opt_timeout),
  97. /* fd and rdma transprt options */
  98. fsparam_u32 ("port", Opt_port),
  99. fsparam_flag ("privport", Opt_privport),
  100. {}
  101. };
  102. /* Interpret mount options for cache mode */
  103. static int get_cache_mode(char *s)
  104. {
  105. int version = -EINVAL;
  106. if (!strcmp(s, "loose")) {
  107. version = CACHE_SC_LOOSE;
  108. p9_debug(P9_DEBUG_9P, "Cache mode: loose\n");
  109. } else if (!strcmp(s, "fscache")) {
  110. version = CACHE_SC_FSCACHE;
  111. p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
  112. } else if (!strcmp(s, "mmap")) {
  113. version = CACHE_SC_MMAP;
  114. p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
  115. } else if (!strcmp(s, "readahead")) {
  116. version = CACHE_SC_READAHEAD;
  117. p9_debug(P9_DEBUG_9P, "Cache mode: readahead\n");
  118. } else if (!strcmp(s, "none")) {
  119. version = CACHE_SC_NONE;
  120. p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
  121. } else if (kstrtoint(s, 0, &version) != 0) {
  122. version = -EINVAL;
  123. pr_info("Unknown Cache mode or invalid value %s\n", s);
  124. }
  125. return version;
  126. }
  127. /*
  128. * Display the mount options in /proc/mounts.
  129. */
  130. int v9fs_show_options(struct seq_file *m, struct dentry *root)
  131. {
  132. struct v9fs_session_info *v9ses = root->d_sb->s_fs_info;
  133. if (v9ses->debug)
  134. seq_printf(m, ",debug=%#x", v9ses->debug);
  135. if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID))
  136. seq_printf(m, ",dfltuid=%u",
  137. from_kuid_munged(&init_user_ns, v9ses->dfltuid));
  138. if (!gid_eq(v9ses->dfltgid, V9FS_DEFGID))
  139. seq_printf(m, ",dfltgid=%u",
  140. from_kgid_munged(&init_user_ns, v9ses->dfltgid));
  141. if (v9ses->afid != ~0)
  142. seq_printf(m, ",afid=%u", v9ses->afid);
  143. if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
  144. seq_printf(m, ",uname=%s", v9ses->uname);
  145. if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
  146. seq_printf(m, ",aname=%s", v9ses->aname);
  147. if (v9ses->nodev)
  148. seq_puts(m, ",nodevmap");
  149. if (v9ses->cache)
  150. seq_printf(m, ",cache=%#x", v9ses->cache);
  151. #ifdef CONFIG_9P_FSCACHE
  152. if (v9ses->cachetag && (v9ses->cache & CACHE_FSCACHE))
  153. seq_printf(m, ",cachetag=%s", v9ses->cachetag);
  154. #endif
  155. switch (v9ses->flags & V9FS_ACCESS_MASK) {
  156. case V9FS_ACCESS_USER:
  157. seq_puts(m, ",access=user");
  158. break;
  159. case V9FS_ACCESS_ANY:
  160. seq_puts(m, ",access=any");
  161. break;
  162. case V9FS_ACCESS_CLIENT:
  163. seq_puts(m, ",access=client");
  164. break;
  165. case V9FS_ACCESS_SINGLE:
  166. seq_printf(m, ",access=%u",
  167. from_kuid_munged(&init_user_ns, v9ses->uid));
  168. break;
  169. }
  170. if (v9ses->flags & V9FS_IGNORE_QV)
  171. seq_puts(m, ",ignoreqv");
  172. if (v9ses->flags & V9FS_DIRECT_IO)
  173. seq_puts(m, ",directio");
  174. if (v9ses->flags & V9FS_POSIX_ACL)
  175. seq_puts(m, ",posixacl");
  176. if (v9ses->flags & V9FS_NO_XATTR)
  177. seq_puts(m, ",noxattr");
  178. return p9_show_client_options(m, v9ses->clnt);
  179. }
  180. /**
  181. * v9fs_parse_param - parse a mount option into the filesystem context
  182. * @fc: the filesystem context
  183. * @param: the parameter to parse
  184. *
  185. * Return 0 upon success, -ERRNO upon failure.
  186. */
  187. int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
  188. {
  189. struct v9fs_context *ctx = fc->fs_private;
  190. struct fs_parse_result result;
  191. char *s;
  192. int r;
  193. int opt;
  194. struct p9_client_opts *clnt = &ctx->client_opts;
  195. struct p9_fd_opts *fd_opts = &ctx->fd_opts;
  196. struct p9_rdma_opts *rdma_opts = &ctx->rdma_opts;
  197. struct p9_session_opts *session_opts = &ctx->session_opts;
  198. opt = fs_parse(fc, v9fs_param_spec, param, &result);
  199. if (opt < 0) {
  200. /*
  201. * We might like to report bad mount options here, but
  202. * traditionally 9p has ignored unknown mount options
  203. */
  204. if (opt == -ENOPARAM)
  205. return 0;
  206. return opt;
  207. }
  208. switch (opt) {
  209. case Opt_source:
  210. if (fc->source) {
  211. pr_info("p9: multiple sources not supported\n");
  212. return -EINVAL;
  213. }
  214. fc->source = param->string;
  215. param->string = NULL;
  216. break;
  217. case Opt_debug:
  218. session_opts->debug = result.uint_32;
  219. #ifdef CONFIG_NET_9P_DEBUG
  220. p9_debug_level = result.uint_32;
  221. #endif
  222. break;
  223. case Opt_dfltuid:
  224. session_opts->dfltuid = result.uid;
  225. break;
  226. case Opt_dfltgid:
  227. session_opts->dfltgid = result.gid;
  228. break;
  229. case Opt_afid:
  230. session_opts->afid = result.uint_32;
  231. break;
  232. case Opt_uname:
  233. kfree(session_opts->uname);
  234. session_opts->uname = param->string;
  235. param->string = NULL;
  236. break;
  237. case Opt_remotename:
  238. kfree(session_opts->aname);
  239. session_opts->aname = param->string;
  240. param->string = NULL;
  241. break;
  242. case Opt_nodevmap:
  243. session_opts->nodev = 1;
  244. break;
  245. case Opt_noxattr:
  246. session_opts->flags |= V9FS_NO_XATTR;
  247. break;
  248. case Opt_directio:
  249. session_opts->flags |= V9FS_DIRECT_IO;
  250. break;
  251. case Opt_ignoreqv:
  252. session_opts->flags |= V9FS_IGNORE_QV;
  253. break;
  254. case Opt_cachetag:
  255. #ifdef CONFIG_9P_FSCACHE
  256. kfree(session_opts->cachetag);
  257. session_opts->cachetag = param->string;
  258. param->string = NULL;
  259. #endif
  260. break;
  261. case Opt_cache:
  262. r = get_cache_mode(param->string);
  263. if (r < 0)
  264. return r;
  265. session_opts->cache = r;
  266. break;
  267. case Opt_access:
  268. s = param->string;
  269. session_opts->flags &= ~V9FS_ACCESS_MASK;
  270. if (strcmp(s, "user") == 0) {
  271. session_opts->flags |= V9FS_ACCESS_USER;
  272. } else if (strcmp(s, "any") == 0) {
  273. session_opts->flags |= V9FS_ACCESS_ANY;
  274. } else if (strcmp(s, "client") == 0) {
  275. session_opts->flags |= V9FS_ACCESS_CLIENT;
  276. } else {
  277. uid_t uid;
  278. session_opts->flags |= V9FS_ACCESS_SINGLE;
  279. r = kstrtouint(s, 10, &uid);
  280. if (r) {
  281. pr_info("Unknown access argument %s: %d\n",
  282. param->string, r);
  283. return r;
  284. }
  285. session_opts->uid = make_kuid(current_user_ns(), uid);
  286. if (!uid_valid(session_opts->uid)) {
  287. pr_info("Unknown uid %s\n", s);
  288. return -EINVAL;
  289. }
  290. }
  291. break;
  292. case Opt_posixacl:
  293. #ifdef CONFIG_9P_FS_POSIX_ACL
  294. session_opts->flags |= V9FS_POSIX_ACL;
  295. #else
  296. p9_debug(P9_DEBUG_ERROR,
  297. "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
  298. #endif
  299. break;
  300. case Opt_locktimeout:
  301. if (result.uint_32 < 1) {
  302. p9_debug(P9_DEBUG_ERROR,
  303. "locktimeout must be a greater than zero integer.\n");
  304. return -EINVAL;
  305. }
  306. session_opts->session_lock_timeout = (long)result.uint_32 * HZ;
  307. break;
  308. /* Options for client */
  309. case Opt_msize:
  310. if (result.uint_32 < 4096) {
  311. p9_debug(P9_DEBUG_ERROR, "msize should be at least 4k\n");
  312. return -EINVAL;
  313. }
  314. if (result.uint_32 > INT_MAX) {
  315. p9_debug(P9_DEBUG_ERROR, "msize too big\n");
  316. return -EINVAL;
  317. }
  318. clnt->msize = result.uint_32;
  319. break;
  320. case Opt_trans:
  321. v9fs_put_trans(clnt->trans_mod);
  322. clnt->trans_mod = v9fs_get_trans_by_name(param->string);
  323. if (!clnt->trans_mod) {
  324. pr_info("Could not find request transport: %s\n",
  325. param->string);
  326. return -EINVAL;
  327. }
  328. break;
  329. case Opt_legacy:
  330. clnt->proto_version = p9_proto_legacy;
  331. break;
  332. case Opt_version:
  333. clnt->proto_version = result.uint_32;
  334. p9_debug(P9_DEBUG_9P, "Protocol version: %s\n", param->string);
  335. break;
  336. /* Options for fd transport */
  337. case Opt_rfdno:
  338. fd_opts->rfd = result.uint_32;
  339. break;
  340. case Opt_wfdno:
  341. fd_opts->wfd = result.uint_32;
  342. break;
  343. /* Options for rdma transport */
  344. case Opt_sq_depth:
  345. rdma_opts->sq_depth = result.uint_32;
  346. break;
  347. case Opt_rq_depth:
  348. rdma_opts->rq_depth = result.uint_32;
  349. break;
  350. case Opt_timeout:
  351. rdma_opts->timeout = result.uint_32;
  352. break;
  353. /* Options for both fd and rdma transports */
  354. case Opt_port:
  355. fd_opts->port = result.uint_32;
  356. rdma_opts->port = result.uint_32;
  357. break;
  358. case Opt_privport:
  359. fd_opts->privport = true;
  360. rdma_opts->port = true;
  361. break;
  362. }
  363. return 0;
  364. }
  365. static void v9fs_apply_options(struct v9fs_session_info *v9ses,
  366. struct fs_context *fc)
  367. {
  368. struct v9fs_context *ctx = fc->fs_private;
  369. v9ses->debug = ctx->session_opts.debug;
  370. v9ses->dfltuid = ctx->session_opts.dfltuid;
  371. v9ses->dfltgid = ctx->session_opts.dfltgid;
  372. v9ses->afid = ctx->session_opts.afid;
  373. v9ses->uname = ctx->session_opts.uname;
  374. ctx->session_opts.uname = NULL;
  375. v9ses->aname = ctx->session_opts.aname;
  376. ctx->session_opts.aname = NULL;
  377. v9ses->nodev = ctx->session_opts.nodev;
  378. /*
  379. * Note that we must |= flags here as session_init already
  380. * set basic flags. This adds in flags from parsed options.
  381. */
  382. v9ses->flags |= ctx->session_opts.flags;
  383. #ifdef CONFIG_9P_FSCACHE
  384. v9ses->cachetag = ctx->session_opts.cachetag;
  385. ctx->session_opts.cachetag = NULL;
  386. #endif
  387. v9ses->cache = ctx->session_opts.cache;
  388. v9ses->uid = ctx->session_opts.uid;
  389. v9ses->session_lock_timeout = ctx->session_opts.session_lock_timeout;
  390. }
  391. /**
  392. * v9fs_session_init - initialize session
  393. * @v9ses: session information structure
  394. * @fc: the filesystem mount context
  395. *
  396. */
  397. struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
  398. struct fs_context *fc)
  399. {
  400. struct p9_fid *fid;
  401. int rc = -ENOMEM;
  402. init_rwsem(&v9ses->rename_sem);
  403. v9ses->clnt = p9_client_create(fc);
  404. if (IS_ERR(v9ses->clnt)) {
  405. rc = PTR_ERR(v9ses->clnt);
  406. p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
  407. goto err_names;
  408. }
  409. /*
  410. * Initialize flags on the real v9ses. v9fs_apply_options below
  411. * will |= the additional flags from parsed options.
  412. */
  413. v9ses->flags = V9FS_ACCESS_USER;
  414. if (p9_is_proto_dotl(v9ses->clnt)) {
  415. v9ses->flags = V9FS_ACCESS_CLIENT;
  416. v9ses->flags |= V9FS_PROTO_2000L;
  417. } else if (p9_is_proto_dotu(v9ses->clnt)) {
  418. v9ses->flags |= V9FS_PROTO_2000U;
  419. }
  420. v9fs_apply_options(v9ses, fc);
  421. v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
  422. if (!v9fs_proto_dotl(v9ses) &&
  423. ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
  424. /*
  425. * We support ACCESS_CLIENT only for dotl.
  426. * Fall back to ACCESS_USER
  427. */
  428. v9ses->flags &= ~V9FS_ACCESS_MASK;
  429. v9ses->flags |= V9FS_ACCESS_USER;
  430. }
  431. /* FIXME: for legacy mode, fall back to V9FS_ACCESS_ANY */
  432. if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
  433. ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
  434. v9ses->flags &= ~V9FS_ACCESS_MASK;
  435. v9ses->flags |= V9FS_ACCESS_ANY;
  436. v9ses->uid = INVALID_UID;
  437. }
  438. if (!v9fs_proto_dotl(v9ses) ||
  439. !((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
  440. /*
  441. * We support ACL checks on client only if the protocol is
  442. * 9P2000.L and access is V9FS_ACCESS_CLIENT.
  443. */
  444. v9ses->flags &= ~V9FS_ACL_MASK;
  445. }
  446. fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, INVALID_UID,
  447. v9ses->aname);
  448. if (IS_ERR(fid)) {
  449. rc = PTR_ERR(fid);
  450. p9_debug(P9_DEBUG_ERROR, "cannot attach\n");
  451. goto err_clnt;
  452. }
  453. if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
  454. fid->uid = v9ses->uid;
  455. else
  456. fid->uid = INVALID_UID;
  457. #ifdef CONFIG_9P_FSCACHE
  458. /* register the session for caching */
  459. if (v9ses->cache & CACHE_FSCACHE) {
  460. rc = v9fs_cache_session_get_cookie(v9ses, fc->source);
  461. if (rc < 0)
  462. goto err_clnt;
  463. }
  464. #endif
  465. spin_lock(&v9fs_sessionlist_lock);
  466. list_add(&v9ses->slist, &v9fs_sessionlist);
  467. spin_unlock(&v9fs_sessionlist_lock);
  468. return fid;
  469. err_clnt:
  470. #ifdef CONFIG_9P_FSCACHE
  471. kfree(v9ses->cachetag);
  472. #endif
  473. p9_client_destroy(v9ses->clnt);
  474. err_names:
  475. kfree(v9ses->uname);
  476. kfree(v9ses->aname);
  477. return ERR_PTR(rc);
  478. }
  479. /**
  480. * v9fs_session_close - shutdown a session
  481. * @v9ses: session information structure
  482. *
  483. */
  484. void v9fs_session_close(struct v9fs_session_info *v9ses)
  485. {
  486. if (v9ses->clnt) {
  487. p9_client_destroy(v9ses->clnt);
  488. v9ses->clnt = NULL;
  489. }
  490. #ifdef CONFIG_9P_FSCACHE
  491. fscache_relinquish_volume(v9fs_session_cache(v9ses), NULL, false);
  492. kfree(v9ses->cachetag);
  493. #endif
  494. kfree(v9ses->uname);
  495. kfree(v9ses->aname);
  496. spin_lock(&v9fs_sessionlist_lock);
  497. list_del(&v9ses->slist);
  498. spin_unlock(&v9fs_sessionlist_lock);
  499. }
  500. /**
  501. * v9fs_session_cancel - terminate a session
  502. * @v9ses: session to terminate
  503. *
  504. * mark transport as disconnected and cancel all pending requests.
  505. */
  506. void v9fs_session_cancel(struct v9fs_session_info *v9ses)
  507. {
  508. p9_debug(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
  509. p9_client_disconnect(v9ses->clnt);
  510. }
  511. /**
  512. * v9fs_session_begin_cancel - Begin terminate of a session
  513. * @v9ses: session to terminate
  514. *
  515. * After this call we don't allow any request other than clunk.
  516. */
  517. void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses)
  518. {
  519. p9_debug(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses);
  520. p9_client_begin_disconnect(v9ses->clnt);
  521. }
  522. static struct kobject *v9fs_kobj;
  523. #ifdef CONFIG_9P_FSCACHE
  524. /*
  525. * List caches associated with a session
  526. */
  527. static ssize_t caches_show(struct kobject *kobj,
  528. struct kobj_attribute *attr,
  529. char *buf)
  530. {
  531. ssize_t n = 0, count = 0, limit = PAGE_SIZE;
  532. struct v9fs_session_info *v9ses;
  533. spin_lock(&v9fs_sessionlist_lock);
  534. list_for_each_entry(v9ses, &v9fs_sessionlist, slist) {
  535. if (v9ses->cachetag) {
  536. n = snprintf(buf + count, limit, "%s\n", v9ses->cachetag);
  537. if (n < 0) {
  538. count = n;
  539. break;
  540. }
  541. count += n;
  542. limit -= n;
  543. }
  544. }
  545. spin_unlock(&v9fs_sessionlist_lock);
  546. return count;
  547. }
  548. static struct kobj_attribute v9fs_attr_cache = __ATTR_RO(caches);
  549. #endif /* CONFIG_9P_FSCACHE */
  550. static struct attribute *v9fs_attrs[] = {
  551. #ifdef CONFIG_9P_FSCACHE
  552. &v9fs_attr_cache.attr,
  553. #endif
  554. NULL,
  555. };
  556. static const struct attribute_group v9fs_attr_group = {
  557. .attrs = v9fs_attrs,
  558. };
  559. /**
  560. * v9fs_sysfs_init - Initialize the v9fs sysfs interface
  561. *
  562. */
  563. static int __init v9fs_sysfs_init(void)
  564. {
  565. int ret;
  566. v9fs_kobj = kobject_create_and_add("9p", fs_kobj);
  567. if (!v9fs_kobj)
  568. return -ENOMEM;
  569. ret = sysfs_create_group(v9fs_kobj, &v9fs_attr_group);
  570. if (ret) {
  571. kobject_put(v9fs_kobj);
  572. return ret;
  573. }
  574. return 0;
  575. }
  576. /**
  577. * v9fs_sysfs_cleanup - Unregister the v9fs sysfs interface
  578. *
  579. */
  580. static void v9fs_sysfs_cleanup(void)
  581. {
  582. sysfs_remove_group(v9fs_kobj, &v9fs_attr_group);
  583. kobject_put(v9fs_kobj);
  584. }
  585. static void v9fs_inode_init_once(void *foo)
  586. {
  587. struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
  588. memset(&v9inode->qid, 0, sizeof(v9inode->qid));
  589. inode_init_once(&v9inode->netfs.inode);
  590. }
  591. /**
  592. * v9fs_init_inode_cache - initialize a cache for 9P
  593. * Returns 0 on success.
  594. */
  595. static int v9fs_init_inode_cache(void)
  596. {
  597. v9fs_inode_cache = kmem_cache_create("v9fs_inode_cache",
  598. sizeof(struct v9fs_inode),
  599. 0, (SLAB_RECLAIM_ACCOUNT|
  600. SLAB_ACCOUNT),
  601. v9fs_inode_init_once);
  602. if (!v9fs_inode_cache)
  603. return -ENOMEM;
  604. return 0;
  605. }
  606. /**
  607. * v9fs_destroy_inode_cache - destroy the cache of 9P inode
  608. *
  609. */
  610. static void v9fs_destroy_inode_cache(void)
  611. {
  612. /*
  613. * Make sure all delayed rcu free inodes are flushed before we
  614. * destroy cache.
  615. */
  616. rcu_barrier();
  617. kmem_cache_destroy(v9fs_inode_cache);
  618. }
  619. /**
  620. * init_v9fs - Initialize module
  621. *
  622. */
  623. static int __init init_v9fs(void)
  624. {
  625. int err;
  626. pr_info("Installing v9fs 9p2000 file system support\n");
  627. /* TODO: Setup list of registered transport modules */
  628. err = v9fs_init_inode_cache();
  629. if (err < 0) {
  630. pr_err("Failed to register v9fs for caching\n");
  631. return err;
  632. }
  633. err = v9fs_sysfs_init();
  634. if (err < 0) {
  635. pr_err("Failed to register with sysfs\n");
  636. goto out_cache;
  637. }
  638. err = register_filesystem(&v9fs_fs_type);
  639. if (err < 0) {
  640. pr_err("Failed to register filesystem\n");
  641. goto out_sysfs_cleanup;
  642. }
  643. return 0;
  644. out_sysfs_cleanup:
  645. v9fs_sysfs_cleanup();
  646. out_cache:
  647. v9fs_destroy_inode_cache();
  648. return err;
  649. }
  650. /**
  651. * exit_v9fs - shutdown module
  652. *
  653. */
  654. static void __exit exit_v9fs(void)
  655. {
  656. v9fs_sysfs_cleanup();
  657. v9fs_destroy_inode_cache();
  658. unregister_filesystem(&v9fs_fs_type);
  659. }
  660. module_init(init_v9fs)
  661. module_exit(exit_v9fs)
  662. MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
  663. MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
  664. MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
  665. MODULE_DESCRIPTION("9P Client File System");
  666. MODULE_LICENSE("GPL");