root/fs/9p/v9fs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_cache_mode
  2. v9fs_show_options
  3. v9fs_parse_options
  4. v9fs_session_init
  5. v9fs_session_close
  6. v9fs_session_cancel
  7. v9fs_session_begin_cancel
  8. caches_show
  9. v9fs_sysfs_init
  10. v9fs_sysfs_cleanup
  11. v9fs_inode_init_once
  12. v9fs_init_inode_cache
  13. v9fs_destroy_inode_cache
  14. v9fs_cache_register
  15. v9fs_cache_unregister
  16. init_v9fs
  17. exit_v9fs

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

/* [<][>][^][v][top][bottom][index][help] */