LCOV - code coverage report
Current view: top level - fs/9p - v9fs.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 20 297 6.7 %
Date: 2022-04-01 13:59:58 Functions: 3 13 23.1 %
Branches: 6 146 4.1 %

           Branch data     Line data    Source code
       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                 :          0 : static int get_cache_mode(char *s)
      83                 :            : {
      84                 :          0 :         int version = -EINVAL;
      85                 :            : 
      86         [ #  # ]:          0 :         if (!strcmp(s, "loose")) {
      87                 :            :                 version = CACHE_LOOSE;
      88                 :            :                 p9_debug(P9_DEBUG_9P, "Cache mode: loose\n");
      89         [ #  # ]:          0 :         } else if (!strcmp(s, "fscache")) {
      90                 :            :                 version = CACHE_FSCACHE;
      91                 :            :                 p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
      92         [ #  # ]:          0 :         } else if (!strcmp(s, "mmap")) {
      93                 :            :                 version = CACHE_MMAP;
      94                 :            :                 p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
      95         [ #  # ]:          0 :         } else if (!strcmp(s, "none")) {
      96                 :            :                 version = CACHE_NONE;
      97                 :            :                 p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
      98                 :            :         } else
      99                 :          0 :                 pr_info("Unknown Cache mode %s\n", s);
     100                 :          0 :         return version;
     101                 :            : }
     102                 :            : 
     103                 :            : /*
     104                 :            :  * Display the mount options in /proc/mounts.
     105                 :            :  */
     106                 :          0 : int v9fs_show_options(struct seq_file *m, struct dentry *root)
     107                 :            : {
     108                 :          0 :         struct v9fs_session_info *v9ses = root->d_sb->s_fs_info;
     109                 :            : 
     110         [ #  # ]:          0 :         if (v9ses->debug)
     111                 :          0 :                 seq_printf(m, ",debug=%x", v9ses->debug);
     112         [ #  # ]:          0 :         if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID))
     113         [ #  # ]:          0 :                 seq_printf(m, ",dfltuid=%u",
     114                 :            :                            from_kuid_munged(&init_user_ns, v9ses->dfltuid));
     115         [ #  # ]:          0 :         if (!gid_eq(v9ses->dfltgid, V9FS_DEFGID))
     116         [ #  # ]:          0 :                 seq_printf(m, ",dfltgid=%u",
     117                 :            :                            from_kgid_munged(&init_user_ns, v9ses->dfltgid));
     118         [ #  # ]:          0 :         if (v9ses->afid != ~0)
     119                 :          0 :                 seq_printf(m, ",afid=%u", v9ses->afid);
     120         [ #  # ]:          0 :         if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
     121                 :          0 :                 seq_printf(m, ",uname=%s", v9ses->uname);
     122         [ #  # ]:          0 :         if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
     123                 :          0 :                 seq_printf(m, ",aname=%s", v9ses->aname);
     124         [ #  # ]:          0 :         if (v9ses->nodev)
     125                 :          0 :                 seq_puts(m, ",nodevmap");
     126         [ #  # ]:          0 :         if (v9ses->cache)
     127                 :          0 :                 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   [ #  #  #  #  :          0 :         switch (v9ses->flags & V9FS_ACCESS_MASK) {
                      # ]
     134                 :          0 :         case V9FS_ACCESS_USER:
     135                 :          0 :                 seq_puts(m, ",access=user");
     136                 :          0 :                 break;
     137                 :          0 :         case V9FS_ACCESS_ANY:
     138                 :          0 :                 seq_puts(m, ",access=any");
     139                 :          0 :                 break;
     140                 :          0 :         case V9FS_ACCESS_CLIENT:
     141                 :          0 :                 seq_puts(m, ",access=client");
     142                 :          0 :                 break;
     143                 :          0 :         case V9FS_ACCESS_SINGLE:
     144         [ #  # ]:          0 :                 seq_printf(m, ",access=%u",
     145                 :            :                            from_kuid_munged(&init_user_ns, v9ses->uid));
     146                 :          0 :                 break;
     147                 :            :         }
     148                 :            : 
     149         [ #  # ]:          0 :         if (v9ses->flags & V9FS_POSIX_ACL)
     150                 :          0 :                 seq_puts(m, ",posixacl");
     151                 :            : 
     152                 :          0 :         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                 :          0 : static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
     163                 :            : {
     164                 :          0 :         char *options, *tmp_options;
     165                 :          0 :         substring_t args[MAX_OPT_ARGS];
     166                 :          0 :         char *p;
     167                 :          0 :         int option = 0;
     168                 :          0 :         char *s, *e;
     169                 :          0 :         int ret = 0;
     170                 :            : 
     171                 :            :         /* setup defaults */
     172                 :          0 :         v9ses->afid = ~0;
     173                 :          0 :         v9ses->debug = 0;
     174                 :          0 :         v9ses->cache = CACHE_NONE;
     175                 :            : #ifdef CONFIG_9P_FSCACHE
     176                 :            :         v9ses->cachetag = NULL;
     177                 :            : #endif
     178                 :          0 :         v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;
     179                 :            : 
     180         [ #  # ]:          0 :         if (!opts)
     181                 :            :                 return 0;
     182                 :            : 
     183                 :          0 :         tmp_options = kstrdup(opts, GFP_KERNEL);
     184         [ #  # ]:          0 :         if (!tmp_options) {
     185                 :          0 :                 ret = -ENOMEM;
     186                 :          0 :                 goto fail_option_alloc;
     187                 :            :         }
     188                 :          0 :         options = tmp_options;
     189                 :            : 
     190         [ #  # ]:          0 :         while ((p = strsep(&options, ",")) != NULL) {
     191                 :          0 :                 int token, r;
     192         [ #  # ]:          0 :                 if (!*p)
     193                 :          0 :                         continue;
     194                 :          0 :                 token = match_token(p, tokens, args);
     195   [ #  #  #  #  :          0 :                 switch (token) {
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     196                 :          0 :                 case Opt_debug:
     197                 :          0 :                         r = match_int(&args[0], &option);
     198         [ #  # ]:          0 :                         if (r < 0) {
     199                 :            :                                 p9_debug(P9_DEBUG_ERROR,
     200                 :            :                                          "integer field, but no integer?\n");
     201                 :            :                                 ret = r;
     202                 :            :                         } else {
     203                 :          0 :                                 v9ses->debug = option;
     204                 :            : #ifdef CONFIG_NET_9P_DEBUG
     205                 :            :                                 p9_debug_level = option;
     206                 :            : #endif
     207                 :            :                         }
     208                 :            :                         break;
     209                 :            : 
     210                 :          0 :                 case Opt_dfltuid:
     211                 :          0 :                         r = match_int(&args[0], &option);
     212         [ #  # ]:          0 :                         if (r < 0) {
     213                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     214                 :            :                                          "integer field, but no integer?\n");
     215                 :          0 :                                 ret = r;
     216                 :          0 :                                 continue;
     217                 :            :                         }
     218         [ #  # ]:          0 :                         v9ses->dfltuid = make_kuid(current_user_ns(), option);
     219         [ #  # ]:          0 :                         if (!uid_valid(v9ses->dfltuid)) {
     220                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     221                 :            :                                          "uid field, but not a uid?\n");
     222                 :          0 :                                 ret = -EINVAL;
     223                 :            :                         }
     224                 :            :                         break;
     225                 :          0 :                 case Opt_dfltgid:
     226                 :          0 :                         r = match_int(&args[0], &option);
     227         [ #  # ]:          0 :                         if (r < 0) {
     228                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     229                 :            :                                          "integer field, but no integer?\n");
     230                 :          0 :                                 ret = r;
     231                 :          0 :                                 continue;
     232                 :            :                         }
     233         [ #  # ]:          0 :                         v9ses->dfltgid = make_kgid(current_user_ns(), option);
     234         [ #  # ]:          0 :                         if (!gid_valid(v9ses->dfltgid)) {
     235                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     236                 :            :                                          "gid field, but not a gid?\n");
     237                 :          0 :                                 ret = -EINVAL;
     238                 :            :                         }
     239                 :            :                         break;
     240                 :          0 :                 case Opt_afid:
     241                 :          0 :                         r = match_int(&args[0], &option);
     242         [ #  # ]:          0 :                         if (r < 0) {
     243                 :            :                                 p9_debug(P9_DEBUG_ERROR,
     244                 :            :                                          "integer field, but no integer?\n");
     245                 :            :                                 ret = r;
     246                 :            :                         } else {
     247                 :          0 :                                 v9ses->afid = option;
     248                 :            :                         }
     249                 :            :                         break;
     250                 :          0 :                 case Opt_uname:
     251                 :          0 :                         kfree(v9ses->uname);
     252                 :          0 :                         v9ses->uname = match_strdup(&args[0]);
     253         [ #  # ]:          0 :                         if (!v9ses->uname) {
     254                 :          0 :                                 ret = -ENOMEM;
     255                 :          0 :                                 goto free_and_return;
     256                 :            :                         }
     257                 :            :                         break;
     258                 :          0 :                 case Opt_remotename:
     259                 :          0 :                         kfree(v9ses->aname);
     260                 :          0 :                         v9ses->aname = match_strdup(&args[0]);
     261         [ #  # ]:          0 :                         if (!v9ses->aname) {
     262                 :          0 :                                 ret = -ENOMEM;
     263                 :          0 :                                 goto free_and_return;
     264                 :            :                         }
     265                 :            :                         break;
     266                 :          0 :                 case Opt_nodevmap:
     267                 :          0 :                         v9ses->nodev = 1;
     268                 :          0 :                         break;
     269                 :          0 :                 case Opt_cache_loose:
     270                 :          0 :                         v9ses->cache = CACHE_LOOSE;
     271                 :          0 :                         break;
     272                 :          0 :                 case Opt_fscache:
     273                 :          0 :                         v9ses->cache = CACHE_FSCACHE;
     274                 :          0 :                         break;
     275                 :          0 :                 case Opt_mmap:
     276                 :          0 :                         v9ses->cache = CACHE_MMAP;
     277                 :          0 :                         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                 :          0 :                 case Opt_cache:
     289                 :          0 :                         s = match_strdup(&args[0]);
     290         [ #  # ]:          0 :                         if (!s) {
     291                 :          0 :                                 ret = -ENOMEM;
     292                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     293                 :            :                                          "problem allocating copy of cache arg\n");
     294                 :          0 :                                 goto free_and_return;
     295                 :            :                         }
     296                 :          0 :                         r = get_cache_mode(s);
     297         [ #  # ]:          0 :                         if (r < 0)
     298                 :            :                                 ret = r;
     299                 :            :                         else
     300                 :          0 :                                 v9ses->cache = r;
     301                 :            : 
     302                 :          0 :                         kfree(s);
     303                 :          0 :                         break;
     304                 :            : 
     305                 :          0 :                 case Opt_access:
     306                 :          0 :                         s = match_strdup(&args[0]);
     307         [ #  # ]:          0 :                         if (!s) {
     308                 :          0 :                                 ret = -ENOMEM;
     309                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     310                 :            :                                          "problem allocating copy of access arg\n");
     311                 :          0 :                                 goto free_and_return;
     312                 :            :                         }
     313                 :            : 
     314                 :          0 :                         v9ses->flags &= ~V9FS_ACCESS_MASK;
     315         [ #  # ]:          0 :                         if (strcmp(s, "user") == 0)
     316                 :          0 :                                 v9ses->flags |= V9FS_ACCESS_USER;
     317         [ #  # ]:          0 :                         else if (strcmp(s, "any") == 0)
     318                 :          0 :                                 v9ses->flags |= V9FS_ACCESS_ANY;
     319         [ #  # ]:          0 :                         else if (strcmp(s, "client") == 0) {
     320                 :          0 :                                 v9ses->flags |= V9FS_ACCESS_CLIENT;
     321                 :            :                         } else {
     322                 :          0 :                                 uid_t uid;
     323                 :          0 :                                 v9ses->flags |= V9FS_ACCESS_SINGLE;
     324                 :          0 :                                 uid = simple_strtoul(s, &e, 10);
     325         [ #  # ]:          0 :                                 if (*e != '\0') {
     326                 :          0 :                                         ret = -EINVAL;
     327                 :          0 :                                         pr_info("Unknown access argument %s\n",
     328                 :            :                                                 s);
     329                 :          0 :                                         kfree(s);
     330                 :          0 :                                         continue;
     331                 :            :                                 }
     332         [ #  # ]:          0 :                                 v9ses->uid = make_kuid(current_user_ns(), uid);
     333         [ #  # ]:          0 :                                 if (!uid_valid(v9ses->uid)) {
     334                 :          0 :                                         ret = -EINVAL;
     335                 :          0 :                                         pr_info("Unknown uid %s\n", s);
     336                 :            :                                 }
     337                 :            :                         }
     338                 :            : 
     339                 :          0 :                         kfree(s);
     340                 :          0 :                         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                 :          0 :                 case Opt_locktimeout:
     352                 :          0 :                         r = match_int(&args[0], &option);
     353         [ #  # ]:          0 :                         if (r < 0) {
     354                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     355                 :            :                                          "integer field, but no integer?\n");
     356                 :          0 :                                 ret = r;
     357                 :          0 :                                 continue;
     358                 :            :                         }
     359         [ #  # ]:          0 :                         if (option < 1) {
     360                 :          0 :                                 p9_debug(P9_DEBUG_ERROR,
     361                 :            :                                          "locktimeout must be a greater than zero integer.\n");
     362                 :          0 :                                 ret = -EINVAL;
     363                 :          0 :                                 continue;
     364                 :            :                         }
     365                 :          0 :                         v9ses->session_lock_timeout = (long)option * HZ;
     366                 :          0 :                         break;
     367                 :            : 
     368                 :          0 :                 default:
     369                 :          0 :                         continue;
     370                 :            :                 }
     371                 :            :         }
     372                 :            : 
     373                 :          0 : free_and_return:
     374                 :          0 :         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                 :          0 : struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
     388                 :            :                   const char *dev_name, char *data)
     389                 :            : {
     390                 :          0 :         struct p9_fid *fid;
     391                 :          0 :         int rc = -ENOMEM;
     392                 :            : 
     393                 :          0 :         v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
     394         [ #  # ]:          0 :         if (!v9ses->uname)
     395                 :          0 :                 goto err_names;
     396                 :            : 
     397                 :          0 :         v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
     398         [ #  # ]:          0 :         if (!v9ses->aname)
     399                 :          0 :                 goto err_names;
     400                 :          0 :         init_rwsem(&v9ses->rename_sem);
     401                 :            : 
     402                 :          0 :         v9ses->uid = INVALID_UID;
     403                 :          0 :         v9ses->dfltuid = V9FS_DEFUID;
     404                 :          0 :         v9ses->dfltgid = V9FS_DEFGID;
     405                 :            : 
     406                 :          0 :         v9ses->clnt = p9_client_create(dev_name, data);
     407         [ #  # ]:          0 :         if (IS_ERR(v9ses->clnt)) {
     408                 :          0 :                 rc = PTR_ERR(v9ses->clnt);
     409                 :          0 :                 p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
     410                 :          0 :                 goto err_names;
     411                 :            :         }
     412                 :            : 
     413                 :          0 :         v9ses->flags = V9FS_ACCESS_USER;
     414                 :            : 
     415         [ #  # ]:          0 :         if (p9_is_proto_dotl(v9ses->clnt)) {
     416                 :          0 :                 v9ses->flags = V9FS_ACCESS_CLIENT;
     417                 :          0 :                 v9ses->flags |= V9FS_PROTO_2000L;
     418         [ #  # ]:          0 :         } else if (p9_is_proto_dotu(v9ses->clnt)) {
     419                 :          0 :                 v9ses->flags |= V9FS_PROTO_2000U;
     420                 :            :         }
     421                 :            : 
     422                 :          0 :         rc = v9fs_parse_options(v9ses, data);
     423         [ #  # ]:          0 :         if (rc < 0)
     424                 :          0 :                 goto err_clnt;
     425                 :            : 
     426                 :          0 :         v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
     427                 :            : 
     428   [ #  #  #  # ]:          0 :         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                 :          0 :                 v9ses->flags &= ~V9FS_ACCESS_MASK;
     435                 :          0 :                 v9ses->flags |= V9FS_ACCESS_USER;
     436                 :            :         }
     437                 :            :         /*FIXME !! */
     438                 :            :         /* for legacy mode, fall back to V9FS_ACCESS_ANY */
     439   [ #  #  #  #  :          0 :         if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
                   #  # ]
     440                 :            :                 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
     441                 :            : 
     442                 :          0 :                 v9ses->flags &= ~V9FS_ACCESS_MASK;
     443                 :          0 :                 v9ses->flags |= V9FS_ACCESS_ANY;
     444                 :          0 :                 v9ses->uid = INVALID_UID;
     445                 :            :         }
     446   [ #  #  #  # ]:          0 :         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                 :          0 :                 v9ses->flags &= ~V9FS_ACL_MASK;
     453                 :            :         }
     454                 :            : 
     455                 :          0 :         fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, INVALID_UID,
     456                 :          0 :                                                         v9ses->aname);
     457         [ #  # ]:          0 :         if (IS_ERR(fid)) {
     458                 :          0 :                 rc = PTR_ERR(fid);
     459                 :          0 :                 p9_debug(P9_DEBUG_ERROR, "cannot attach\n");
     460                 :          0 :                 goto err_clnt;
     461                 :            :         }
     462                 :            : 
     463         [ #  # ]:          0 :         if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
     464                 :          0 :                 fid->uid = v9ses->uid;
     465                 :            :         else
     466                 :          0 :                 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                 :          0 :         spin_lock(&v9fs_sessionlist_lock);
     473                 :          0 :         list_add(&v9ses->slist, &v9fs_sessionlist);
     474                 :          0 :         spin_unlock(&v9fs_sessionlist_lock);
     475                 :            : 
     476                 :          0 :         return fid;
     477                 :            : 
     478                 :          0 : err_clnt:
     479                 :            : #ifdef CONFIG_9P_FSCACHE
     480                 :            :         kfree(v9ses->cachetag);
     481                 :            : #endif
     482                 :          0 :         p9_client_destroy(v9ses->clnt);
     483                 :          0 : err_names:
     484                 :          0 :         kfree(v9ses->uname);
     485                 :          0 :         kfree(v9ses->aname);
     486                 :          0 :         return ERR_PTR(rc);
     487                 :            : }
     488                 :            : 
     489                 :            : /**
     490                 :            :  * v9fs_session_close - shutdown a session
     491                 :            :  * @v9ses: session information structure
     492                 :            :  *
     493                 :            :  */
     494                 :            : 
     495                 :          0 : void v9fs_session_close(struct v9fs_session_info *v9ses)
     496                 :            : {
     497         [ #  # ]:          0 :         if (v9ses->clnt) {
     498                 :          0 :                 p9_client_destroy(v9ses->clnt);
     499                 :          0 :                 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                 :          0 :         kfree(v9ses->uname);
     509                 :          0 :         kfree(v9ses->aname);
     510                 :            : 
     511                 :          0 :         spin_lock(&v9fs_sessionlist_lock);
     512                 :          0 :         list_del(&v9ses->slist);
     513                 :          0 :         spin_unlock(&v9fs_sessionlist_lock);
     514                 :          0 : }
     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                 :          0 : void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
     524                 :          0 :         p9_debug(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
     525                 :          0 :         p9_client_disconnect(v9ses->clnt);
     526                 :          0 : }
     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                 :          0 : void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses)
     536                 :            : {
     537                 :          0 :         p9_debug(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses);
     538                 :          0 :         p9_client_begin_disconnect(v9ses->clnt);
     539                 :          0 : }
     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                 :         78 : static int __init v9fs_sysfs_init(void)
     597                 :            : {
     598                 :         78 :         v9fs_kobj = kobject_create_and_add("9p", fs_kobj);
     599         [ +  - ]:         78 :         if (!v9fs_kobj)
     600                 :            :                 return -ENOMEM;
     601                 :            : 
     602         [ -  + ]:         78 :         if (sysfs_create_group(v9fs_kobj, &v9fs_attr_group)) {
     603                 :          0 :                 kobject_put(v9fs_kobj);
     604                 :          0 :                 return -ENOMEM;
     605                 :            :         }
     606                 :            : 
     607                 :            :         return 0;
     608                 :            : }
     609                 :            : 
     610                 :            : /**
     611                 :            :  * v9fs_sysfs_cleanup - Unregister the v9fs sysfs interface
     612                 :            :  *
     613                 :            :  */
     614                 :            : 
     615                 :          0 : static void v9fs_sysfs_cleanup(void)
     616                 :            : {
     617                 :          0 :         sysfs_remove_group(v9fs_kobj, &v9fs_attr_group);
     618                 :          0 :         kobject_put(v9fs_kobj);
     619                 :          0 : }
     620                 :            : 
     621                 :          0 : static void v9fs_inode_init_once(void *foo)
     622                 :            : {
     623                 :          0 :         struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
     624                 :            : #ifdef CONFIG_9P_FSCACHE
     625                 :            :         v9inode->fscache = NULL;
     626                 :            : #endif
     627                 :          0 :         memset(&v9inode->qid, 0, sizeof(v9inode->qid));
     628                 :          0 :         inode_init_once(&v9inode->vfs_inode);
     629                 :          0 : }
     630                 :            : 
     631                 :            : /**
     632                 :            :  * v9fs_init_inode_cache - initialize a cache for 9P
     633                 :            :  * Returns 0 on success.
     634                 :            :  */
     635                 :         78 : static int v9fs_init_inode_cache(void)
     636                 :            : {
     637                 :         78 :         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         [ -  + ]:         78 :         if (!v9fs_inode_cache)
     643                 :          0 :                 return -ENOMEM;
     644                 :            : 
     645                 :            :         return 0;
     646                 :            : }
     647                 :            : 
     648                 :            : /**
     649                 :            :  * v9fs_destroy_inode_cache - destroy the cache of 9P inode
     650                 :            :  *
     651                 :            :  */
     652                 :          0 : 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                 :          0 :         rcu_barrier();
     659                 :          0 :         kmem_cache_destroy(v9fs_inode_cache);
     660                 :            : }
     661                 :            : 
     662                 :         78 : static int v9fs_cache_register(void)
     663                 :            : {
     664                 :         78 :         int ret;
     665                 :         78 :         ret = v9fs_init_inode_cache();
     666                 :         78 :         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                 :          0 : static void v9fs_cache_unregister(void)
     677                 :            : {
     678                 :          0 :         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                 :         78 : static int __init init_v9fs(void)
     690                 :            : {
     691                 :         78 :         int err;
     692                 :         78 :         pr_info("Installing v9fs 9p2000 file system support\n");
     693                 :            :         /* TODO: Setup list of registered trasnport modules */
     694                 :            : 
     695                 :         78 :         err = v9fs_cache_register();
     696         [ -  + ]:         78 :         if (err < 0) {
     697                 :          0 :                 pr_err("Failed to register v9fs for caching\n");
     698                 :          0 :                 return err;
     699                 :            :         }
     700                 :            : 
     701                 :         78 :         err = v9fs_sysfs_init();
     702         [ -  + ]:         78 :         if (err < 0) {
     703                 :          0 :                 pr_err("Failed to register with sysfs\n");
     704                 :          0 :                 goto out_cache;
     705                 :            :         }
     706                 :         78 :         err = register_filesystem(&v9fs_fs_type);
     707         [ -  + ]:         78 :         if (err < 0) {
     708                 :          0 :                 pr_err("Failed to register filesystem\n");
     709                 :          0 :                 goto out_sysfs_cleanup;
     710                 :            :         }
     711                 :            : 
     712                 :            :         return 0;
     713                 :            : 
     714                 :            : out_sysfs_cleanup:
     715                 :          0 :         v9fs_sysfs_cleanup();
     716                 :            : 
     717                 :          0 : out_cache:
     718                 :          0 :         v9fs_cache_unregister();
     719                 :            : 
     720                 :          0 :         return err;
     721                 :            : }
     722                 :            : 
     723                 :            : /**
     724                 :            :  * exit_v9fs - shutdown module
     725                 :            :  *
     726                 :            :  */
     727                 :            : 
     728                 :          0 : static void __exit exit_v9fs(void)
     729                 :            : {
     730                 :          0 :         v9fs_sysfs_cleanup();
     731                 :          0 :         v9fs_cache_unregister();
     732                 :          0 :         unregister_filesystem(&v9fs_fs_type);
     733                 :          0 : }
     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");

Generated by: LCOV version 1.14