inode.c 17.1 KB
Newer Older
1

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * SPU file system
 *
 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
 *
 * Author: Arnd Bergmann <arndb@de.ibm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/file.h>
#include <linux/fs.h>
26
#include <linux/fsnotify.h>
27 28 29 30
#include <linux/backing-dev.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/module.h>
31
#include <linux/mount.h>
32 33 34 35 36 37
#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/parser.h>

38
#include <asm/prom.h>
39
#include <asm/spu.h>
40
#include <asm/spu_priv1.h>
41 42 43 44
#include <asm/uaccess.h>

#include "spufs.h"

45 46 47 48
struct spufs_sb_info {
	int debug;
};

49
static struct kmem_cache *spufs_inode_cache;
50
char *isolated_loader;
51
static int isolated_loader_size;
52

53 54 55 56 57
static struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb)
{
	return sb->s_fs_info;
}

58 59 60 61 62
static struct inode *
spufs_alloc_inode(struct super_block *sb)
{
	struct spufs_inode_info *ei;

63
	ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL);
64 65
	if (!ei)
		return NULL;
66 67 68

	ei->i_gang = NULL;
	ei->i_ctx = NULL;
69
	ei->i_openers = 0;
70

71 72 73
	return &ei->vfs_inode;
}

N
Nick Piggin 已提交
74
static void spufs_i_callback(struct rcu_head *head)
75
{
N
Nick Piggin 已提交
76
	struct inode *inode = container_of(head, struct inode, i_rcu);
77 78 79
	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
}

N
Nick Piggin 已提交
80 81 82 83 84
static void spufs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, spufs_i_callback);
}

85
static void
86
spufs_init_once(void *p)
87 88 89
{
	struct spufs_inode_info *ei = p;

C
Christoph Lameter 已提交
90
	inode_init_once(&ei->vfs_inode);
91 92 93
}

static struct inode *
A
Al Viro 已提交
94
spufs_new_inode(struct super_block *sb, umode_t mode)
95 96 97 98 99 100 101
{
	struct inode *inode;

	inode = new_inode(sb);
	if (!inode)
		goto out;

102
	inode->i_ino = get_next_ino();
103
	inode->i_mode = mode;
104 105
	inode->i_uid = current_fsuid();
	inode->i_gid = current_fsgid();
106 107 108 109 110 111 112 113 114 115 116 117 118
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
out:
	return inode;
}

static int
spufs_setattr(struct dentry *dentry, struct iattr *attr)
{
	struct inode *inode = dentry->d_inode;

	if ((attr->ia_valid & ATTR_SIZE) &&
	    (attr->ia_size != inode->i_size))
		return -EINVAL;
C
Christoph Hellwig 已提交
119 120 121
	setattr_copy(inode, attr);
	mark_inode_dirty(inode);
	return 0;
122 123 124 125 126
}


static int
spufs_new_file(struct super_block *sb, struct dentry *dentry,
A
Al Viro 已提交
127
		const struct file_operations *fops, umode_t mode,
128
		size_t size, struct spu_context *ctx)
129
{
130
	static const struct inode_operations spufs_file_iops = {
131 132 133 134 135 136 137 138 139 140 141 142 143
		.setattr = spufs_setattr,
	};
	struct inode *inode;
	int ret;

	ret = -ENOSPC;
	inode = spufs_new_inode(sb, S_IFREG | mode);
	if (!inode)
		goto out;

	ret = 0;
	inode->i_op = &spufs_file_iops;
	inode->i_fop = fops;
144
	inode->i_size = size;
145
	inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
146 147 148 149 150 151
	d_add(dentry, inode);
out:
	return ret;
}

static void
A
Al Viro 已提交
152
spufs_evict_inode(struct inode *inode)
153
{
154
	struct spufs_inode_info *ei = SPUFS_I(inode);
155
	clear_inode(inode);
156 157 158 159
	if (ei->i_ctx)
		put_spu_context(ei->i_ctx);
	if (ei->i_gang)
		put_spu_gang(ei->i_gang);
160 161
}

162
static void spufs_prune_dir(struct dentry *dir)
163
{
164
	struct dentry *dentry, *tmp;
165

166
	mutex_lock(&dir->d_inode->i_mutex);
167
	list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
168
		spin_lock(&dentry->d_lock);
169
		if (!(d_unhashed(dentry)) && dentry->d_inode) {
170
			dget_dlock(dentry);
171 172
			__d_drop(dentry);
			spin_unlock(&dentry->d_lock);
173
			simple_unlink(dir->d_inode, dentry);
N
Nick Piggin 已提交
174
			/* XXX: what was dcache_lock protecting here? Other
N
Nick Piggin 已提交
175 176
			 * filesystems (IB, configfs) release dcache_lock
			 * before unlink */
177 178 179 180
			dput(dentry);
		} else {
			spin_unlock(&dentry->d_lock);
		}
181
	}
182
	shrink_dcache_parent(dir);
183
	mutex_unlock(&dir->d_inode->i_mutex);
184 185
}

186 187
/* Caller must hold parent->i_mutex */
static int spufs_rmdir(struct inode *parent, struct dentry *dir)
188 189
{
	/* remove all entries */
A
Al Viro 已提交
190
	int res;
191
	spufs_prune_dir(dir);
192
	d_drop(dir);
A
Al Viro 已提交
193 194 195 196
	res = simple_rmdir(parent, dir);
	/* We have to give up the mm_struct */
	spu_forget(SPUFS_I(dir->d_inode)->i_ctx);
	return res;
197 198
}

199
static int spufs_fill_dir(struct dentry *dir,
A
Al Viro 已提交
200
		const struct spufs_tree_descr *files, umode_t mode,
201
		struct spu_context *ctx)
202 203
{
	while (files->name && files->name[0]) {
204 205
		int ret;
		struct dentry *dentry = d_alloc_name(dir, files->name);
206
		if (!dentry)
207
			return -ENOMEM;
208
		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
209
					files->mode & mode, files->size, ctx);
210
		if (ret)
211
			return ret;
212 213 214 215 216
		files++;
	}
	return 0;
}

217 218
static int spufs_dir_close(struct inode *inode, struct file *file)
{
219
	struct spu_context *ctx;
220 221
	struct inode *parent;
	struct dentry *dir;
222 223
	int ret;

J
Josef Sipek 已提交
224
	dir = file->f_path.dentry;
225 226
	parent = dir->d_parent->d_inode;
	ctx = SPUFS_I(dir->d_inode)->i_ctx;
227

228
	mutex_lock_nested(&parent->i_mutex, I_MUTEX_PARENT);
229 230
	ret = spufs_rmdir(parent, dir);
	mutex_unlock(&parent->i_mutex);
231
	WARN_ON(ret);
232

233 234 235
	return dcache_dir_close(inode, file);
}

236
const struct file_operations spufs_context_fops = {
237 238 239 240
	.open		= dcache_dir_open,
	.release	= spufs_dir_close,
	.llseek		= dcache_dir_lseek,
	.read		= generic_read_dir,
241
	.iterate	= dcache_readdir,
242
	.fsync		= noop_fsync,
243
};
244
EXPORT_SYMBOL_GPL(spufs_context_fops);
245 246

static int
247
spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
A
Al Viro 已提交
248
		umode_t mode)
249 250 251 252 253 254 255
{
	int ret;
	struct inode *inode;
	struct spu_context *ctx;

	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
	if (!inode)
256
		return -ENOSPC;
257 258 259 260 261

	if (dir->i_mode & S_ISGID) {
		inode->i_gid = dir->i_gid;
		inode->i_mode &= S_ISGID;
	}
262
	ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
263
	SPUFS_I(inode)->i_ctx = ctx;
264 265 266 267
	if (!ctx) {
		iput(inode);
		return -ENOSPC;
	}
268

269
	ctx->flags = flags;
270
	inode->i_op = &simple_dir_inode_operations;
271
	inode->i_fop = &simple_dir_operations;
272 273 274 275 276 277 278 279 280

	mutex_lock(&inode->i_mutex);

	dget(dentry);
	inc_nlink(dir);
	inc_nlink(inode);

	d_instantiate(dentry, inode);

281 282 283 284 285 286
	if (flags & SPU_CREATE_NOSCHED)
		ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
					 mode, ctx);
	else
		ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);

287
	if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
288 289 290 291
		ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
				mode, ctx);

	if (ret)
292 293 294
		spufs_rmdir(dir, dentry);

	mutex_unlock(&inode->i_mutex);
295

296 297 298
	return ret;
}

299
static int spufs_context_open(struct path *path)
300 301 302 303 304
{
	int ret;
	struct file *filp;

	ret = get_unused_fd();
305 306
	if (ret < 0)
		return ret;
307

308
	filp = dentry_open(path, O_RDONLY, current_cred());
309 310
	if (IS_ERR(filp)) {
		put_unused_fd(ret);
311
		return PTR_ERR(filp);
312 313 314 315 316 317 318
	}

	filp->f_op = &spufs_context_fops;
	fd_install(ret, filp);
	return ret;
}

319 320 321 322
static struct spu_context *
spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
						struct file *filp)
{
323
	struct spu_context *tmp, *neighbor, *err;
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
	int count, node;
	int aff_supp;

	aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
					struct spu, cbe_list))->aff_list);

	if (!aff_supp)
		return ERR_PTR(-EINVAL);

	if (flags & SPU_CREATE_GANG)
		return ERR_PTR(-EINVAL);

	if (flags & SPU_CREATE_AFFINITY_MEM &&
	    gang->aff_ref_ctx &&
	    gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
		return ERR_PTR(-EEXIST);

	if (gang->aff_flags & AFF_MERGED)
		return ERR_PTR(-EBUSY);

	neighbor = NULL;
	if (flags & SPU_CREATE_AFFINITY_SPU) {
		if (!filp || filp->f_op != &spufs_context_fops)
			return ERR_PTR(-EINVAL);

		neighbor = get_spu_context(
A
Al Viro 已提交
350
				SPUFS_I(file_inode(filp))->i_ctx);
351 352 353 354

		if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
		    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
		    !list_entry(neighbor->aff_list.next, struct spu_context,
355 356 357 358
		    aff_list)->aff_head) {
			err = ERR_PTR(-EEXIST);
			goto out_put_neighbor;
		}
359

360 361 362 363
		if (gang != neighbor->gang) {
			err = ERR_PTR(-EINVAL);
			goto out_put_neighbor;
		}
364 365 366 367 368 369 370 371 372 373 374 375 376

		count = 1;
		list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
			count++;
		if (list_empty(&neighbor->aff_list))
			count++;

		for (node = 0; node < MAX_NUMNODES; node++) {
			if ((cbe_spu_info[node].n_spus - atomic_read(
				&cbe_spu_info[node].reserved_spus)) >= count)
				break;
		}

377 378 379 380
		if (node == MAX_NUMNODES) {
			err = ERR_PTR(-EEXIST);
			goto out_put_neighbor;
		}
381 382 383
	}

	return neighbor;
384 385 386 387

out_put_neighbor:
	put_spu_context(neighbor);
	return err;
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
}

static void
spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
					struct spu_context *neighbor)
{
	if (flags & SPU_CREATE_AFFINITY_MEM)
		ctx->gang->aff_ref_ctx = ctx;

	if (flags & SPU_CREATE_AFFINITY_SPU) {
		if (list_empty(&neighbor->aff_list)) {
			list_add_tail(&neighbor->aff_list,
				&ctx->gang->aff_list_head);
			neighbor->aff_head = 1;
		}

		if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
		    || list_entry(neighbor->aff_list.next, struct spu_context,
							aff_list)->aff_head) {
			list_add(&ctx->aff_list, &neighbor->aff_list);
		} else  {
			list_add_tail(&ctx->aff_list, &neighbor->aff_list);
			if (neighbor->aff_head) {
				neighbor->aff_head = 0;
				ctx->aff_head = 1;
			}
		}

		if (!ctx->gang->aff_ref_ctx)
			ctx->gang->aff_ref_ctx = ctx;
	}
}

static int
spufs_create_context(struct inode *inode, struct dentry *dentry,
A
Al Viro 已提交
423
			struct vfsmount *mnt, int flags, umode_t mode,
424
			struct file *aff_filp)
425 426
{
	int ret;
427 428 429
	int affinity;
	struct spu_gang *gang;
	struct spu_context *neighbor;
430
	struct path path = {.mnt = mnt, .dentry = dentry};
431

432 433
	if ((flags & SPU_CREATE_NOSCHED) &&
	    !capable(CAP_SYS_NICE))
434
		return -EPERM;
435 436 437

	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
	    == SPU_CREATE_ISOLATE)
438
		return -EINVAL;
439

440
	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
441
		return -ENODEV;
442

443 444 445 446 447 448
	gang = NULL;
	neighbor = NULL;
	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
	if (affinity) {
		gang = SPUFS_I(inode)->i_gang;
		if (!gang)
449
			return -EINVAL;
450 451 452 453 454 455 456 457
		mutex_lock(&gang->aff_mutex);
		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
		if (IS_ERR(neighbor)) {
			ret = PTR_ERR(neighbor);
			goto out_aff_unlock;
		}
	}

458 459
	ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
	if (ret)
460 461
		goto out_aff_unlock;

462
	if (affinity) {
463 464
		spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
								neighbor);
465 466 467
		if (neighbor)
			put_spu_context(neighbor);
	}
468

469
	ret = spufs_context_open(&path);
470
	if (ret < 0)
471 472
		WARN_ON(spufs_rmdir(inode, dentry));

473 474 475
out_aff_unlock:
	if (affinity)
		mutex_unlock(&gang->aff_mutex);
476 477 478 479
	return ret;
}

static int
A
Al Viro 已提交
480
spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
{
	int ret;
	struct inode *inode;
	struct spu_gang *gang;

	ret = -ENOSPC;
	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
	if (!inode)
		goto out;

	ret = 0;
	if (dir->i_mode & S_ISGID) {
		inode->i_gid = dir->i_gid;
		inode->i_mode &= S_ISGID;
	}
	gang = alloc_spu_gang();
	SPUFS_I(inode)->i_ctx = NULL;
	SPUFS_I(inode)->i_gang = gang;
	if (!gang)
		goto out_iput;

502
	inode->i_op = &simple_dir_inode_operations;
503 504 505
	inode->i_fop = &simple_dir_operations;

	d_instantiate(dentry, inode);
J
Jeremy Kerr 已提交
506 507
	inc_nlink(dir);
	inc_nlink(dentry->d_inode);
508 509 510 511 512 513 514 515
	return ret;

out_iput:
	iput(inode);
out:
	return ret;
}

516
static int spufs_gang_open(struct path *path)
517 518 519 520 521
{
	int ret;
	struct file *filp;

	ret = get_unused_fd();
522 523
	if (ret < 0)
		return ret;
524

525 526 527 528
	/*
	 * get references for dget and mntget, will be released
	 * in error path of *_open().
	 */
529
	filp = dentry_open(path, O_RDONLY, current_cred());
530 531
	if (IS_ERR(filp)) {
		put_unused_fd(ret);
532
		return PTR_ERR(filp);
533 534
	}

535
	filp->f_op = &simple_dir_operations;
536 537 538 539 540 541
	fd_install(ret, filp);
	return ret;
}

static int spufs_create_gang(struct inode *inode,
			struct dentry *dentry,
A
Al Viro 已提交
542
			struct vfsmount *mnt, umode_t mode)
543
{
544
	struct path path = {.mnt = mnt, .dentry = dentry};
545 546 547
	int ret;

	ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
548 549 550 551 552 553
	if (!ret) {
		ret = spufs_gang_open(&path);
		if (ret < 0) {
			int err = simple_rmdir(inode, dentry);
			WARN_ON(err);
		}
554
	}
555 556 557 558
	return ret;
}


559 560
static struct file_system_type spufs_type;

561
long spufs_create(struct path *path, struct dentry *dentry,
A
Al Viro 已提交
562
		unsigned int flags, umode_t mode, struct file *filp)
563
{
564
	struct inode *dir = path->dentry->d_inode;
565 566
	int ret;

567
	/* check if we are on spufs */
568
	if (path->dentry->d_sb->s_type != &spufs_type)
569
		return -EINVAL;
570

571
	/* don't accept undefined flags */
572
	if (flags & (~SPU_CREATE_FLAG_ALL))
573
		return -EINVAL;
574

575
	/* only threads can be underneath a gang */
576 577 578
	if (path->dentry != path->dentry->d_sb->s_root)
		if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
			return -EINVAL;
579

A
Al Viro 已提交
580
	mode &= ~current_umask();
581

582
	if (flags & SPU_CREATE_GANG)
583
		ret = spufs_create_gang(dir, dentry, path->mnt, mode);
584
	else
585
		ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
586
					    filp);
587
	if (ret >= 0)
588
		fsnotify_mkdir(dir, dentry);
589 590 591 592 593 594

	return ret;
}

/* File system initialization */
enum {
595
	Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err,
596 597
};

598
static const match_table_t spufs_tokens = {
599 600 601 602 603
	{ Opt_uid,   "uid=%d" },
	{ Opt_gid,   "gid=%d" },
	{ Opt_mode,  "mode=%o" },
	{ Opt_debug, "debug" },
	{ Opt_err,    NULL  },
604 605 606
};

static int
607
spufs_parse_options(struct super_block *sb, char *options, struct inode *root)
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
{
	char *p;
	substring_t args[MAX_OPT_ARGS];

	while ((p = strsep(&options, ",")) != NULL) {
		int token, option;

		if (!*p)
			continue;

		token = match_token(p, spufs_tokens, args);
		switch (token) {
		case Opt_uid:
			if (match_int(&args[0], &option))
				return 0;
			root->i_uid = option;
			break;
		case Opt_gid:
			if (match_int(&args[0], &option))
				return 0;
			root->i_gid = option;
			break;
630 631 632 633 634
		case Opt_mode:
			if (match_octal(&args[0], &option))
				return 0;
			root->i_mode = option | S_IFDIR;
			break;
635 636 637
		case Opt_debug:
			spufs_get_sb_info(sb)->debug = 1;
			break;
638 639 640 641 642 643 644
		default:
			return 0;
		}
	}
	return 1;
}

645 646
static void spufs_exit_isolated_loader(void)
{
647 648
	free_pages((unsigned long) isolated_loader,
			get_order(isolated_loader_size));
649 650
}

651 652 653 654 655 656 657 658 659 660 661
static void
spufs_init_isolated_loader(void)
{
	struct device_node *dn;
	const char *loader;
	int size;

	dn = of_find_node_by_path("/spu-isolation");
	if (!dn)
		return;

662
	loader = of_get_property(dn, "loader", &size);
663 664 665
	if (!loader)
		return;

666 667
	/* the loader must be align on a 16 byte boundary */
	isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size));
668 669 670
	if (!isolated_loader)
		return;

671
	isolated_loader_size = size;
672 673 674 675
	memcpy(isolated_loader, loader, size);
	printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
}

676
static int
677 678
spufs_create_root(struct super_block *sb, void *data)
{
679 680 681
	struct inode *inode;
	int ret;

682 683 684 685
	ret = -ENODEV;
	if (!spu_management_ops)
		goto out;

686 687 688 689 690
	ret = -ENOMEM;
	inode = spufs_new_inode(sb, S_IFDIR | 0775);
	if (!inode)
		goto out;

691
	inode->i_op = &simple_dir_inode_operations;
692 693
	inode->i_fop = &simple_dir_operations;
	SPUFS_I(inode)->i_ctx = NULL;
694
	inc_nlink(inode);
695 696

	ret = -EINVAL;
697
	if (!spufs_parse_options(sb, data, inode))
698 699 700
		goto out_iput;

	ret = -ENOMEM;
701
	sb->s_root = d_make_root(inode);
702
	if (!sb->s_root)
703
		goto out;
704 705 706 707 708 709 710 711 712 713 714

	return 0;
out_iput:
	iput(inode);
out:
	return ret;
}

static int
spufs_fill_super(struct super_block *sb, void *data, int silent)
{
715
	struct spufs_sb_info *info;
716
	static const struct super_operations s_ops = {
717 718 719
		.alloc_inode = spufs_alloc_inode,
		.destroy_inode = spufs_destroy_inode,
		.statfs = simple_statfs,
A
Al Viro 已提交
720
		.evict_inode = spufs_evict_inode,
M
Miklos Szeredi 已提交
721
		.show_options = generic_show_options,
722 723
	};

M
Miklos Szeredi 已提交
724 725
	save_mount_options(sb, data);

726 727 728 729
	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

730 731 732 733 734
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_blocksize = PAGE_CACHE_SIZE;
	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
	sb->s_magic = SPUFS_MAGIC;
	sb->s_op = &s_ops;
735
	sb->s_fs_info = info;
736 737 738 739

	return spufs_create_root(sb, data);
}

A
Al Viro 已提交
740 741 742
static struct dentry *
spufs_mount(struct file_system_type *fstype, int flags,
		const char *name, void *data)
743
{
A
Al Viro 已提交
744
	return mount_single(fstype, flags, data, spufs_fill_super);
745 746 747 748 749
}

static struct file_system_type spufs_type = {
	.owner = THIS_MODULE,
	.name = "spufs",
A
Al Viro 已提交
750
	.mount = spufs_mount,
751 752
	.kill_sb = kill_litter_super,
};
753
MODULE_ALIAS_FS("spufs");
754

755
static int __init spufs_init(void)
756 757
{
	int ret;
758

759 760 761 762
	ret = -ENODEV;
	if (!spu_management_ops)
		goto out;

763 764 765
	ret = -ENOMEM;
	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
			sizeof(struct spufs_inode_info), 0,
766
			SLAB_HWCACHE_ALIGN, spufs_init_once);
767 768 769

	if (!spufs_inode_cache)
		goto out;
770
	ret = spu_sched_init();
771 772
	if (ret)
		goto out_cache;
773
	ret = register_spu_syscalls(&spufs_calls);
774 775
	if (ret)
		goto out_sched;
776
	ret = register_filesystem(&spufs_type);
777
	if (ret)
778
		goto out_syscalls;
779 780

	spufs_init_isolated_loader();
781

782
	return 0;
783

784 785
out_syscalls:
	unregister_spu_syscalls(&spufs_calls);
786 787
out_sched:
	spu_sched_exit();
788 789 790 791 792 793 794
out_cache:
	kmem_cache_destroy(spufs_inode_cache);
out:
	return ret;
}
module_init(spufs_init);

795
static void __exit spufs_exit(void)
796
{
797
	spu_sched_exit();
798
	spufs_exit_isolated_loader();
799 800 801 802 803 804 805 806 807
	unregister_spu_syscalls(&spufs_calls);
	unregister_filesystem(&spufs_type);
	kmem_cache_destroy(spufs_inode_cache);
}
module_exit(spufs_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");