File Index
Files and directories
Sign in
FILE

v9fs.c

File preview with syntax highlighting.

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