| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * This file contains functions assisting in mapping VFS to 9P2000
- *
- * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #include <linux/module.h>
- #include <linux/errno.h>
- #include <linux/fs.h>
- #include <linux/sched.h>
- #include <linux/cred.h>
- #include <linux/fs_parser.h>
- #include <linux/fs_context.h>
- #include <linux/slab.h>
- #include <linux/seq_file.h>
- #include <net/9p/9p.h>
- #include <net/9p/client.h>
- #include <net/9p/transport.h>
- #include "v9fs.h"
- #include "v9fs_vfs.h"
- #include "cache.h"
- static DEFINE_SPINLOCK(v9fs_sessionlist_lock);
- static LIST_HEAD(v9fs_sessionlist);
- struct kmem_cache *v9fs_inode_cache;
- /*
- * Option Parsing (code inspired by NFS code)
- * NOTE: each transport will parse its own options
- */
- enum {
- /* Mount-point source, we need to handle this explicitly because
- * the code below accepts unknown args and the vfs layer only handles
- * source if we rejected it as EINVAL */
- Opt_source,
- /* Options that take integer arguments */
- Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
- /* String options */
- Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag,
- /* Options that take no arguments */
- Opt_nodevmap, Opt_noxattr, Opt_directio, Opt_ignoreqv,
- /* Access options */
- Opt_access, Opt_posixacl,
- /* Lock timeout option */
- Opt_locktimeout,
- /* Client options */
- Opt_msize, Opt_trans, Opt_legacy, Opt_version,
- /* fd transport options */
- /* Options that take integer arguments */
- Opt_rfdno, Opt_wfdno,
- /* Options that take no arguments */
- /* rdma transport options */
- /* Options that take integer arguments */
- Opt_rq_depth, Opt_sq_depth, Opt_timeout,
- /* Options for both fd and rdma transports */
- Opt_port, Opt_privport,
- };
- static const struct constant_table p9_versions[] = {
- { "9p2000", p9_proto_legacy },
- { "9p2000.u", p9_proto_2000u },
- { "9p2000.L", p9_proto_2000L },
- {}
- };
- /*
- * This structure contains all parameters used for the core code,
- * the client, and all the transports.
- */
- const struct fs_parameter_spec v9fs_param_spec[] = {
- fsparam_string ("source", Opt_source),
- fsparam_u32hex ("debug", Opt_debug),
- fsparam_uid ("dfltuid", Opt_dfltuid),
- fsparam_gid ("dfltgid", Opt_dfltgid),
- fsparam_u32 ("afid", Opt_afid),
- fsparam_string ("uname", Opt_uname),
- fsparam_string ("aname", Opt_remotename),
- fsparam_flag ("nodevmap", Opt_nodevmap),
- fsparam_flag ("noxattr", Opt_noxattr),
- fsparam_flag ("directio", Opt_directio),
- fsparam_flag ("ignoreqv", Opt_ignoreqv),
- fsparam_string ("cache", Opt_cache),
- fsparam_string ("cachetag", Opt_cachetag),
- fsparam_string ("access", Opt_access),
- fsparam_flag ("posixacl", Opt_posixacl),
- fsparam_u32 ("locktimeout", Opt_locktimeout),
- /* client options */
- fsparam_u32 ("msize", Opt_msize),
- fsparam_flag ("noextend", Opt_legacy),
- fsparam_string ("trans", Opt_trans),
- fsparam_enum ("version", Opt_version, p9_versions),
- /* fd transport options */
- fsparam_u32 ("rfdno", Opt_rfdno),
- fsparam_u32 ("wfdno", Opt_wfdno),
- /* rdma transport options */
- fsparam_u32 ("sq", Opt_sq_depth),
- fsparam_u32 ("rq", Opt_rq_depth),
- fsparam_u32 ("timeout", Opt_timeout),
- /* fd and rdma transprt options */
- fsparam_u32 ("port", Opt_port),
- fsparam_flag ("privport", Opt_privport),
- {}
- };
- /* Interpret mount options for cache mode */
- static int get_cache_mode(char *s)
- {
- int version = -EINVAL;
- if (!strcmp(s, "loose")) {
- version = CACHE_SC_LOOSE;
- p9_debug(P9_DEBUG_9P, "Cache mode: loose\n");
- } else if (!strcmp(s, "fscache")) {
- version = CACHE_SC_FSCACHE;
- p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
- } else if (!strcmp(s, "mmap")) {
- version = CACHE_SC_MMAP;
- p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
- } else if (!strcmp(s, "readahead")) {
- version = CACHE_SC_READAHEAD;
- p9_debug(P9_DEBUG_9P, "Cache mode: readahead\n");
- } else if (!strcmp(s, "none")) {
- version = CACHE_SC_NONE;
- p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
- } else if (kstrtoint(s, 0, &version) != 0) {
- version = -EINVAL;
- pr_info("Unknown Cache mode or invalid value %s\n", s);
- }
- return version;
- }
- /*
- * Display the mount options in /proc/mounts.
- */
- int v9fs_show_options(struct seq_file *m, struct dentry *root)
- {
- struct v9fs_session_info *v9ses = root->d_sb->s_fs_info;
- if (v9ses->debug)
- seq_printf(m, ",debug=%#x", v9ses->debug);
- if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID))
- seq_printf(m, ",dfltuid=%u",
- from_kuid_munged(&init_user_ns, v9ses->dfltuid));
- if (!gid_eq(v9ses->dfltgid, V9FS_DEFGID))
- seq_printf(m, ",dfltgid=%u",
- from_kgid_munged(&init_user_ns, v9ses->dfltgid));
- if (v9ses->afid != ~0)
- seq_printf(m, ",afid=%u", v9ses->afid);
- if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
- seq_printf(m, ",uname=%s", v9ses->uname);
- if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
- seq_printf(m, ",aname=%s", v9ses->aname);
- if (v9ses->nodev)
- seq_puts(m, ",nodevmap");
- if (v9ses->cache)
- seq_printf(m, ",cache=%#x", v9ses->cache);
- #ifdef CONFIG_9P_FSCACHE
- if (v9ses->cachetag && (v9ses->cache & CACHE_FSCACHE))
- seq_printf(m, ",cachetag=%s", v9ses->cachetag);
- #endif
- switch (v9ses->flags & V9FS_ACCESS_MASK) {
- case V9FS_ACCESS_USER:
- seq_puts(m, ",access=user");
- break;
- case V9FS_ACCESS_ANY:
- seq_puts(m, ",access=any");
- break;
- case V9FS_ACCESS_CLIENT:
- seq_puts(m, ",access=client");
- break;
- case V9FS_ACCESS_SINGLE:
- seq_printf(m, ",access=%u",
- from_kuid_munged(&init_user_ns, v9ses->uid));
- break;
- }
- if (v9ses->flags & V9FS_IGNORE_QV)
- seq_puts(m, ",ignoreqv");
- if (v9ses->flags & V9FS_DIRECT_IO)
- seq_puts(m, ",directio");
- if (v9ses->flags & V9FS_POSIX_ACL)
- seq_puts(m, ",posixacl");
- if (v9ses->flags & V9FS_NO_XATTR)
- seq_puts(m, ",noxattr");
- return p9_show_client_options(m, v9ses->clnt);
- }
- /**
- * v9fs_parse_param - parse a mount option into the filesystem context
- * @fc: the filesystem context
- * @param: the parameter to parse
- *
- * Return 0 upon success, -ERRNO upon failure.
- */
- int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
- {
- struct v9fs_context *ctx = fc->fs_private;
- struct fs_parse_result result;
- char *s;
- int r;
- int opt;
- struct p9_client_opts *clnt = &ctx->client_opts;
- struct p9_fd_opts *fd_opts = &ctx->fd_opts;
- struct p9_rdma_opts *rdma_opts = &ctx->rdma_opts;
- struct p9_session_opts *session_opts = &ctx->session_opts;
- opt = fs_parse(fc, v9fs_param_spec, param, &result);
- if (opt < 0) {
- /*
- * We might like to report bad mount options here, but
- * traditionally 9p has ignored unknown mount options
- */
- if (opt == -ENOPARAM)
- return 0;
- return opt;
- }
- switch (opt) {
- case Opt_source:
- if (fc->source) {
- pr_info("p9: multiple sources not supported\n");
- return -EINVAL;
- }
- fc->source = param->string;
- param->string = NULL;
- break;
- case Opt_debug:
- session_opts->debug = result.uint_32;
- #ifdef CONFIG_NET_9P_DEBUG
- p9_debug_level = result.uint_32;
- #endif
- break;
- case Opt_dfltuid:
- session_opts->dfltuid = result.uid;
- break;
- case Opt_dfltgid:
- session_opts->dfltgid = result.gid;
- break;
- case Opt_afid:
- session_opts->afid = result.uint_32;
- break;
- case Opt_uname:
- kfree(session_opts->uname);
- session_opts->uname = param->string;
- param->string = NULL;
- break;
- case Opt_remotename:
- kfree(session_opts->aname);
- session_opts->aname = param->string;
- param->string = NULL;
- break;
- case Opt_nodevmap:
- session_opts->nodev = 1;
- break;
- case Opt_noxattr:
- session_opts->flags |= V9FS_NO_XATTR;
- break;
- case Opt_directio:
- session_opts->flags |= V9FS_DIRECT_IO;
- break;
- case Opt_ignoreqv:
- session_opts->flags |= V9FS_IGNORE_QV;
- break;
- case Opt_cachetag:
- #ifdef CONFIG_9P_FSCACHE
- kfree(session_opts->cachetag);
- session_opts->cachetag = param->string;
- param->string = NULL;
- #endif
- break;
- case Opt_cache:
- r = get_cache_mode(param->string);
- if (r < 0)
- return r;
- session_opts->cache = r;
- break;
- case Opt_access:
- s = param->string;
- session_opts->flags &= ~V9FS_ACCESS_MASK;
- if (strcmp(s, "user") == 0) {
- session_opts->flags |= V9FS_ACCESS_USER;
- } else if (strcmp(s, "any") == 0) {
- session_opts->flags |= V9FS_ACCESS_ANY;
- } else if (strcmp(s, "client") == 0) {
- session_opts->flags |= V9FS_ACCESS_CLIENT;
- } else {
- uid_t uid;
- session_opts->flags |= V9FS_ACCESS_SINGLE;
- r = kstrtouint(s, 10, &uid);
- if (r) {
- pr_info("Unknown access argument %s: %d\n",
- param->string, r);
- return r;
- }
- session_opts->uid = make_kuid(current_user_ns(), uid);
- if (!uid_valid(session_opts->uid)) {
- pr_info("Unknown uid %s\n", s);
- return -EINVAL;
- }
- }
- break;
- case Opt_posixacl:
- #ifdef CONFIG_9P_FS_POSIX_ACL
- session_opts->flags |= V9FS_POSIX_ACL;
- #else
- p9_debug(P9_DEBUG_ERROR,
- "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
- #endif
- break;
- case Opt_locktimeout:
- if (result.uint_32 < 1) {
- p9_debug(P9_DEBUG_ERROR,
- "locktimeout must be a greater than zero integer.\n");
- return -EINVAL;
- }
- session_opts->session_lock_timeout = (long)result.uint_32 * HZ;
- break;
- /* Options for client */
- case Opt_msize:
- if (result.uint_32 < 4096) {
- p9_debug(P9_DEBUG_ERROR, "msize should be at least 4k\n");
- return -EINVAL;
- }
- if (result.uint_32 > INT_MAX) {
- p9_debug(P9_DEBUG_ERROR, "msize too big\n");
- return -EINVAL;
- }
- clnt->msize = result.uint_32;
- break;
- case Opt_trans:
- v9fs_put_trans(clnt->trans_mod);
- clnt->trans_mod = v9fs_get_trans_by_name(param->string);
- if (!clnt->trans_mod) {
- pr_info("Could not find request transport: %s\n",
- param->string);
- return -EINVAL;
- }
- break;
- case Opt_legacy:
- clnt->proto_version = p9_proto_legacy;
- break;
- case Opt_version:
- clnt->proto_version = result.uint_32;
- p9_debug(P9_DEBUG_9P, "Protocol version: %s\n", param->string);
- break;
- /* Options for fd transport */
- case Opt_rfdno:
- fd_opts->rfd = result.uint_32;
- break;
- case Opt_wfdno:
- fd_opts->wfd = result.uint_32;
- break;
- /* Options for rdma transport */
- case Opt_sq_depth:
- rdma_opts->sq_depth = result.uint_32;
- break;
- case Opt_rq_depth:
- rdma_opts->rq_depth = result.uint_32;
- break;
- case Opt_timeout:
- rdma_opts->timeout = result.uint_32;
- break;
- /* Options for both fd and rdma transports */
- case Opt_port:
- fd_opts->port = result.uint_32;
- rdma_opts->port = result.uint_32;
- break;
- case Opt_privport:
- fd_opts->privport = true;
- rdma_opts->port = true;
- break;
- }
- return 0;
- }
- static void v9fs_apply_options(struct v9fs_session_info *v9ses,
- struct fs_context *fc)
- {
- struct v9fs_context *ctx = fc->fs_private;
- v9ses->debug = ctx->session_opts.debug;
- v9ses->dfltuid = ctx->session_opts.dfltuid;
- v9ses->dfltgid = ctx->session_opts.dfltgid;
- v9ses->afid = ctx->session_opts.afid;
- v9ses->uname = ctx->session_opts.uname;
- ctx->session_opts.uname = NULL;
- v9ses->aname = ctx->session_opts.aname;
- ctx->session_opts.aname = NULL;
- v9ses->nodev = ctx->session_opts.nodev;
- /*
- * Note that we must |= flags here as session_init already
- * set basic flags. This adds in flags from parsed options.
- */
- v9ses->flags |= ctx->session_opts.flags;
- #ifdef CONFIG_9P_FSCACHE
- v9ses->cachetag = ctx->session_opts.cachetag;
- ctx->session_opts.cachetag = NULL;
- #endif
- v9ses->cache = ctx->session_opts.cache;
- v9ses->uid = ctx->session_opts.uid;
- v9ses->session_lock_timeout = ctx->session_opts.session_lock_timeout;
- }
- /**
- * v9fs_session_init - initialize session
- * @v9ses: session information structure
- * @fc: the filesystem mount context
- *
- */
- struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
- struct fs_context *fc)
- {
- struct p9_fid *fid;
- int rc = -ENOMEM;
- init_rwsem(&v9ses->rename_sem);
- v9ses->clnt = p9_client_create(fc);
- if (IS_ERR(v9ses->clnt)) {
- rc = PTR_ERR(v9ses->clnt);
- p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
- goto err_names;
- }
- /*
- * Initialize flags on the real v9ses. v9fs_apply_options below
- * will |= the additional flags from parsed options.
- */
- v9ses->flags = V9FS_ACCESS_USER;
- if (p9_is_proto_dotl(v9ses->clnt)) {
- v9ses->flags = V9FS_ACCESS_CLIENT;
- v9ses->flags |= V9FS_PROTO_2000L;
- } else if (p9_is_proto_dotu(v9ses->clnt)) {
- v9ses->flags |= V9FS_PROTO_2000U;
- }
- v9fs_apply_options(v9ses, fc);
- v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
- if (!v9fs_proto_dotl(v9ses) &&
- ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
- /*
- * We support ACCESS_CLIENT only for dotl.
- * Fall back to ACCESS_USER
- */
- v9ses->flags &= ~V9FS_ACCESS_MASK;
- v9ses->flags |= V9FS_ACCESS_USER;
- }
- /* FIXME: for legacy mode, fall back to V9FS_ACCESS_ANY */
- if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
- ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
- v9ses->flags &= ~V9FS_ACCESS_MASK;
- v9ses->flags |= V9FS_ACCESS_ANY;
- v9ses->uid = INVALID_UID;
- }
- if (!v9fs_proto_dotl(v9ses) ||
- !((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
- /*
- * We support ACL checks on client only if the protocol is
- * 9P2000.L and access is V9FS_ACCESS_CLIENT.
- */
- v9ses->flags &= ~V9FS_ACL_MASK;
- }
- fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, INVALID_UID,
- v9ses->aname);
- if (IS_ERR(fid)) {
- rc = PTR_ERR(fid);
- p9_debug(P9_DEBUG_ERROR, "cannot attach\n");
- goto err_clnt;
- }
- if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
- fid->uid = v9ses->uid;
- else
- fid->uid = INVALID_UID;
- #ifdef CONFIG_9P_FSCACHE
- /* register the session for caching */
- if (v9ses->cache & CACHE_FSCACHE) {
- rc = v9fs_cache_session_get_cookie(v9ses, fc->source);
- if (rc < 0)
- goto err_clnt;
- }
- #endif
- spin_lock(&v9fs_sessionlist_lock);
- list_add(&v9ses->slist, &v9fs_sessionlist);
- spin_unlock(&v9fs_sessionlist_lock);
- return fid;
- err_clnt:
- #ifdef CONFIG_9P_FSCACHE
- kfree(v9ses->cachetag);
- #endif
- p9_client_destroy(v9ses->clnt);
- err_names:
- kfree(v9ses->uname);
- kfree(v9ses->aname);
- return ERR_PTR(rc);
- }
- /**
- * v9fs_session_close - shutdown a session
- * @v9ses: session information structure
- *
- */
- void v9fs_session_close(struct v9fs_session_info *v9ses)
- {
- if (v9ses->clnt) {
- p9_client_destroy(v9ses->clnt);
- v9ses->clnt = NULL;
- }
- #ifdef CONFIG_9P_FSCACHE
- fscache_relinquish_volume(v9fs_session_cache(v9ses), NULL, false);
- kfree(v9ses->cachetag);
- #endif
- kfree(v9ses->uname);
- kfree(v9ses->aname);
- spin_lock(&v9fs_sessionlist_lock);
- list_del(&v9ses->slist);
- spin_unlock(&v9fs_sessionlist_lock);
- }
- /**
- * v9fs_session_cancel - terminate a session
- * @v9ses: session to terminate
- *
- * mark transport as disconnected and cancel all pending requests.
- */
- void v9fs_session_cancel(struct v9fs_session_info *v9ses)
- {
- p9_debug(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
- p9_client_disconnect(v9ses->clnt);
- }
- /**
- * v9fs_session_begin_cancel - Begin terminate of a session
- * @v9ses: session to terminate
- *
- * After this call we don't allow any request other than clunk.
- */
- void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses)
- {
- p9_debug(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses);
- p9_client_begin_disconnect(v9ses->clnt);
- }
- static struct kobject *v9fs_kobj;
- #ifdef CONFIG_9P_FSCACHE
- /*
- * List caches associated with a session
- */
- static ssize_t caches_show(struct kobject *kobj,
- struct kobj_attribute *attr,
- char *buf)
- {
- ssize_t n = 0, count = 0, limit = PAGE_SIZE;
- struct v9fs_session_info *v9ses;
- spin_lock(&v9fs_sessionlist_lock);
- list_for_each_entry(v9ses, &v9fs_sessionlist, slist) {
- if (v9ses->cachetag) {
- n = snprintf(buf + count, limit, "%s\n", v9ses->cachetag);
- if (n < 0) {
- count = n;
- break;
- }
- count += n;
- limit -= n;
- }
- }
- spin_unlock(&v9fs_sessionlist_lock);
- return count;
- }
- static struct kobj_attribute v9fs_attr_cache = __ATTR_RO(caches);
- #endif /* CONFIG_9P_FSCACHE */
- static struct attribute *v9fs_attrs[] = {
- #ifdef CONFIG_9P_FSCACHE
- &v9fs_attr_cache.attr,
- #endif
- NULL,
- };
- static const struct attribute_group v9fs_attr_group = {
- .attrs = v9fs_attrs,
- };
- /**
- * v9fs_sysfs_init - Initialize the v9fs sysfs interface
- *
- */
- static int __init v9fs_sysfs_init(void)
- {
- int ret;
- v9fs_kobj = kobject_create_and_add("9p", fs_kobj);
- if (!v9fs_kobj)
- return -ENOMEM;
- ret = sysfs_create_group(v9fs_kobj, &v9fs_attr_group);
- if (ret) {
- kobject_put(v9fs_kobj);
- return ret;
- }
- return 0;
- }
- /**
- * v9fs_sysfs_cleanup - Unregister the v9fs sysfs interface
- *
- */
- static void v9fs_sysfs_cleanup(void)
- {
- sysfs_remove_group(v9fs_kobj, &v9fs_attr_group);
- kobject_put(v9fs_kobj);
- }
- static void v9fs_inode_init_once(void *foo)
- {
- struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
- memset(&v9inode->qid, 0, sizeof(v9inode->qid));
- inode_init_once(&v9inode->netfs.inode);
- }
- /**
- * v9fs_init_inode_cache - initialize a cache for 9P
- * Returns 0 on success.
- */
- static int v9fs_init_inode_cache(void)
- {
- v9fs_inode_cache = kmem_cache_create("v9fs_inode_cache",
- sizeof(struct v9fs_inode),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_ACCOUNT),
- v9fs_inode_init_once);
- if (!v9fs_inode_cache)
- return -ENOMEM;
- return 0;
- }
- /**
- * v9fs_destroy_inode_cache - destroy the cache of 9P inode
- *
- */
- static void v9fs_destroy_inode_cache(void)
- {
- /*
- * Make sure all delayed rcu free inodes are flushed before we
- * destroy cache.
- */
- rcu_barrier();
- kmem_cache_destroy(v9fs_inode_cache);
- }
- /**
- * init_v9fs - Initialize module
- *
- */
- static int __init init_v9fs(void)
- {
- int err;
- pr_info("Installing v9fs 9p2000 file system support\n");
- /* TODO: Setup list of registered transport modules */
- err = v9fs_init_inode_cache();
- if (err < 0) {
- pr_err("Failed to register v9fs for caching\n");
- return err;
- }
- err = v9fs_sysfs_init();
- if (err < 0) {
- pr_err("Failed to register with sysfs\n");
- goto out_cache;
- }
- err = register_filesystem(&v9fs_fs_type);
- if (err < 0) {
- pr_err("Failed to register filesystem\n");
- goto out_sysfs_cleanup;
- }
- return 0;
- out_sysfs_cleanup:
- v9fs_sysfs_cleanup();
- out_cache:
- v9fs_destroy_inode_cache();
- return err;
- }
- /**
- * exit_v9fs - shutdown module
- *
- */
- static void __exit exit_v9fs(void)
- {
- v9fs_sysfs_cleanup();
- v9fs_destroy_inode_cache();
- unregister_filesystem(&v9fs_fs_type);
- }
- module_init(init_v9fs)
- module_exit(exit_v9fs)
- MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
- MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
- MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
- MODULE_DESCRIPTION("9P Client File System");
- MODULE_LICENSE("GPL");
|