~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/9p/v9fs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php