Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/9p/v9fs.c
50303 views
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 <[email protected]>
6
* Copyright (C) 2002 by Ron Minnich <[email protected]>
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
27
static DEFINE_SPINLOCK(v9fs_sessionlist_lock);
28
static LIST_HEAD(v9fs_sessionlist);
29
struct 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
36
enum {
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
68
static 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
*/
79
const 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 */
119
static 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
*/
148
int 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
*/
211
int 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
399
static 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
434
struct 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
519
err_clnt:
520
#ifdef CONFIG_9P_FSCACHE
521
kfree(v9ses->cachetag);
522
#endif
523
p9_client_destroy(v9ses->clnt);
524
err_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
536
void 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
562
void 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
575
void 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
581
static struct kobject *v9fs_kobj;
582
583
#ifdef CONFIG_9P_FSCACHE
584
/*
585
* List caches associated with a session
586
*/
587
static 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
612
static struct kobj_attribute v9fs_attr_cache = __ATTR_RO(caches);
613
#endif /* CONFIG_9P_FSCACHE */
614
615
static struct attribute *v9fs_attrs[] = {
616
#ifdef CONFIG_9P_FSCACHE
617
&v9fs_attr_cache.attr,
618
#endif
619
NULL,
620
};
621
622
static 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
631
static 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
653
static void v9fs_sysfs_cleanup(void)
654
{
655
sysfs_remove_group(v9fs_kobj, &v9fs_attr_group);
656
kobject_put(v9fs_kobj);
657
}
658
659
static 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
*/
671
static 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
*/
688
static 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
703
static 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
729
out_sysfs_cleanup:
730
v9fs_sysfs_cleanup();
731
732
out_cache:
733
v9fs_destroy_inode_cache();
734
735
return err;
736
}
737
738
/**
739
* exit_v9fs - shutdown module
740
*
741
*/
742
743
static void __exit exit_v9fs(void)
744
{
745
v9fs_sysfs_cleanup();
746
v9fs_destroy_inode_cache();
747
unregister_filesystem(&v9fs_fs_type);
748
}
749
750
module_init(init_v9fs)
751
module_exit(exit_v9fs)
752
753
MODULE_AUTHOR("Latchesar Ionkov <[email protected]>");
754
MODULE_AUTHOR("Eric Van Hensbergen <[email protected]>");
755
MODULE_AUTHOR("Ron Minnich <[email protected]>");
756
MODULE_DESCRIPTION("9P Client File System");
757
MODULE_LICENSE("GPL");
758
759