Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  This file contains functions assisting in mapping VFS to 9P2000
0004  *
0005  *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
0006  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/module.h>
0012 #include <linux/errno.h>
0013 #include <linux/fs.h>
0014 #include <linux/sched.h>
0015 #include <linux/cred.h>
0016 #include <linux/parser.h>
0017 #include <linux/idr.h>
0018 #include <linux/slab.h>
0019 #include <linux/seq_file.h>
0020 #include <net/9p/9p.h>
0021 #include <net/9p/client.h>
0022 #include <net/9p/transport.h>
0023 #include "v9fs.h"
0024 #include "v9fs_vfs.h"
0025 #include "cache.h"
0026 
0027 static DEFINE_SPINLOCK(v9fs_sessionlist_lock);
0028 static LIST_HEAD(v9fs_sessionlist);
0029 struct kmem_cache *v9fs_inode_cache;
0030 
0031 /*
0032  * Option Parsing (code inspired by NFS code)
0033  *  NOTE: each transport will parse its own options
0034  */
0035 
0036 enum {
0037     /* Options that take integer arguments */
0038     Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
0039     /* String options */
0040     Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag,
0041     /* Options that take no arguments */
0042     Opt_nodevmap,
0043     /* Cache options */
0044     Opt_cache_loose, Opt_fscache, Opt_mmap,
0045     /* Access options */
0046     Opt_access, Opt_posixacl,
0047     /* Lock timeout option */
0048     Opt_locktimeout,
0049     /* Error token */
0050     Opt_err
0051 };
0052 
0053 static const match_table_t tokens = {
0054     {Opt_debug, "debug=%x"},
0055     {Opt_dfltuid, "dfltuid=%u"},
0056     {Opt_dfltgid, "dfltgid=%u"},
0057     {Opt_afid, "afid=%u"},
0058     {Opt_uname, "uname=%s"},
0059     {Opt_remotename, "aname=%s"},
0060     {Opt_nodevmap, "nodevmap"},
0061     {Opt_cache, "cache=%s"},
0062     {Opt_cache_loose, "loose"},
0063     {Opt_fscache, "fscache"},
0064     {Opt_mmap, "mmap"},
0065     {Opt_cachetag, "cachetag=%s"},
0066     {Opt_access, "access=%s"},
0067     {Opt_posixacl, "posixacl"},
0068     {Opt_locktimeout, "locktimeout=%u"},
0069     {Opt_err, NULL}
0070 };
0071 
0072 static const char *const v9fs_cache_modes[nr__p9_cache_modes] = {
0073     [CACHE_NONE]    = "none",
0074     [CACHE_MMAP]    = "mmap",
0075     [CACHE_LOOSE]   = "loose",
0076     [CACHE_FSCACHE] = "fscache",
0077 };
0078 
0079 /* Interpret mount options for cache mode */
0080 static int get_cache_mode(char *s)
0081 {
0082     int version = -EINVAL;
0083 
0084     if (!strcmp(s, "loose")) {
0085         version = CACHE_LOOSE;
0086         p9_debug(P9_DEBUG_9P, "Cache mode: loose\n");
0087     } else if (!strcmp(s, "fscache")) {
0088         version = CACHE_FSCACHE;
0089         p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
0090     } else if (!strcmp(s, "mmap")) {
0091         version = CACHE_MMAP;
0092         p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
0093     } else if (!strcmp(s, "none")) {
0094         version = CACHE_NONE;
0095         p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
0096     } else
0097         pr_info("Unknown Cache mode %s\n", s);
0098     return version;
0099 }
0100 
0101 /*
0102  * Display the mount options in /proc/mounts.
0103  */
0104 int v9fs_show_options(struct seq_file *m, struct dentry *root)
0105 {
0106     struct v9fs_session_info *v9ses = root->d_sb->s_fs_info;
0107 
0108     if (v9ses->debug)
0109         seq_printf(m, ",debug=%x", v9ses->debug);
0110     if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID))
0111         seq_printf(m, ",dfltuid=%u",
0112                from_kuid_munged(&init_user_ns, v9ses->dfltuid));
0113     if (!gid_eq(v9ses->dfltgid, V9FS_DEFGID))
0114         seq_printf(m, ",dfltgid=%u",
0115                from_kgid_munged(&init_user_ns, v9ses->dfltgid));
0116     if (v9ses->afid != ~0)
0117         seq_printf(m, ",afid=%u", v9ses->afid);
0118     if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
0119         seq_printf(m, ",uname=%s", v9ses->uname);
0120     if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
0121         seq_printf(m, ",aname=%s", v9ses->aname);
0122     if (v9ses->nodev)
0123         seq_puts(m, ",nodevmap");
0124     if (v9ses->cache)
0125         seq_printf(m, ",%s", v9fs_cache_modes[v9ses->cache]);
0126 #ifdef CONFIG_9P_FSCACHE
0127     if (v9ses->cachetag && v9ses->cache == CACHE_FSCACHE)
0128         seq_printf(m, ",cachetag=%s", v9ses->cachetag);
0129 #endif
0130 
0131     switch (v9ses->flags & V9FS_ACCESS_MASK) {
0132     case V9FS_ACCESS_USER:
0133         seq_puts(m, ",access=user");
0134         break;
0135     case V9FS_ACCESS_ANY:
0136         seq_puts(m, ",access=any");
0137         break;
0138     case V9FS_ACCESS_CLIENT:
0139         seq_puts(m, ",access=client");
0140         break;
0141     case V9FS_ACCESS_SINGLE:
0142         seq_printf(m, ",access=%u",
0143                from_kuid_munged(&init_user_ns, v9ses->uid));
0144         break;
0145     }
0146 
0147     if (v9ses->flags & V9FS_POSIX_ACL)
0148         seq_puts(m, ",posixacl");
0149 
0150     return p9_show_client_options(m, v9ses->clnt);
0151 }
0152 
0153 /**
0154  * v9fs_parse_options - parse mount options into session structure
0155  * @v9ses: existing v9fs session information
0156  * @opts: The mount option string
0157  *
0158  * Return 0 upon success, -ERRNO upon failure.
0159  */
0160 
0161 static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
0162 {
0163     char *options, *tmp_options;
0164     substring_t args[MAX_OPT_ARGS];
0165     char *p;
0166     int option = 0;
0167     char *s;
0168     int ret = 0;
0169 
0170     /* setup defaults */
0171     v9ses->afid = ~0;
0172     v9ses->debug = 0;
0173     v9ses->cache = CACHE_NONE;
0174 #ifdef CONFIG_9P_FSCACHE
0175     v9ses->cachetag = NULL;
0176 #endif
0177     v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;
0178 
0179     if (!opts)
0180         return 0;
0181 
0182     tmp_options = kstrdup(opts, GFP_KERNEL);
0183     if (!tmp_options) {
0184         ret = -ENOMEM;
0185         goto fail_option_alloc;
0186     }
0187     options = tmp_options;
0188 
0189     while ((p = strsep(&options, ",")) != NULL) {
0190         int token, r;
0191 
0192         if (!*p)
0193             continue;
0194 
0195         token = match_token(p, tokens, args);
0196         switch (token) {
0197         case Opt_debug:
0198             r = match_int(&args[0], &option);
0199             if (r < 0) {
0200                 p9_debug(P9_DEBUG_ERROR,
0201                      "integer field, but no integer?\n");
0202                 ret = r;
0203             } else {
0204                 v9ses->debug = option;
0205 #ifdef CONFIG_NET_9P_DEBUG
0206                 p9_debug_level = option;
0207 #endif
0208             }
0209             break;
0210 
0211         case Opt_dfltuid:
0212             r = match_int(&args[0], &option);
0213             if (r < 0) {
0214                 p9_debug(P9_DEBUG_ERROR,
0215                      "integer field, but no integer?\n");
0216                 ret = r;
0217                 continue;
0218             }
0219             v9ses->dfltuid = make_kuid(current_user_ns(), option);
0220             if (!uid_valid(v9ses->dfltuid)) {
0221                 p9_debug(P9_DEBUG_ERROR,
0222                      "uid field, but not a uid?\n");
0223                 ret = -EINVAL;
0224             }
0225             break;
0226         case Opt_dfltgid:
0227             r = match_int(&args[0], &option);
0228             if (r < 0) {
0229                 p9_debug(P9_DEBUG_ERROR,
0230                      "integer field, but no integer?\n");
0231                 ret = r;
0232                 continue;
0233             }
0234             v9ses->dfltgid = make_kgid(current_user_ns(), option);
0235             if (!gid_valid(v9ses->dfltgid)) {
0236                 p9_debug(P9_DEBUG_ERROR,
0237                      "gid field, but not a gid?\n");
0238                 ret = -EINVAL;
0239             }
0240             break;
0241         case Opt_afid:
0242             r = match_int(&args[0], &option);
0243             if (r < 0) {
0244                 p9_debug(P9_DEBUG_ERROR,
0245                      "integer field, but no integer?\n");
0246                 ret = r;
0247             } else {
0248                 v9ses->afid = option;
0249             }
0250             break;
0251         case Opt_uname:
0252             kfree(v9ses->uname);
0253             v9ses->uname = match_strdup(&args[0]);
0254             if (!v9ses->uname) {
0255                 ret = -ENOMEM;
0256                 goto free_and_return;
0257             }
0258             break;
0259         case Opt_remotename:
0260             kfree(v9ses->aname);
0261             v9ses->aname = match_strdup(&args[0]);
0262             if (!v9ses->aname) {
0263                 ret = -ENOMEM;
0264                 goto free_and_return;
0265             }
0266             break;
0267         case Opt_nodevmap:
0268             v9ses->nodev = 1;
0269             break;
0270         case Opt_cache_loose:
0271             v9ses->cache = CACHE_LOOSE;
0272             break;
0273         case Opt_fscache:
0274             v9ses->cache = CACHE_FSCACHE;
0275             break;
0276         case Opt_mmap:
0277             v9ses->cache = CACHE_MMAP;
0278             break;
0279         case Opt_cachetag:
0280 #ifdef CONFIG_9P_FSCACHE
0281             kfree(v9ses->cachetag);
0282             v9ses->cachetag = match_strdup(&args[0]);
0283             if (!v9ses->cachetag) {
0284                 ret = -ENOMEM;
0285                 goto free_and_return;
0286             }
0287 #endif
0288             break;
0289         case Opt_cache:
0290             s = match_strdup(&args[0]);
0291             if (!s) {
0292                 ret = -ENOMEM;
0293                 p9_debug(P9_DEBUG_ERROR,
0294                      "problem allocating copy of cache arg\n");
0295                 goto free_and_return;
0296             }
0297             r = get_cache_mode(s);
0298             if (r < 0)
0299                 ret = r;
0300             else
0301                 v9ses->cache = r;
0302 
0303             kfree(s);
0304             break;
0305 
0306         case Opt_access:
0307             s = match_strdup(&args[0]);
0308             if (!s) {
0309                 ret = -ENOMEM;
0310                 p9_debug(P9_DEBUG_ERROR,
0311                      "problem allocating copy of access arg\n");
0312                 goto free_and_return;
0313             }
0314 
0315             v9ses->flags &= ~V9FS_ACCESS_MASK;
0316             if (strcmp(s, "user") == 0)
0317                 v9ses->flags |= V9FS_ACCESS_USER;
0318             else if (strcmp(s, "any") == 0)
0319                 v9ses->flags |= V9FS_ACCESS_ANY;
0320             else if (strcmp(s, "client") == 0) {
0321                 v9ses->flags |= V9FS_ACCESS_CLIENT;
0322             } else {
0323                 uid_t uid;
0324 
0325                 v9ses->flags |= V9FS_ACCESS_SINGLE;
0326                 r = kstrtouint(s, 10, &uid);
0327                 if (r) {
0328                     ret = r;
0329                     pr_info("Unknown access argument %s: %d\n",
0330                         s, r);
0331                     kfree(s);
0332                     continue;
0333                 }
0334                 v9ses->uid = make_kuid(current_user_ns(), uid);
0335                 if (!uid_valid(v9ses->uid)) {
0336                     ret = -EINVAL;
0337                     pr_info("Unknown uid %s\n", s);
0338                 }
0339             }
0340 
0341             kfree(s);
0342             break;
0343 
0344         case Opt_posixacl:
0345 #ifdef CONFIG_9P_FS_POSIX_ACL
0346             v9ses->flags |= V9FS_POSIX_ACL;
0347 #else
0348             p9_debug(P9_DEBUG_ERROR,
0349                  "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
0350 #endif
0351             break;
0352 
0353         case Opt_locktimeout:
0354             r = match_int(&args[0], &option);
0355             if (r < 0) {
0356                 p9_debug(P9_DEBUG_ERROR,
0357                      "integer field, but no integer?\n");
0358                 ret = r;
0359                 continue;
0360             }
0361             if (option < 1) {
0362                 p9_debug(P9_DEBUG_ERROR,
0363                      "locktimeout must be a greater than zero integer.\n");
0364                 ret = -EINVAL;
0365                 continue;
0366             }
0367             v9ses->session_lock_timeout = (long)option * HZ;
0368             break;
0369 
0370         default:
0371             continue;
0372         }
0373     }
0374 
0375 free_and_return:
0376     kfree(tmp_options);
0377 fail_option_alloc:
0378     return ret;
0379 }
0380 
0381 /**
0382  * v9fs_session_init - initialize session
0383  * @v9ses: session information structure
0384  * @dev_name: device being mounted
0385  * @data: options
0386  *
0387  */
0388 
0389 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
0390           const char *dev_name, char *data)
0391 {
0392     struct p9_fid *fid;
0393     int rc = -ENOMEM;
0394 
0395     v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
0396     if (!v9ses->uname)
0397         goto err_names;
0398 
0399     v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
0400     if (!v9ses->aname)
0401         goto err_names;
0402     init_rwsem(&v9ses->rename_sem);
0403 
0404     v9ses->uid = INVALID_UID;
0405     v9ses->dfltuid = V9FS_DEFUID;
0406     v9ses->dfltgid = V9FS_DEFGID;
0407 
0408     v9ses->clnt = p9_client_create(dev_name, data);
0409     if (IS_ERR(v9ses->clnt)) {
0410         rc = PTR_ERR(v9ses->clnt);
0411         p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
0412         goto err_names;
0413     }
0414 
0415     v9ses->flags = V9FS_ACCESS_USER;
0416 
0417     if (p9_is_proto_dotl(v9ses->clnt)) {
0418         v9ses->flags = V9FS_ACCESS_CLIENT;
0419         v9ses->flags |= V9FS_PROTO_2000L;
0420     } else if (p9_is_proto_dotu(v9ses->clnt)) {
0421         v9ses->flags |= V9FS_PROTO_2000U;
0422     }
0423 
0424     rc = v9fs_parse_options(v9ses, data);
0425     if (rc < 0)
0426         goto err_clnt;
0427 
0428     v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
0429 
0430     if (!v9fs_proto_dotl(v9ses) &&
0431         ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
0432         /*
0433          * We support ACCESS_CLIENT only for dotl.
0434          * Fall back to ACCESS_USER
0435          */
0436         v9ses->flags &= ~V9FS_ACCESS_MASK;
0437         v9ses->flags |= V9FS_ACCESS_USER;
0438     }
0439     /*FIXME !! */
0440     /* for legacy mode, fall back to V9FS_ACCESS_ANY */
0441     if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
0442         ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
0443 
0444         v9ses->flags &= ~V9FS_ACCESS_MASK;
0445         v9ses->flags |= V9FS_ACCESS_ANY;
0446         v9ses->uid = INVALID_UID;
0447     }
0448     if (!v9fs_proto_dotl(v9ses) ||
0449         !((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
0450         /*
0451          * We support ACL checks on clinet only if the protocol is
0452          * 9P2000.L and access is V9FS_ACCESS_CLIENT.
0453          */
0454         v9ses->flags &= ~V9FS_ACL_MASK;
0455     }
0456 
0457     fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, INVALID_UID,
0458                             v9ses->aname);
0459     if (IS_ERR(fid)) {
0460         rc = PTR_ERR(fid);
0461         p9_debug(P9_DEBUG_ERROR, "cannot attach\n");
0462         goto err_clnt;
0463     }
0464 
0465     if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
0466         fid->uid = v9ses->uid;
0467     else
0468         fid->uid = INVALID_UID;
0469 
0470 #ifdef CONFIG_9P_FSCACHE
0471     /* register the session for caching */
0472     if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
0473         rc = v9fs_cache_session_get_cookie(v9ses, dev_name);
0474         if (rc < 0)
0475             goto err_clnt;
0476     }
0477 #endif
0478     spin_lock(&v9fs_sessionlist_lock);
0479     list_add(&v9ses->slist, &v9fs_sessionlist);
0480     spin_unlock(&v9fs_sessionlist_lock);
0481 
0482     return fid;
0483 
0484 err_clnt:
0485 #ifdef CONFIG_9P_FSCACHE
0486     kfree(v9ses->cachetag);
0487 #endif
0488     p9_client_destroy(v9ses->clnt);
0489 err_names:
0490     kfree(v9ses->uname);
0491     kfree(v9ses->aname);
0492     return ERR_PTR(rc);
0493 }
0494 
0495 /**
0496  * v9fs_session_close - shutdown a session
0497  * @v9ses: session information structure
0498  *
0499  */
0500 
0501 void v9fs_session_close(struct v9fs_session_info *v9ses)
0502 {
0503     if (v9ses->clnt) {
0504         p9_client_destroy(v9ses->clnt);
0505         v9ses->clnt = NULL;
0506     }
0507 
0508 #ifdef CONFIG_9P_FSCACHE
0509     fscache_relinquish_volume(v9fs_session_cache(v9ses), NULL, false);
0510     kfree(v9ses->cachetag);
0511 #endif
0512     kfree(v9ses->uname);
0513     kfree(v9ses->aname);
0514 
0515     spin_lock(&v9fs_sessionlist_lock);
0516     list_del(&v9ses->slist);
0517     spin_unlock(&v9fs_sessionlist_lock);
0518 }
0519 
0520 /**
0521  * v9fs_session_cancel - terminate a session
0522  * @v9ses: session to terminate
0523  *
0524  * mark transport as disconnected and cancel all pending requests.
0525  */
0526 
0527 void v9fs_session_cancel(struct v9fs_session_info *v9ses)
0528 {
0529     p9_debug(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
0530     p9_client_disconnect(v9ses->clnt);
0531 }
0532 
0533 /**
0534  * v9fs_session_begin_cancel - Begin terminate of a session
0535  * @v9ses: session to terminate
0536  *
0537  * After this call we don't allow any request other than clunk.
0538  */
0539 
0540 void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses)
0541 {
0542     p9_debug(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses);
0543     p9_client_begin_disconnect(v9ses->clnt);
0544 }
0545 
0546 extern int v9fs_error_init(void);
0547 
0548 static struct kobject *v9fs_kobj;
0549 
0550 #ifdef CONFIG_9P_FSCACHE
0551 /*
0552  * List caches associated with a session
0553  */
0554 static ssize_t caches_show(struct kobject *kobj,
0555                struct kobj_attribute *attr,
0556                char *buf)
0557 {
0558     ssize_t n = 0, count = 0, limit = PAGE_SIZE;
0559     struct v9fs_session_info *v9ses;
0560 
0561     spin_lock(&v9fs_sessionlist_lock);
0562     list_for_each_entry(v9ses, &v9fs_sessionlist, slist) {
0563         if (v9ses->cachetag) {
0564             n = snprintf(buf, limit, "%s\n", v9ses->cachetag);
0565             if (n < 0) {
0566                 count = n;
0567                 break;
0568             }
0569 
0570             count += n;
0571             limit -= n;
0572         }
0573     }
0574 
0575     spin_unlock(&v9fs_sessionlist_lock);
0576     return count;
0577 }
0578 
0579 static struct kobj_attribute v9fs_attr_cache = __ATTR_RO(caches);
0580 #endif /* CONFIG_9P_FSCACHE */
0581 
0582 static struct attribute *v9fs_attrs[] = {
0583 #ifdef CONFIG_9P_FSCACHE
0584     &v9fs_attr_cache.attr,
0585 #endif
0586     NULL,
0587 };
0588 
0589 static const struct attribute_group v9fs_attr_group = {
0590     .attrs = v9fs_attrs,
0591 };
0592 
0593 /**
0594  * v9fs_sysfs_init - Initialize the v9fs sysfs interface
0595  *
0596  */
0597 
0598 static int __init v9fs_sysfs_init(void)
0599 {
0600     v9fs_kobj = kobject_create_and_add("9p", fs_kobj);
0601     if (!v9fs_kobj)
0602         return -ENOMEM;
0603 
0604     if (sysfs_create_group(v9fs_kobj, &v9fs_attr_group)) {
0605         kobject_put(v9fs_kobj);
0606         return -ENOMEM;
0607     }
0608 
0609     return 0;
0610 }
0611 
0612 /**
0613  * v9fs_sysfs_cleanup - Unregister the v9fs sysfs interface
0614  *
0615  */
0616 
0617 static void v9fs_sysfs_cleanup(void)
0618 {
0619     sysfs_remove_group(v9fs_kobj, &v9fs_attr_group);
0620     kobject_put(v9fs_kobj);
0621 }
0622 
0623 static void v9fs_inode_init_once(void *foo)
0624 {
0625     struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
0626 
0627     memset(&v9inode->qid, 0, sizeof(v9inode->qid));
0628     inode_init_once(&v9inode->netfs.inode);
0629 }
0630 
0631 /**
0632  * v9fs_init_inode_cache - initialize a cache for 9P
0633  * Returns 0 on success.
0634  */
0635 static int v9fs_init_inode_cache(void)
0636 {
0637     v9fs_inode_cache = kmem_cache_create("v9fs_inode_cache",
0638                       sizeof(struct v9fs_inode),
0639                       0, (SLAB_RECLAIM_ACCOUNT|
0640                           SLAB_MEM_SPREAD|SLAB_ACCOUNT),
0641                       v9fs_inode_init_once);
0642     if (!v9fs_inode_cache)
0643         return -ENOMEM;
0644 
0645     return 0;
0646 }
0647 
0648 /**
0649  * v9fs_destroy_inode_cache - destroy the cache of 9P inode
0650  *
0651  */
0652 static void v9fs_destroy_inode_cache(void)
0653 {
0654     /*
0655      * Make sure all delayed rcu free inodes are flushed before we
0656      * destroy cache.
0657      */
0658     rcu_barrier();
0659     kmem_cache_destroy(v9fs_inode_cache);
0660 }
0661 
0662 static int v9fs_cache_register(void)
0663 {
0664     int ret;
0665 
0666     ret = v9fs_init_inode_cache();
0667     if (ret < 0)
0668         return ret;
0669     return ret;
0670 }
0671 
0672 static void v9fs_cache_unregister(void)
0673 {
0674     v9fs_destroy_inode_cache();
0675 }
0676 
0677 /**
0678  * init_v9fs - Initialize module
0679  *
0680  */
0681 
0682 static int __init init_v9fs(void)
0683 {
0684     int err;
0685 
0686     pr_info("Installing v9fs 9p2000 file system support\n");
0687     /* TODO: Setup list of registered trasnport modules */
0688 
0689     err = v9fs_cache_register();
0690     if (err < 0) {
0691         pr_err("Failed to register v9fs for caching\n");
0692         return err;
0693     }
0694 
0695     err = v9fs_sysfs_init();
0696     if (err < 0) {
0697         pr_err("Failed to register with sysfs\n");
0698         goto out_cache;
0699     }
0700     err = register_filesystem(&v9fs_fs_type);
0701     if (err < 0) {
0702         pr_err("Failed to register filesystem\n");
0703         goto out_sysfs_cleanup;
0704     }
0705 
0706     return 0;
0707 
0708 out_sysfs_cleanup:
0709     v9fs_sysfs_cleanup();
0710 
0711 out_cache:
0712     v9fs_cache_unregister();
0713 
0714     return err;
0715 }
0716 
0717 /**
0718  * exit_v9fs - shutdown module
0719  *
0720  */
0721 
0722 static void __exit exit_v9fs(void)
0723 {
0724     v9fs_sysfs_cleanup();
0725     v9fs_cache_unregister();
0726     unregister_filesystem(&v9fs_fs_type);
0727 }
0728 
0729 module_init(init_v9fs)
0730 module_exit(exit_v9fs)
0731 
0732 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
0733 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
0734 MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
0735 MODULE_LICENSE("GPL");