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