Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/cell/spufs/inode.c
26498 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
/*
4
* SPU file system
5
*
6
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
7
*
8
* Author: Arnd Bergmann <[email protected]>
9
*/
10
11
#include <linux/file.h>
12
#include <linux/fs.h>
13
#include <linux/fs_context.h>
14
#include <linux/fs_parser.h>
15
#include <linux/fsnotify.h>
16
#include <linux/backing-dev.h>
17
#include <linux/init.h>
18
#include <linux/ioctl.h>
19
#include <linux/module.h>
20
#include <linux/mount.h>
21
#include <linux/namei.h>
22
#include <linux/pagemap.h>
23
#include <linux/poll.h>
24
#include <linux/of.h>
25
#include <linux/seq_file.h>
26
#include <linux/slab.h>
27
28
#include <asm/spu.h>
29
#include <asm/spu_priv1.h>
30
#include <linux/uaccess.h>
31
32
#include "spufs.h"
33
34
struct spufs_sb_info {
35
bool debug;
36
};
37
38
static struct kmem_cache *spufs_inode_cache;
39
char *isolated_loader;
40
static int isolated_loader_size;
41
42
static struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb)
43
{
44
return sb->s_fs_info;
45
}
46
47
static struct inode *
48
spufs_alloc_inode(struct super_block *sb)
49
{
50
struct spufs_inode_info *ei;
51
52
ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL);
53
if (!ei)
54
return NULL;
55
56
ei->i_gang = NULL;
57
ei->i_ctx = NULL;
58
ei->i_openers = 0;
59
60
return &ei->vfs_inode;
61
}
62
63
static void spufs_free_inode(struct inode *inode)
64
{
65
kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
66
}
67
68
static void
69
spufs_init_once(void *p)
70
{
71
struct spufs_inode_info *ei = p;
72
73
inode_init_once(&ei->vfs_inode);
74
}
75
76
static struct inode *
77
spufs_new_inode(struct super_block *sb, umode_t mode)
78
{
79
struct inode *inode;
80
81
inode = new_inode(sb);
82
if (!inode)
83
goto out;
84
85
inode->i_ino = get_next_ino();
86
inode->i_mode = mode;
87
inode->i_uid = current_fsuid();
88
inode->i_gid = current_fsgid();
89
simple_inode_init_ts(inode);
90
out:
91
return inode;
92
}
93
94
static int
95
spufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
96
struct iattr *attr)
97
{
98
struct inode *inode = d_inode(dentry);
99
100
if ((attr->ia_valid & ATTR_SIZE) &&
101
(attr->ia_size != inode->i_size))
102
return -EINVAL;
103
setattr_copy(&nop_mnt_idmap, inode, attr);
104
mark_inode_dirty(inode);
105
return 0;
106
}
107
108
109
static int
110
spufs_new_file(struct super_block *sb, struct dentry *dentry,
111
const struct file_operations *fops, umode_t mode,
112
size_t size, struct spu_context *ctx)
113
{
114
static const struct inode_operations spufs_file_iops = {
115
.setattr = spufs_setattr,
116
};
117
struct inode *inode;
118
int ret;
119
120
ret = -ENOSPC;
121
inode = spufs_new_inode(sb, S_IFREG | mode);
122
if (!inode)
123
goto out;
124
125
ret = 0;
126
inode->i_op = &spufs_file_iops;
127
inode->i_fop = fops;
128
inode->i_size = size;
129
inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
130
d_add(dentry, inode);
131
out:
132
return ret;
133
}
134
135
static void
136
spufs_evict_inode(struct inode *inode)
137
{
138
struct spufs_inode_info *ei = SPUFS_I(inode);
139
clear_inode(inode);
140
if (ei->i_ctx)
141
put_spu_context(ei->i_ctx);
142
if (ei->i_gang)
143
put_spu_gang(ei->i_gang);
144
}
145
146
/* Caller must hold parent->i_mutex */
147
static void spufs_rmdir(struct inode *parent, struct dentry *dir)
148
{
149
struct spu_context *ctx = SPUFS_I(d_inode(dir))->i_ctx;
150
151
locked_recursive_removal(dir, NULL);
152
spu_forget(ctx);
153
}
154
155
static int spufs_fill_dir(struct dentry *dir,
156
const struct spufs_tree_descr *files, umode_t mode,
157
struct spu_context *ctx)
158
{
159
while (files->name && files->name[0]) {
160
int ret;
161
struct dentry *dentry = d_alloc_name(dir, files->name);
162
if (!dentry)
163
return -ENOMEM;
164
ret = spufs_new_file(dir->d_sb, dentry, files->ops,
165
files->mode & mode, files->size, ctx);
166
if (ret) {
167
dput(dentry);
168
return ret;
169
}
170
files++;
171
}
172
return 0;
173
}
174
175
static void unuse_gang(struct dentry *dir)
176
{
177
struct inode *inode = dir->d_inode;
178
struct spu_gang *gang = SPUFS_I(inode)->i_gang;
179
180
if (gang) {
181
bool dead;
182
183
inode_lock(inode); // exclusion with spufs_create_context()
184
dead = !--gang->alive;
185
inode_unlock(inode);
186
187
if (dead)
188
simple_recursive_removal(dir, NULL);
189
}
190
}
191
192
static int spufs_dir_close(struct inode *inode, struct file *file)
193
{
194
struct inode *parent;
195
struct dentry *dir;
196
197
dir = file->f_path.dentry;
198
parent = d_inode(dir->d_parent);
199
200
inode_lock_nested(parent, I_MUTEX_PARENT);
201
spufs_rmdir(parent, dir);
202
inode_unlock(parent);
203
204
unuse_gang(dir->d_parent);
205
return dcache_dir_close(inode, file);
206
}
207
208
const struct file_operations spufs_context_fops = {
209
.open = dcache_dir_open,
210
.release = spufs_dir_close,
211
.llseek = dcache_dir_lseek,
212
.read = generic_read_dir,
213
.iterate_shared = dcache_readdir,
214
.fsync = noop_fsync,
215
};
216
EXPORT_SYMBOL_GPL(spufs_context_fops);
217
218
static int
219
spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
220
umode_t mode)
221
{
222
int ret;
223
struct inode *inode;
224
struct spu_context *ctx;
225
226
inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
227
if (!inode)
228
return -ENOSPC;
229
230
inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR);
231
ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
232
SPUFS_I(inode)->i_ctx = ctx;
233
if (!ctx) {
234
iput(inode);
235
return -ENOSPC;
236
}
237
238
ctx->flags = flags;
239
inode->i_op = &simple_dir_inode_operations;
240
inode->i_fop = &simple_dir_operations;
241
242
inode_lock(inode);
243
244
dget(dentry);
245
inc_nlink(dir);
246
inc_nlink(inode);
247
248
d_instantiate(dentry, inode);
249
250
if (flags & SPU_CREATE_NOSCHED)
251
ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
252
mode, ctx);
253
else
254
ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
255
256
if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
257
ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
258
mode, ctx);
259
260
inode_unlock(inode);
261
262
if (ret)
263
spufs_rmdir(dir, dentry);
264
265
return ret;
266
}
267
268
static int spufs_context_open(const struct path *path)
269
{
270
int ret;
271
struct file *filp;
272
273
ret = get_unused_fd_flags(0);
274
if (ret < 0)
275
return ret;
276
277
filp = dentry_open(path, O_RDONLY, current_cred());
278
if (IS_ERR(filp)) {
279
put_unused_fd(ret);
280
return PTR_ERR(filp);
281
}
282
283
filp->f_op = &spufs_context_fops;
284
fd_install(ret, filp);
285
return ret;
286
}
287
288
static struct spu_context *
289
spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
290
struct file *filp)
291
{
292
struct spu_context *tmp, *neighbor, *err;
293
int count, node;
294
int aff_supp;
295
296
aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
297
struct spu, cbe_list))->aff_list);
298
299
if (!aff_supp)
300
return ERR_PTR(-EINVAL);
301
302
if (flags & SPU_CREATE_GANG)
303
return ERR_PTR(-EINVAL);
304
305
if (flags & SPU_CREATE_AFFINITY_MEM &&
306
gang->aff_ref_ctx &&
307
gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
308
return ERR_PTR(-EEXIST);
309
310
if (gang->aff_flags & AFF_MERGED)
311
return ERR_PTR(-EBUSY);
312
313
neighbor = NULL;
314
if (flags & SPU_CREATE_AFFINITY_SPU) {
315
if (!filp || filp->f_op != &spufs_context_fops)
316
return ERR_PTR(-EINVAL);
317
318
neighbor = get_spu_context(
319
SPUFS_I(file_inode(filp))->i_ctx);
320
321
if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
322
!list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
323
!list_entry(neighbor->aff_list.next, struct spu_context,
324
aff_list)->aff_head) {
325
err = ERR_PTR(-EEXIST);
326
goto out_put_neighbor;
327
}
328
329
if (gang != neighbor->gang) {
330
err = ERR_PTR(-EINVAL);
331
goto out_put_neighbor;
332
}
333
334
count = 1;
335
list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
336
count++;
337
if (list_empty(&neighbor->aff_list))
338
count++;
339
340
for (node = 0; node < MAX_NUMNODES; node++) {
341
if ((cbe_spu_info[node].n_spus - atomic_read(
342
&cbe_spu_info[node].reserved_spus)) >= count)
343
break;
344
}
345
346
if (node == MAX_NUMNODES) {
347
err = ERR_PTR(-EEXIST);
348
goto out_put_neighbor;
349
}
350
}
351
352
return neighbor;
353
354
out_put_neighbor:
355
put_spu_context(neighbor);
356
return err;
357
}
358
359
static void
360
spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
361
struct spu_context *neighbor)
362
{
363
if (flags & SPU_CREATE_AFFINITY_MEM)
364
ctx->gang->aff_ref_ctx = ctx;
365
366
if (flags & SPU_CREATE_AFFINITY_SPU) {
367
if (list_empty(&neighbor->aff_list)) {
368
list_add_tail(&neighbor->aff_list,
369
&ctx->gang->aff_list_head);
370
neighbor->aff_head = 1;
371
}
372
373
if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
374
|| list_entry(neighbor->aff_list.next, struct spu_context,
375
aff_list)->aff_head) {
376
list_add(&ctx->aff_list, &neighbor->aff_list);
377
} else {
378
list_add_tail(&ctx->aff_list, &neighbor->aff_list);
379
if (neighbor->aff_head) {
380
neighbor->aff_head = 0;
381
ctx->aff_head = 1;
382
}
383
}
384
385
if (!ctx->gang->aff_ref_ctx)
386
ctx->gang->aff_ref_ctx = ctx;
387
}
388
}
389
390
static int
391
spufs_create_context(struct inode *inode, struct dentry *dentry,
392
struct vfsmount *mnt, int flags, umode_t mode,
393
struct file *aff_filp)
394
{
395
int ret;
396
int affinity;
397
struct spu_gang *gang = SPUFS_I(inode)->i_gang;
398
struct spu_context *neighbor;
399
struct path path = {.mnt = mnt, .dentry = dentry};
400
401
if ((flags & SPU_CREATE_NOSCHED) &&
402
!capable(CAP_SYS_NICE))
403
return -EPERM;
404
405
if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
406
== SPU_CREATE_ISOLATE)
407
return -EINVAL;
408
409
if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
410
return -ENODEV;
411
412
if (gang) {
413
if (!gang->alive)
414
return -ENOENT;
415
gang->alive++;
416
}
417
418
neighbor = NULL;
419
affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
420
if (affinity) {
421
if (!gang)
422
return -EINVAL;
423
mutex_lock(&gang->aff_mutex);
424
neighbor = spufs_assert_affinity(flags, gang, aff_filp);
425
if (IS_ERR(neighbor)) {
426
ret = PTR_ERR(neighbor);
427
goto out_aff_unlock;
428
}
429
}
430
431
ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
432
if (ret) {
433
if (neighbor)
434
put_spu_context(neighbor);
435
goto out_aff_unlock;
436
}
437
438
if (affinity) {
439
spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx,
440
neighbor);
441
if (neighbor)
442
put_spu_context(neighbor);
443
}
444
445
ret = spufs_context_open(&path);
446
if (ret < 0)
447
spufs_rmdir(inode, dentry);
448
449
out_aff_unlock:
450
if (affinity)
451
mutex_unlock(&gang->aff_mutex);
452
if (ret && gang)
453
gang->alive--; // can't reach 0
454
return ret;
455
}
456
457
static int
458
spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
459
{
460
int ret;
461
struct inode *inode;
462
struct spu_gang *gang;
463
464
ret = -ENOSPC;
465
inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
466
if (!inode)
467
goto out;
468
469
ret = 0;
470
inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR);
471
gang = alloc_spu_gang();
472
SPUFS_I(inode)->i_ctx = NULL;
473
SPUFS_I(inode)->i_gang = gang;
474
if (!gang) {
475
ret = -ENOMEM;
476
goto out_iput;
477
}
478
479
inode->i_op = &simple_dir_inode_operations;
480
inode->i_fop = &simple_dir_operations;
481
482
d_instantiate(dentry, inode);
483
dget(dentry);
484
inc_nlink(dir);
485
inc_nlink(d_inode(dentry));
486
return ret;
487
488
out_iput:
489
iput(inode);
490
out:
491
return ret;
492
}
493
494
static int spufs_gang_close(struct inode *inode, struct file *file)
495
{
496
unuse_gang(file->f_path.dentry);
497
return dcache_dir_close(inode, file);
498
}
499
500
static const struct file_operations spufs_gang_fops = {
501
.open = dcache_dir_open,
502
.release = spufs_gang_close,
503
.llseek = dcache_dir_lseek,
504
.read = generic_read_dir,
505
.iterate_shared = dcache_readdir,
506
.fsync = noop_fsync,
507
};
508
509
static int spufs_gang_open(const struct path *path)
510
{
511
int ret;
512
struct file *filp;
513
514
ret = get_unused_fd_flags(0);
515
if (ret < 0)
516
return ret;
517
518
/*
519
* get references for dget and mntget, will be released
520
* in error path of *_open().
521
*/
522
filp = dentry_open(path, O_RDONLY, current_cred());
523
if (IS_ERR(filp)) {
524
put_unused_fd(ret);
525
return PTR_ERR(filp);
526
}
527
528
filp->f_op = &spufs_gang_fops;
529
fd_install(ret, filp);
530
return ret;
531
}
532
533
static int spufs_create_gang(struct inode *inode,
534
struct dentry *dentry,
535
struct vfsmount *mnt, umode_t mode)
536
{
537
struct path path = {.mnt = mnt, .dentry = dentry};
538
int ret;
539
540
ret = spufs_mkgang(inode, dentry, mode & 0777);
541
if (!ret) {
542
ret = spufs_gang_open(&path);
543
if (ret < 0)
544
unuse_gang(dentry);
545
}
546
return ret;
547
}
548
549
550
static struct file_system_type spufs_type;
551
552
long spufs_create(const struct path *path, struct dentry *dentry,
553
unsigned int flags, umode_t mode, struct file *filp)
554
{
555
struct inode *dir = d_inode(path->dentry);
556
int ret;
557
558
/* check if we are on spufs */
559
if (path->dentry->d_sb->s_type != &spufs_type)
560
return -EINVAL;
561
562
/* don't accept undefined flags */
563
if (flags & (~SPU_CREATE_FLAG_ALL))
564
return -EINVAL;
565
566
/* only threads can be underneath a gang */
567
if (path->dentry != path->dentry->d_sb->s_root)
568
if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
569
return -EINVAL;
570
571
mode &= ~current_umask();
572
573
if (flags & SPU_CREATE_GANG)
574
ret = spufs_create_gang(dir, dentry, path->mnt, mode);
575
else
576
ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
577
filp);
578
if (ret >= 0)
579
fsnotify_mkdir(dir, dentry);
580
581
return ret;
582
}
583
584
/* File system initialization */
585
struct spufs_fs_context {
586
kuid_t uid;
587
kgid_t gid;
588
umode_t mode;
589
};
590
591
enum {
592
Opt_uid, Opt_gid, Opt_mode, Opt_debug,
593
};
594
595
static const struct fs_parameter_spec spufs_fs_parameters[] = {
596
fsparam_u32 ("gid", Opt_gid),
597
fsparam_u32oct ("mode", Opt_mode),
598
fsparam_u32 ("uid", Opt_uid),
599
fsparam_flag ("debug", Opt_debug),
600
{}
601
};
602
603
static int spufs_show_options(struct seq_file *m, struct dentry *root)
604
{
605
struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb);
606
struct inode *inode = root->d_inode;
607
608
if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
609
seq_printf(m, ",uid=%u",
610
from_kuid_munged(&init_user_ns, inode->i_uid));
611
if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
612
seq_printf(m, ",gid=%u",
613
from_kgid_munged(&init_user_ns, inode->i_gid));
614
if ((inode->i_mode & S_IALLUGO) != 0775)
615
seq_printf(m, ",mode=%o", inode->i_mode);
616
if (sbi->debug)
617
seq_puts(m, ",debug");
618
return 0;
619
}
620
621
static int spufs_parse_param(struct fs_context *fc, struct fs_parameter *param)
622
{
623
struct spufs_fs_context *ctx = fc->fs_private;
624
struct spufs_sb_info *sbi = fc->s_fs_info;
625
struct fs_parse_result result;
626
kuid_t uid;
627
kgid_t gid;
628
int opt;
629
630
opt = fs_parse(fc, spufs_fs_parameters, param, &result);
631
if (opt < 0)
632
return opt;
633
634
switch (opt) {
635
case Opt_uid:
636
uid = make_kuid(current_user_ns(), result.uint_32);
637
if (!uid_valid(uid))
638
return invalf(fc, "Unknown uid");
639
ctx->uid = uid;
640
break;
641
case Opt_gid:
642
gid = make_kgid(current_user_ns(), result.uint_32);
643
if (!gid_valid(gid))
644
return invalf(fc, "Unknown gid");
645
ctx->gid = gid;
646
break;
647
case Opt_mode:
648
ctx->mode = result.uint_32 & S_IALLUGO;
649
break;
650
case Opt_debug:
651
sbi->debug = true;
652
break;
653
}
654
655
return 0;
656
}
657
658
static void spufs_exit_isolated_loader(void)
659
{
660
free_pages((unsigned long) isolated_loader,
661
get_order(isolated_loader_size));
662
}
663
664
static void __init
665
spufs_init_isolated_loader(void)
666
{
667
struct device_node *dn;
668
const char *loader;
669
int size;
670
671
dn = of_find_node_by_path("/spu-isolation");
672
if (!dn)
673
return;
674
675
loader = of_get_property(dn, "loader", &size);
676
of_node_put(dn);
677
if (!loader)
678
return;
679
680
/* the loader must be align on a 16 byte boundary */
681
isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size));
682
if (!isolated_loader)
683
return;
684
685
isolated_loader_size = size;
686
memcpy(isolated_loader, loader, size);
687
printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
688
}
689
690
static int spufs_create_root(struct super_block *sb, struct fs_context *fc)
691
{
692
struct spufs_fs_context *ctx = fc->fs_private;
693
struct inode *inode;
694
695
if (!spu_management_ops)
696
return -ENODEV;
697
698
inode = spufs_new_inode(sb, S_IFDIR | ctx->mode);
699
if (!inode)
700
return -ENOMEM;
701
702
inode->i_uid = ctx->uid;
703
inode->i_gid = ctx->gid;
704
inode->i_op = &simple_dir_inode_operations;
705
inode->i_fop = &simple_dir_operations;
706
SPUFS_I(inode)->i_ctx = NULL;
707
inc_nlink(inode);
708
709
sb->s_root = d_make_root(inode);
710
if (!sb->s_root)
711
return -ENOMEM;
712
return 0;
713
}
714
715
static const struct super_operations spufs_ops = {
716
.alloc_inode = spufs_alloc_inode,
717
.free_inode = spufs_free_inode,
718
.statfs = simple_statfs,
719
.evict_inode = spufs_evict_inode,
720
.show_options = spufs_show_options,
721
};
722
723
static int spufs_fill_super(struct super_block *sb, struct fs_context *fc)
724
{
725
sb->s_maxbytes = MAX_LFS_FILESIZE;
726
sb->s_blocksize = PAGE_SIZE;
727
sb->s_blocksize_bits = PAGE_SHIFT;
728
sb->s_magic = SPUFS_MAGIC;
729
sb->s_op = &spufs_ops;
730
731
return spufs_create_root(sb, fc);
732
}
733
734
static int spufs_get_tree(struct fs_context *fc)
735
{
736
return get_tree_single(fc, spufs_fill_super);
737
}
738
739
static void spufs_free_fc(struct fs_context *fc)
740
{
741
kfree(fc->s_fs_info);
742
}
743
744
static const struct fs_context_operations spufs_context_ops = {
745
.free = spufs_free_fc,
746
.parse_param = spufs_parse_param,
747
.get_tree = spufs_get_tree,
748
};
749
750
static int spufs_init_fs_context(struct fs_context *fc)
751
{
752
struct spufs_fs_context *ctx;
753
struct spufs_sb_info *sbi;
754
755
ctx = kzalloc(sizeof(struct spufs_fs_context), GFP_KERNEL);
756
if (!ctx)
757
goto nomem;
758
759
sbi = kzalloc(sizeof(struct spufs_sb_info), GFP_KERNEL);
760
if (!sbi)
761
goto nomem_ctx;
762
763
ctx->uid = current_uid();
764
ctx->gid = current_gid();
765
ctx->mode = 0755;
766
767
fc->fs_private = ctx;
768
fc->s_fs_info = sbi;
769
fc->ops = &spufs_context_ops;
770
return 0;
771
772
nomem_ctx:
773
kfree(ctx);
774
nomem:
775
return -ENOMEM;
776
}
777
778
static struct file_system_type spufs_type = {
779
.owner = THIS_MODULE,
780
.name = "spufs",
781
.init_fs_context = spufs_init_fs_context,
782
.parameters = spufs_fs_parameters,
783
.kill_sb = kill_litter_super,
784
};
785
MODULE_ALIAS_FS("spufs");
786
787
static int __init spufs_init(void)
788
{
789
int ret;
790
791
ret = -ENODEV;
792
if (!spu_management_ops)
793
goto out;
794
795
ret = -ENOMEM;
796
spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
797
sizeof(struct spufs_inode_info), 0,
798
SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once);
799
800
if (!spufs_inode_cache)
801
goto out;
802
ret = spu_sched_init();
803
if (ret)
804
goto out_cache;
805
ret = register_spu_syscalls(&spufs_calls);
806
if (ret)
807
goto out_sched;
808
ret = register_filesystem(&spufs_type);
809
if (ret)
810
goto out_syscalls;
811
812
spufs_init_isolated_loader();
813
814
return 0;
815
816
out_syscalls:
817
unregister_spu_syscalls(&spufs_calls);
818
out_sched:
819
spu_sched_exit();
820
out_cache:
821
kmem_cache_destroy(spufs_inode_cache);
822
out:
823
return ret;
824
}
825
module_init(spufs_init);
826
827
static void __exit spufs_exit(void)
828
{
829
spu_sched_exit();
830
spufs_exit_isolated_loader();
831
unregister_spu_syscalls(&spufs_calls);
832
unregister_filesystem(&spufs_type);
833
kmem_cache_destroy(spufs_inode_cache);
834
}
835
module_exit(spufs_exit);
836
837
MODULE_DESCRIPTION("SPU file system");
838
MODULE_LICENSE("GPL");
839
MODULE_AUTHOR("Arnd Bergmann <[email protected]>");
840
841
842