xref: /linux/arch/powerpc/platforms/cell/spufs/inode.c (revision 67207b9664a8d603138ef1556141e6d0a102bea7)
1*67207b96SArnd Bergmann /*
2*67207b96SArnd Bergmann  * SPU file system
3*67207b96SArnd Bergmann  *
4*67207b96SArnd Bergmann  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
5*67207b96SArnd Bergmann  *
6*67207b96SArnd Bergmann  * Author: Arnd Bergmann <arndb@de.ibm.com>
7*67207b96SArnd Bergmann  *
8*67207b96SArnd Bergmann  * This program is free software; you can redistribute it and/or modify
9*67207b96SArnd Bergmann  * it under the terms of the GNU General Public License as published by
10*67207b96SArnd Bergmann  * the Free Software Foundation; either version 2, or (at your option)
11*67207b96SArnd Bergmann  * any later version.
12*67207b96SArnd Bergmann  *
13*67207b96SArnd Bergmann  * This program is distributed in the hope that it will be useful,
14*67207b96SArnd Bergmann  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*67207b96SArnd Bergmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*67207b96SArnd Bergmann  * GNU General Public License for more details.
17*67207b96SArnd Bergmann  *
18*67207b96SArnd Bergmann  * You should have received a copy of the GNU General Public License
19*67207b96SArnd Bergmann  * along with this program; if not, write to the Free Software
20*67207b96SArnd Bergmann  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*67207b96SArnd Bergmann  */
22*67207b96SArnd Bergmann 
23*67207b96SArnd Bergmann #include <linux/file.h>
24*67207b96SArnd Bergmann #include <linux/fs.h>
25*67207b96SArnd Bergmann #include <linux/backing-dev.h>
26*67207b96SArnd Bergmann #include <linux/init.h>
27*67207b96SArnd Bergmann #include <linux/ioctl.h>
28*67207b96SArnd Bergmann #include <linux/module.h>
29*67207b96SArnd Bergmann #include <linux/namei.h>
30*67207b96SArnd Bergmann #include <linux/pagemap.h>
31*67207b96SArnd Bergmann #include <linux/poll.h>
32*67207b96SArnd Bergmann #include <linux/slab.h>
33*67207b96SArnd Bergmann #include <linux/parser.h>
34*67207b96SArnd Bergmann 
35*67207b96SArnd Bergmann #include <asm/io.h>
36*67207b96SArnd Bergmann #include <asm/semaphore.h>
37*67207b96SArnd Bergmann #include <asm/spu.h>
38*67207b96SArnd Bergmann #include <asm/uaccess.h>
39*67207b96SArnd Bergmann 
40*67207b96SArnd Bergmann #include "spufs.h"
41*67207b96SArnd Bergmann 
42*67207b96SArnd Bergmann static kmem_cache_t *spufs_inode_cache;
43*67207b96SArnd Bergmann 
44*67207b96SArnd Bergmann /* Information about the backing dev, same as ramfs */
45*67207b96SArnd Bergmann #if 0
46*67207b96SArnd Bergmann static struct backing_dev_info spufs_backing_dev_info = {
47*67207b96SArnd Bergmann 	.ra_pages       = 0,    /* No readahead */
48*67207b96SArnd Bergmann 	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
49*67207b96SArnd Bergmann 	  BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | BDI_CAP_READ_MAP |
50*67207b96SArnd Bergmann 	  BDI_CAP_WRITE_MAP,
51*67207b96SArnd Bergmann };
52*67207b96SArnd Bergmann 
53*67207b96SArnd Bergmann static struct address_space_operations spufs_aops = {
54*67207b96SArnd Bergmann 	.readpage       = simple_readpage,
55*67207b96SArnd Bergmann 	.prepare_write  = simple_prepare_write,
56*67207b96SArnd Bergmann 	.commit_write   = simple_commit_write,
57*67207b96SArnd Bergmann };
58*67207b96SArnd Bergmann #endif
59*67207b96SArnd Bergmann 
60*67207b96SArnd Bergmann /* Inode operations */
61*67207b96SArnd Bergmann 
62*67207b96SArnd Bergmann static struct inode *
63*67207b96SArnd Bergmann spufs_alloc_inode(struct super_block *sb)
64*67207b96SArnd Bergmann {
65*67207b96SArnd Bergmann 	struct spufs_inode_info *ei;
66*67207b96SArnd Bergmann 
67*67207b96SArnd Bergmann 	ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL);
68*67207b96SArnd Bergmann 	if (!ei)
69*67207b96SArnd Bergmann 		return NULL;
70*67207b96SArnd Bergmann 	return &ei->vfs_inode;
71*67207b96SArnd Bergmann }
72*67207b96SArnd Bergmann 
73*67207b96SArnd Bergmann static void
74*67207b96SArnd Bergmann spufs_destroy_inode(struct inode *inode)
75*67207b96SArnd Bergmann {
76*67207b96SArnd Bergmann 	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
77*67207b96SArnd Bergmann }
78*67207b96SArnd Bergmann 
79*67207b96SArnd Bergmann static void
80*67207b96SArnd Bergmann spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags)
81*67207b96SArnd Bergmann {
82*67207b96SArnd Bergmann 	struct spufs_inode_info *ei = p;
83*67207b96SArnd Bergmann 
84*67207b96SArnd Bergmann 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
85*67207b96SArnd Bergmann 	    SLAB_CTOR_CONSTRUCTOR) {
86*67207b96SArnd Bergmann 		inode_init_once(&ei->vfs_inode);
87*67207b96SArnd Bergmann 	}
88*67207b96SArnd Bergmann }
89*67207b96SArnd Bergmann 
90*67207b96SArnd Bergmann static struct inode *
91*67207b96SArnd Bergmann spufs_new_inode(struct super_block *sb, int mode)
92*67207b96SArnd Bergmann {
93*67207b96SArnd Bergmann 	struct inode *inode;
94*67207b96SArnd Bergmann 
95*67207b96SArnd Bergmann 	inode = new_inode(sb);
96*67207b96SArnd Bergmann 	if (!inode)
97*67207b96SArnd Bergmann 		goto out;
98*67207b96SArnd Bergmann 
99*67207b96SArnd Bergmann 	inode->i_mode = mode;
100*67207b96SArnd Bergmann 	inode->i_uid = current->fsuid;
101*67207b96SArnd Bergmann 	inode->i_gid = current->fsgid;
102*67207b96SArnd Bergmann 	inode->i_blksize = PAGE_CACHE_SIZE;
103*67207b96SArnd Bergmann 	inode->i_blocks = 0;
104*67207b96SArnd Bergmann 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
105*67207b96SArnd Bergmann out:
106*67207b96SArnd Bergmann 	return inode;
107*67207b96SArnd Bergmann }
108*67207b96SArnd Bergmann 
109*67207b96SArnd Bergmann static int
110*67207b96SArnd Bergmann spufs_setattr(struct dentry *dentry, struct iattr *attr)
111*67207b96SArnd Bergmann {
112*67207b96SArnd Bergmann 	struct inode *inode = dentry->d_inode;
113*67207b96SArnd Bergmann 
114*67207b96SArnd Bergmann /*	dump_stack();
115*67207b96SArnd Bergmann 	pr_debug("ia_size %lld, i_size:%lld\n", attr->ia_size, inode->i_size);
116*67207b96SArnd Bergmann */
117*67207b96SArnd Bergmann 	if ((attr->ia_valid & ATTR_SIZE) &&
118*67207b96SArnd Bergmann 	    (attr->ia_size != inode->i_size))
119*67207b96SArnd Bergmann 		return -EINVAL;
120*67207b96SArnd Bergmann 	return inode_setattr(inode, attr);
121*67207b96SArnd Bergmann }
122*67207b96SArnd Bergmann 
123*67207b96SArnd Bergmann 
124*67207b96SArnd Bergmann static int
125*67207b96SArnd Bergmann spufs_new_file(struct super_block *sb, struct dentry *dentry,
126*67207b96SArnd Bergmann 		struct file_operations *fops, int mode,
127*67207b96SArnd Bergmann 		struct spu_context *ctx)
128*67207b96SArnd Bergmann {
129*67207b96SArnd Bergmann 	static struct inode_operations spufs_file_iops = {
130*67207b96SArnd Bergmann 		.getattr = simple_getattr,
131*67207b96SArnd Bergmann 		.setattr = spufs_setattr,
132*67207b96SArnd Bergmann 		.unlink  = simple_unlink,
133*67207b96SArnd Bergmann 	};
134*67207b96SArnd Bergmann 	struct inode *inode;
135*67207b96SArnd Bergmann 	int ret;
136*67207b96SArnd Bergmann 
137*67207b96SArnd Bergmann 	ret = -ENOSPC;
138*67207b96SArnd Bergmann 	inode = spufs_new_inode(sb, S_IFREG | mode);
139*67207b96SArnd Bergmann 	if (!inode)
140*67207b96SArnd Bergmann 		goto out;
141*67207b96SArnd Bergmann 
142*67207b96SArnd Bergmann 	ret = 0;
143*67207b96SArnd Bergmann 	inode->i_op = &spufs_file_iops;
144*67207b96SArnd Bergmann 	inode->i_fop = fops;
145*67207b96SArnd Bergmann 	inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
146*67207b96SArnd Bergmann 	d_add(dentry, inode);
147*67207b96SArnd Bergmann out:
148*67207b96SArnd Bergmann 	return ret;
149*67207b96SArnd Bergmann }
150*67207b96SArnd Bergmann 
151*67207b96SArnd Bergmann static void
152*67207b96SArnd Bergmann spufs_delete_inode(struct inode *inode)
153*67207b96SArnd Bergmann {
154*67207b96SArnd Bergmann 	if (SPUFS_I(inode)->i_ctx)
155*67207b96SArnd Bergmann 		put_spu_context(SPUFS_I(inode)->i_ctx);
156*67207b96SArnd Bergmann 	clear_inode(inode);
157*67207b96SArnd Bergmann }
158*67207b96SArnd Bergmann 
159*67207b96SArnd Bergmann static int
160*67207b96SArnd Bergmann spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
161*67207b96SArnd Bergmann 		int mode, struct spu_context *ctx)
162*67207b96SArnd Bergmann {
163*67207b96SArnd Bergmann 	struct dentry *dentry;
164*67207b96SArnd Bergmann 	int ret;
165*67207b96SArnd Bergmann 
166*67207b96SArnd Bergmann 	while (files->name && files->name[0]) {
167*67207b96SArnd Bergmann 		ret = -ENOMEM;
168*67207b96SArnd Bergmann 		dentry = d_alloc_name(dir, files->name);
169*67207b96SArnd Bergmann 		if (!dentry)
170*67207b96SArnd Bergmann 			goto out;
171*67207b96SArnd Bergmann 		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
172*67207b96SArnd Bergmann 					files->mode & mode, ctx);
173*67207b96SArnd Bergmann 		if (ret)
174*67207b96SArnd Bergmann 			goto out;
175*67207b96SArnd Bergmann 		files++;
176*67207b96SArnd Bergmann 	}
177*67207b96SArnd Bergmann 	return 0;
178*67207b96SArnd Bergmann out:
179*67207b96SArnd Bergmann 	// FIXME: remove all files that are left
180*67207b96SArnd Bergmann 
181*67207b96SArnd Bergmann 	return ret;
182*67207b96SArnd Bergmann }
183*67207b96SArnd Bergmann 
184*67207b96SArnd Bergmann static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
185*67207b96SArnd Bergmann {
186*67207b96SArnd Bergmann 	struct dentry *dentry;
187*67207b96SArnd Bergmann 	int err;
188*67207b96SArnd Bergmann 
189*67207b96SArnd Bergmann 	spin_lock(&dcache_lock);
190*67207b96SArnd Bergmann 	/* remove all entries */
191*67207b96SArnd Bergmann 	err = 0;
192*67207b96SArnd Bergmann 	list_for_each_entry(dentry, &dir_dentry->d_subdirs, d_child) {
193*67207b96SArnd Bergmann 		if (d_unhashed(dentry) || !dentry->d_inode)
194*67207b96SArnd Bergmann 			continue;
195*67207b96SArnd Bergmann 		atomic_dec(&dentry->d_count);
196*67207b96SArnd Bergmann 		spin_lock(&dentry->d_lock);
197*67207b96SArnd Bergmann 		__d_drop(dentry);
198*67207b96SArnd Bergmann 		spin_unlock(&dentry->d_lock);
199*67207b96SArnd Bergmann 	}
200*67207b96SArnd Bergmann 	spin_unlock(&dcache_lock);
201*67207b96SArnd Bergmann 	if (!err) {
202*67207b96SArnd Bergmann 		shrink_dcache_parent(dir_dentry);
203*67207b96SArnd Bergmann 		err = simple_rmdir(root, dir_dentry);
204*67207b96SArnd Bergmann 	}
205*67207b96SArnd Bergmann 	return err;
206*67207b96SArnd Bergmann }
207*67207b96SArnd Bergmann 
208*67207b96SArnd Bergmann static int spufs_dir_close(struct inode *inode, struct file *file)
209*67207b96SArnd Bergmann {
210*67207b96SArnd Bergmann 	struct inode *dir;
211*67207b96SArnd Bergmann 	struct dentry *dentry;
212*67207b96SArnd Bergmann 	int ret;
213*67207b96SArnd Bergmann 
214*67207b96SArnd Bergmann 	dentry = file->f_dentry;
215*67207b96SArnd Bergmann 	dir = dentry->d_parent->d_inode;
216*67207b96SArnd Bergmann 	down(&dir->i_sem);
217*67207b96SArnd Bergmann 	ret = spufs_rmdir(dir, file->f_dentry);
218*67207b96SArnd Bergmann 	WARN_ON(ret);
219*67207b96SArnd Bergmann 	up(&dir->i_sem);
220*67207b96SArnd Bergmann 	return dcache_dir_close(inode, file);
221*67207b96SArnd Bergmann }
222*67207b96SArnd Bergmann 
223*67207b96SArnd Bergmann struct inode_operations spufs_dir_inode_operations = {
224*67207b96SArnd Bergmann 	.lookup = simple_lookup,
225*67207b96SArnd Bergmann };
226*67207b96SArnd Bergmann 
227*67207b96SArnd Bergmann struct file_operations spufs_autodelete_dir_operations = {
228*67207b96SArnd Bergmann 	.open		= dcache_dir_open,
229*67207b96SArnd Bergmann 	.release	= spufs_dir_close,
230*67207b96SArnd Bergmann 	.llseek		= dcache_dir_lseek,
231*67207b96SArnd Bergmann 	.read		= generic_read_dir,
232*67207b96SArnd Bergmann 	.readdir	= dcache_readdir,
233*67207b96SArnd Bergmann 	.fsync		= simple_sync_file,
234*67207b96SArnd Bergmann };
235*67207b96SArnd Bergmann 
236*67207b96SArnd Bergmann static int
237*67207b96SArnd Bergmann spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
238*67207b96SArnd Bergmann {
239*67207b96SArnd Bergmann 	int ret;
240*67207b96SArnd Bergmann 	struct inode *inode;
241*67207b96SArnd Bergmann 	struct spu_context *ctx;
242*67207b96SArnd Bergmann 
243*67207b96SArnd Bergmann 	ret = -ENOSPC;
244*67207b96SArnd Bergmann 	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
245*67207b96SArnd Bergmann 	if (!inode)
246*67207b96SArnd Bergmann 		goto out;
247*67207b96SArnd Bergmann 
248*67207b96SArnd Bergmann 	if (dir->i_mode & S_ISGID) {
249*67207b96SArnd Bergmann 		inode->i_gid = dir->i_gid;
250*67207b96SArnd Bergmann 		inode->i_mode &= S_ISGID;
251*67207b96SArnd Bergmann 	}
252*67207b96SArnd Bergmann 	ctx = alloc_spu_context();
253*67207b96SArnd Bergmann 	SPUFS_I(inode)->i_ctx = ctx;
254*67207b96SArnd Bergmann 	if (!ctx)
255*67207b96SArnd Bergmann 		goto out_iput;
256*67207b96SArnd Bergmann 
257*67207b96SArnd Bergmann 	inode->i_op = &spufs_dir_inode_operations;
258*67207b96SArnd Bergmann 	inode->i_fop = &simple_dir_operations;
259*67207b96SArnd Bergmann 	ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
260*67207b96SArnd Bergmann 	if (ret)
261*67207b96SArnd Bergmann 		goto out_free_ctx;
262*67207b96SArnd Bergmann 
263*67207b96SArnd Bergmann 	d_instantiate(dentry, inode);
264*67207b96SArnd Bergmann 	dget(dentry);
265*67207b96SArnd Bergmann 	dir->i_nlink++;
266*67207b96SArnd Bergmann 	goto out;
267*67207b96SArnd Bergmann 
268*67207b96SArnd Bergmann out_free_ctx:
269*67207b96SArnd Bergmann 	put_spu_context(ctx);
270*67207b96SArnd Bergmann out_iput:
271*67207b96SArnd Bergmann 	iput(inode);
272*67207b96SArnd Bergmann out:
273*67207b96SArnd Bergmann 	return ret;
274*67207b96SArnd Bergmann }
275*67207b96SArnd Bergmann 
276*67207b96SArnd Bergmann long
277*67207b96SArnd Bergmann spufs_create_thread(struct nameidata *nd, const char *name,
278*67207b96SArnd Bergmann 			unsigned int flags, mode_t mode)
279*67207b96SArnd Bergmann {
280*67207b96SArnd Bergmann 	struct dentry *dentry;
281*67207b96SArnd Bergmann 	struct file *filp;
282*67207b96SArnd Bergmann 	int ret;
283*67207b96SArnd Bergmann 
284*67207b96SArnd Bergmann 	/* need to be at the root of spufs */
285*67207b96SArnd Bergmann 	ret = -EINVAL;
286*67207b96SArnd Bergmann 	if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC ||
287*67207b96SArnd Bergmann 		nd->dentry != nd->dentry->d_sb->s_root)
288*67207b96SArnd Bergmann 		goto out;
289*67207b96SArnd Bergmann 
290*67207b96SArnd Bergmann 	dentry = lookup_create(nd, 1);
291*67207b96SArnd Bergmann 	ret = PTR_ERR(dentry);
292*67207b96SArnd Bergmann 	if (IS_ERR(dentry))
293*67207b96SArnd Bergmann 		goto out_dir;
294*67207b96SArnd Bergmann 
295*67207b96SArnd Bergmann 	ret = -EEXIST;
296*67207b96SArnd Bergmann 	if (dentry->d_inode)
297*67207b96SArnd Bergmann 		goto out_dput;
298*67207b96SArnd Bergmann 
299*67207b96SArnd Bergmann 	mode &= ~current->fs->umask;
300*67207b96SArnd Bergmann 	ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO);
301*67207b96SArnd Bergmann 	if (ret)
302*67207b96SArnd Bergmann 		goto out_dput;
303*67207b96SArnd Bergmann 
304*67207b96SArnd Bergmann 	ret = get_unused_fd();
305*67207b96SArnd Bergmann 	if (ret < 0)
306*67207b96SArnd Bergmann 		goto out_dput;
307*67207b96SArnd Bergmann 
308*67207b96SArnd Bergmann 	dentry->d_inode->i_nlink++;
309*67207b96SArnd Bergmann 
310*67207b96SArnd Bergmann 	filp = filp_open(name, O_RDONLY, mode);
311*67207b96SArnd Bergmann 	if (IS_ERR(filp)) {
312*67207b96SArnd Bergmann 		// FIXME: remove directory again
313*67207b96SArnd Bergmann 		put_unused_fd(ret);
314*67207b96SArnd Bergmann 		ret = PTR_ERR(filp);
315*67207b96SArnd Bergmann 	} else {
316*67207b96SArnd Bergmann 		filp->f_op = &spufs_autodelete_dir_operations;
317*67207b96SArnd Bergmann 		fd_install(ret, filp);
318*67207b96SArnd Bergmann 	}
319*67207b96SArnd Bergmann 
320*67207b96SArnd Bergmann out_dput:
321*67207b96SArnd Bergmann 	dput(dentry);
322*67207b96SArnd Bergmann out_dir:
323*67207b96SArnd Bergmann 	up(&nd->dentry->d_inode->i_sem);
324*67207b96SArnd Bergmann out:
325*67207b96SArnd Bergmann 	return ret;
326*67207b96SArnd Bergmann }
327*67207b96SArnd Bergmann 
328*67207b96SArnd Bergmann /* File system initialization */
329*67207b96SArnd Bergmann enum {
330*67207b96SArnd Bergmann 	Opt_uid, Opt_gid, Opt_err,
331*67207b96SArnd Bergmann };
332*67207b96SArnd Bergmann 
333*67207b96SArnd Bergmann static match_table_t spufs_tokens = {
334*67207b96SArnd Bergmann 	{ Opt_uid, "uid=%d" },
335*67207b96SArnd Bergmann 	{ Opt_gid, "gid=%d" },
336*67207b96SArnd Bergmann 	{ Opt_err, NULL  },
337*67207b96SArnd Bergmann };
338*67207b96SArnd Bergmann 
339*67207b96SArnd Bergmann static int
340*67207b96SArnd Bergmann spufs_parse_options(char *options, struct inode *root)
341*67207b96SArnd Bergmann {
342*67207b96SArnd Bergmann 	char *p;
343*67207b96SArnd Bergmann 	substring_t args[MAX_OPT_ARGS];
344*67207b96SArnd Bergmann 
345*67207b96SArnd Bergmann 	while ((p = strsep(&options, ",")) != NULL) {
346*67207b96SArnd Bergmann 		int token, option;
347*67207b96SArnd Bergmann 
348*67207b96SArnd Bergmann 		if (!*p)
349*67207b96SArnd Bergmann 			continue;
350*67207b96SArnd Bergmann 
351*67207b96SArnd Bergmann 		token = match_token(p, spufs_tokens, args);
352*67207b96SArnd Bergmann 		switch (token) {
353*67207b96SArnd Bergmann 		case Opt_uid:
354*67207b96SArnd Bergmann 			if (match_int(&args[0], &option))
355*67207b96SArnd Bergmann 				return 0;
356*67207b96SArnd Bergmann 			root->i_uid = option;
357*67207b96SArnd Bergmann 			break;
358*67207b96SArnd Bergmann 		case Opt_gid:
359*67207b96SArnd Bergmann 			if (match_int(&args[0], &option))
360*67207b96SArnd Bergmann 				return 0;
361*67207b96SArnd Bergmann 			root->i_gid = option;
362*67207b96SArnd Bergmann 			break;
363*67207b96SArnd Bergmann 		default:
364*67207b96SArnd Bergmann 			return 0;
365*67207b96SArnd Bergmann 		}
366*67207b96SArnd Bergmann 	}
367*67207b96SArnd Bergmann 	return 1;
368*67207b96SArnd Bergmann }
369*67207b96SArnd Bergmann 
370*67207b96SArnd Bergmann static int
371*67207b96SArnd Bergmann spufs_create_root(struct super_block *sb, void *data) {
372*67207b96SArnd Bergmann 	struct inode *inode;
373*67207b96SArnd Bergmann 	int ret;
374*67207b96SArnd Bergmann 
375*67207b96SArnd Bergmann 	ret = -ENOMEM;
376*67207b96SArnd Bergmann 	inode = spufs_new_inode(sb, S_IFDIR | 0775);
377*67207b96SArnd Bergmann 	if (!inode)
378*67207b96SArnd Bergmann 		goto out;
379*67207b96SArnd Bergmann 
380*67207b96SArnd Bergmann 	inode->i_op = &spufs_dir_inode_operations;
381*67207b96SArnd Bergmann 	inode->i_fop = &simple_dir_operations;
382*67207b96SArnd Bergmann 	SPUFS_I(inode)->i_ctx = NULL;
383*67207b96SArnd Bergmann 
384*67207b96SArnd Bergmann 	ret = -EINVAL;
385*67207b96SArnd Bergmann 	if (!spufs_parse_options(data, inode))
386*67207b96SArnd Bergmann 		goto out_iput;
387*67207b96SArnd Bergmann 
388*67207b96SArnd Bergmann 	ret = -ENOMEM;
389*67207b96SArnd Bergmann 	sb->s_root = d_alloc_root(inode);
390*67207b96SArnd Bergmann 	if (!sb->s_root)
391*67207b96SArnd Bergmann 		goto out_iput;
392*67207b96SArnd Bergmann 
393*67207b96SArnd Bergmann 	return 0;
394*67207b96SArnd Bergmann out_iput:
395*67207b96SArnd Bergmann 	iput(inode);
396*67207b96SArnd Bergmann out:
397*67207b96SArnd Bergmann 	return ret;
398*67207b96SArnd Bergmann }
399*67207b96SArnd Bergmann 
400*67207b96SArnd Bergmann static int
401*67207b96SArnd Bergmann spufs_fill_super(struct super_block *sb, void *data, int silent)
402*67207b96SArnd Bergmann {
403*67207b96SArnd Bergmann 	static struct super_operations s_ops = {
404*67207b96SArnd Bergmann 		.alloc_inode = spufs_alloc_inode,
405*67207b96SArnd Bergmann 		.destroy_inode = spufs_destroy_inode,
406*67207b96SArnd Bergmann 		.statfs = simple_statfs,
407*67207b96SArnd Bergmann 		.delete_inode = spufs_delete_inode,
408*67207b96SArnd Bergmann 		.drop_inode = generic_delete_inode,
409*67207b96SArnd Bergmann 	};
410*67207b96SArnd Bergmann 
411*67207b96SArnd Bergmann 	sb->s_maxbytes = MAX_LFS_FILESIZE;
412*67207b96SArnd Bergmann 	sb->s_blocksize = PAGE_CACHE_SIZE;
413*67207b96SArnd Bergmann 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
414*67207b96SArnd Bergmann 	sb->s_magic = SPUFS_MAGIC;
415*67207b96SArnd Bergmann 	sb->s_op = &s_ops;
416*67207b96SArnd Bergmann 
417*67207b96SArnd Bergmann 	return spufs_create_root(sb, data);
418*67207b96SArnd Bergmann }
419*67207b96SArnd Bergmann 
420*67207b96SArnd Bergmann static struct super_block *
421*67207b96SArnd Bergmann spufs_get_sb(struct file_system_type *fstype, int flags,
422*67207b96SArnd Bergmann 		const char *name, void *data)
423*67207b96SArnd Bergmann {
424*67207b96SArnd Bergmann 	return get_sb_single(fstype, flags, data, spufs_fill_super);
425*67207b96SArnd Bergmann }
426*67207b96SArnd Bergmann 
427*67207b96SArnd Bergmann static struct file_system_type spufs_type = {
428*67207b96SArnd Bergmann 	.owner = THIS_MODULE,
429*67207b96SArnd Bergmann 	.name = "spufs",
430*67207b96SArnd Bergmann 	.get_sb = spufs_get_sb,
431*67207b96SArnd Bergmann 	.kill_sb = kill_litter_super,
432*67207b96SArnd Bergmann };
433*67207b96SArnd Bergmann 
434*67207b96SArnd Bergmann static int spufs_init(void)
435*67207b96SArnd Bergmann {
436*67207b96SArnd Bergmann 	int ret;
437*67207b96SArnd Bergmann 	ret = -ENOMEM;
438*67207b96SArnd Bergmann 	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
439*67207b96SArnd Bergmann 			sizeof(struct spufs_inode_info), 0,
440*67207b96SArnd Bergmann 			SLAB_HWCACHE_ALIGN, spufs_init_once, NULL);
441*67207b96SArnd Bergmann 
442*67207b96SArnd Bergmann 	if (!spufs_inode_cache)
443*67207b96SArnd Bergmann 		goto out;
444*67207b96SArnd Bergmann 	ret = register_filesystem(&spufs_type);
445*67207b96SArnd Bergmann 	if (ret)
446*67207b96SArnd Bergmann 		goto out_cache;
447*67207b96SArnd Bergmann 	ret = register_spu_syscalls(&spufs_calls);
448*67207b96SArnd Bergmann 	if (ret)
449*67207b96SArnd Bergmann 		goto out_fs;
450*67207b96SArnd Bergmann 	return 0;
451*67207b96SArnd Bergmann out_fs:
452*67207b96SArnd Bergmann 	unregister_filesystem(&spufs_type);
453*67207b96SArnd Bergmann out_cache:
454*67207b96SArnd Bergmann 	kmem_cache_destroy(spufs_inode_cache);
455*67207b96SArnd Bergmann out:
456*67207b96SArnd Bergmann 	return ret;
457*67207b96SArnd Bergmann }
458*67207b96SArnd Bergmann module_init(spufs_init);
459*67207b96SArnd Bergmann 
460*67207b96SArnd Bergmann static void spufs_exit(void)
461*67207b96SArnd Bergmann {
462*67207b96SArnd Bergmann 	unregister_spu_syscalls(&spufs_calls);
463*67207b96SArnd Bergmann 	unregister_filesystem(&spufs_type);
464*67207b96SArnd Bergmann 	kmem_cache_destroy(spufs_inode_cache);
465*67207b96SArnd Bergmann }
466*67207b96SArnd Bergmann module_exit(spufs_exit);
467*67207b96SArnd Bergmann 
468*67207b96SArnd Bergmann MODULE_LICENSE("GPL");
469*67207b96SArnd Bergmann MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
470*67207b96SArnd Bergmann 
471