xref: /openbmc/linux/fs/fuse/inode.c (revision 334f485d)
1d8a5ba45SMiklos Szeredi /*
2d8a5ba45SMiklos Szeredi   FUSE: Filesystem in Userspace
3d8a5ba45SMiklos Szeredi   Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
4d8a5ba45SMiklos Szeredi 
5d8a5ba45SMiklos Szeredi   This program can be distributed under the terms of the GNU GPL.
6d8a5ba45SMiklos Szeredi   See the file COPYING.
7d8a5ba45SMiklos Szeredi */
8d8a5ba45SMiklos Szeredi 
9d8a5ba45SMiklos Szeredi #include "fuse_i.h"
10d8a5ba45SMiklos Szeredi 
11d8a5ba45SMiklos Szeredi #include <linux/pagemap.h>
12d8a5ba45SMiklos Szeredi #include <linux/slab.h>
13d8a5ba45SMiklos Szeredi #include <linux/file.h>
14d8a5ba45SMiklos Szeredi #include <linux/mount.h>
15d8a5ba45SMiklos Szeredi #include <linux/seq_file.h>
16d8a5ba45SMiklos Szeredi #include <linux/init.h>
17d8a5ba45SMiklos Szeredi #include <linux/module.h>
18d8a5ba45SMiklos Szeredi #include <linux/moduleparam.h>
19d8a5ba45SMiklos Szeredi #include <linux/parser.h>
20d8a5ba45SMiklos Szeredi #include <linux/statfs.h>
21d8a5ba45SMiklos Szeredi 
22d8a5ba45SMiklos Szeredi MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
23d8a5ba45SMiklos Szeredi MODULE_DESCRIPTION("Filesystem in Userspace");
24d8a5ba45SMiklos Szeredi MODULE_LICENSE("GPL");
25d8a5ba45SMiklos Szeredi 
26d8a5ba45SMiklos Szeredi spinlock_t fuse_lock;
27d8a5ba45SMiklos Szeredi static kmem_cache_t *fuse_inode_cachep;
28d8a5ba45SMiklos Szeredi static int mount_count;
29d8a5ba45SMiklos Szeredi 
30d8a5ba45SMiklos Szeredi static int mount_max = 1000;
31d8a5ba45SMiklos Szeredi module_param(mount_max, int, 0644);
32d8a5ba45SMiklos Szeredi MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)");
33d8a5ba45SMiklos Szeredi 
34d8a5ba45SMiklos Szeredi #define FUSE_SUPER_MAGIC 0x65735546
35d8a5ba45SMiklos Szeredi 
36d8a5ba45SMiklos Szeredi struct fuse_mount_data {
37d8a5ba45SMiklos Szeredi 	int fd;
38d8a5ba45SMiklos Szeredi 	unsigned rootmode;
39d8a5ba45SMiklos Szeredi 	unsigned user_id;
40d8a5ba45SMiklos Szeredi };
41d8a5ba45SMiklos Szeredi 
42d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb)
43d8a5ba45SMiklos Szeredi {
44d8a5ba45SMiklos Szeredi 	struct inode *inode;
45d8a5ba45SMiklos Szeredi 	struct fuse_inode *fi;
46d8a5ba45SMiklos Szeredi 
47d8a5ba45SMiklos Szeredi 	inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
48d8a5ba45SMiklos Szeredi 	if (!inode)
49d8a5ba45SMiklos Szeredi 		return NULL;
50d8a5ba45SMiklos Szeredi 
51d8a5ba45SMiklos Szeredi 	fi = get_fuse_inode(inode);
52d8a5ba45SMiklos Szeredi 	fi->i_time = jiffies - 1;
53d8a5ba45SMiklos Szeredi 	fi->nodeid = 0;
54d8a5ba45SMiklos Szeredi 
55d8a5ba45SMiklos Szeredi 	return inode;
56d8a5ba45SMiklos Szeredi }
57d8a5ba45SMiklos Szeredi 
58d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode)
59d8a5ba45SMiklos Szeredi {
60d8a5ba45SMiklos Szeredi 	kmem_cache_free(fuse_inode_cachep, inode);
61d8a5ba45SMiklos Szeredi }
62d8a5ba45SMiklos Szeredi 
63d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode)
64d8a5ba45SMiklos Szeredi {
65d8a5ba45SMiklos Szeredi 	/* No op */
66d8a5ba45SMiklos Szeredi }
67d8a5ba45SMiklos Szeredi 
68d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode)
69d8a5ba45SMiklos Szeredi {
70d8a5ba45SMiklos Szeredi }
71d8a5ba45SMiklos Szeredi 
72d8a5ba45SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
73d8a5ba45SMiklos Szeredi {
74d8a5ba45SMiklos Szeredi 	if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
75d8a5ba45SMiklos Szeredi 		invalidate_inode_pages(inode->i_mapping);
76d8a5ba45SMiklos Szeredi 
77d8a5ba45SMiklos Szeredi 	inode->i_ino     = attr->ino;
78d8a5ba45SMiklos Szeredi 	inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
79d8a5ba45SMiklos Szeredi 	inode->i_nlink   = attr->nlink;
80d8a5ba45SMiklos Szeredi 	inode->i_uid     = attr->uid;
81d8a5ba45SMiklos Szeredi 	inode->i_gid     = attr->gid;
82d8a5ba45SMiklos Szeredi 	i_size_write(inode, attr->size);
83d8a5ba45SMiklos Szeredi 	inode->i_blksize = PAGE_CACHE_SIZE;
84d8a5ba45SMiklos Szeredi 	inode->i_blocks  = attr->blocks;
85d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_sec   = attr->atime;
86d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_nsec  = attr->atimensec;
87d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_sec   = attr->mtime;
88d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_nsec  = attr->mtimensec;
89d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_sec   = attr->ctime;
90d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_nsec  = attr->ctimensec;
91d8a5ba45SMiklos Szeredi }
92d8a5ba45SMiklos Szeredi 
93d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
94d8a5ba45SMiklos Szeredi {
95d8a5ba45SMiklos Szeredi 	inode->i_mode = attr->mode & S_IFMT;
96d8a5ba45SMiklos Szeredi 	i_size_write(inode, attr->size);
97d8a5ba45SMiklos Szeredi }
98d8a5ba45SMiklos Szeredi 
99d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
100d8a5ba45SMiklos Szeredi {
101d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
102d8a5ba45SMiklos Szeredi 	if (get_node_id(inode) == nodeid)
103d8a5ba45SMiklos Szeredi 		return 1;
104d8a5ba45SMiklos Szeredi 	else
105d8a5ba45SMiklos Szeredi 		return 0;
106d8a5ba45SMiklos Szeredi }
107d8a5ba45SMiklos Szeredi 
108d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp)
109d8a5ba45SMiklos Szeredi {
110d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
111d8a5ba45SMiklos Szeredi 	get_fuse_inode(inode)->nodeid = nodeid;
112d8a5ba45SMiklos Szeredi 	return 0;
113d8a5ba45SMiklos Szeredi }
114d8a5ba45SMiklos Szeredi 
115d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
116d8a5ba45SMiklos Szeredi 			int generation, struct fuse_attr *attr, int version)
117d8a5ba45SMiklos Szeredi {
118d8a5ba45SMiklos Szeredi 	struct inode *inode;
119d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
120d8a5ba45SMiklos Szeredi 	int retried = 0;
121d8a5ba45SMiklos Szeredi 
122d8a5ba45SMiklos Szeredi  retry:
123d8a5ba45SMiklos Szeredi 	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
124d8a5ba45SMiklos Szeredi 	if (!inode)
125d8a5ba45SMiklos Szeredi 		return NULL;
126d8a5ba45SMiklos Szeredi 
127d8a5ba45SMiklos Szeredi 	if ((inode->i_state & I_NEW)) {
128d8a5ba45SMiklos Szeredi 		inode->i_generation = generation;
129d8a5ba45SMiklos Szeredi 		inode->i_data.backing_dev_info = &fc->bdi;
130d8a5ba45SMiklos Szeredi 		fuse_init_inode(inode, attr);
131d8a5ba45SMiklos Szeredi 		unlock_new_inode(inode);
132d8a5ba45SMiklos Szeredi 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
133d8a5ba45SMiklos Szeredi 		BUG_ON(retried);
134d8a5ba45SMiklos Szeredi 		/* Inode has changed type, any I/O on the old should fail */
135d8a5ba45SMiklos Szeredi 		make_bad_inode(inode);
136d8a5ba45SMiklos Szeredi 		iput(inode);
137d8a5ba45SMiklos Szeredi 		retried = 1;
138d8a5ba45SMiklos Szeredi 		goto retry;
139d8a5ba45SMiklos Szeredi 	}
140d8a5ba45SMiklos Szeredi 
141d8a5ba45SMiklos Szeredi 	fuse_change_attributes(inode, attr);
142d8a5ba45SMiklos Szeredi 	inode->i_version = version;
143d8a5ba45SMiklos Szeredi 	return inode;
144d8a5ba45SMiklos Szeredi }
145d8a5ba45SMiklos Szeredi 
146d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb)
147d8a5ba45SMiklos Szeredi {
148d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
149d8a5ba45SMiklos Szeredi 
150d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
151d8a5ba45SMiklos Szeredi 	mount_count --;
152d8a5ba45SMiklos Szeredi 	fc->sb = NULL;
153d8a5ba45SMiklos Szeredi 	fc->user_id = 0;
154*334f485dSMiklos Szeredi 	/* Flush all readers on this fs */
155*334f485dSMiklos Szeredi 	wake_up_all(&fc->waitq);
156d8a5ba45SMiklos Szeredi 	fuse_release_conn(fc);
157d8a5ba45SMiklos Szeredi 	*get_fuse_conn_super_p(sb) = NULL;
158d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
159d8a5ba45SMiklos Szeredi }
160d8a5ba45SMiklos Szeredi 
161d8a5ba45SMiklos Szeredi enum {
162d8a5ba45SMiklos Szeredi 	OPT_FD,
163d8a5ba45SMiklos Szeredi 	OPT_ROOTMODE,
164d8a5ba45SMiklos Szeredi 	OPT_USER_ID,
165d8a5ba45SMiklos Szeredi 	OPT_DEFAULT_PERMISSIONS,
166d8a5ba45SMiklos Szeredi 	OPT_ALLOW_OTHER,
167d8a5ba45SMiklos Szeredi 	OPT_ALLOW_ROOT,
168d8a5ba45SMiklos Szeredi 	OPT_KERNEL_CACHE,
169d8a5ba45SMiklos Szeredi 	OPT_ERR
170d8a5ba45SMiklos Szeredi };
171d8a5ba45SMiklos Szeredi 
172d8a5ba45SMiklos Szeredi static match_table_t tokens = {
173d8a5ba45SMiklos Szeredi 	{OPT_FD,			"fd=%u"},
174d8a5ba45SMiklos Szeredi 	{OPT_ROOTMODE,			"rootmode=%o"},
175d8a5ba45SMiklos Szeredi 	{OPT_USER_ID,			"user_id=%u"},
176d8a5ba45SMiklos Szeredi 	{OPT_DEFAULT_PERMISSIONS,	"default_permissions"},
177d8a5ba45SMiklos Szeredi 	{OPT_ALLOW_OTHER,		"allow_other"},
178d8a5ba45SMiklos Szeredi 	{OPT_ALLOW_ROOT,		"allow_root"},
179d8a5ba45SMiklos Szeredi 	{OPT_KERNEL_CACHE,		"kernel_cache"},
180d8a5ba45SMiklos Szeredi 	{OPT_ERR,			NULL}
181d8a5ba45SMiklos Szeredi };
182d8a5ba45SMiklos Szeredi 
183d8a5ba45SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
184d8a5ba45SMiklos Szeredi {
185d8a5ba45SMiklos Szeredi 	char *p;
186d8a5ba45SMiklos Szeredi 	memset(d, 0, sizeof(struct fuse_mount_data));
187d8a5ba45SMiklos Szeredi 	d->fd = -1;
188d8a5ba45SMiklos Szeredi 
189d8a5ba45SMiklos Szeredi 	while ((p = strsep(&opt, ",")) != NULL) {
190d8a5ba45SMiklos Szeredi 		int token;
191d8a5ba45SMiklos Szeredi 		int value;
192d8a5ba45SMiklos Szeredi 		substring_t args[MAX_OPT_ARGS];
193d8a5ba45SMiklos Szeredi 		if (!*p)
194d8a5ba45SMiklos Szeredi 			continue;
195d8a5ba45SMiklos Szeredi 
196d8a5ba45SMiklos Szeredi 		token = match_token(p, tokens, args);
197d8a5ba45SMiklos Szeredi 		switch (token) {
198d8a5ba45SMiklos Szeredi 		case OPT_FD:
199d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
200d8a5ba45SMiklos Szeredi 				return 0;
201d8a5ba45SMiklos Szeredi 			d->fd = value;
202d8a5ba45SMiklos Szeredi 			break;
203d8a5ba45SMiklos Szeredi 
204d8a5ba45SMiklos Szeredi 		case OPT_ROOTMODE:
205d8a5ba45SMiklos Szeredi 			if (match_octal(&args[0], &value))
206d8a5ba45SMiklos Szeredi 				return 0;
207d8a5ba45SMiklos Szeredi 			d->rootmode = value;
208d8a5ba45SMiklos Szeredi 			break;
209d8a5ba45SMiklos Szeredi 
210d8a5ba45SMiklos Szeredi 		case OPT_USER_ID:
211d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
212d8a5ba45SMiklos Szeredi 				return 0;
213d8a5ba45SMiklos Szeredi 			d->user_id = value;
214d8a5ba45SMiklos Szeredi 			break;
215d8a5ba45SMiklos Szeredi 
216d8a5ba45SMiklos Szeredi 		default:
217d8a5ba45SMiklos Szeredi 			return 0;
218d8a5ba45SMiklos Szeredi 		}
219d8a5ba45SMiklos Szeredi 	}
220d8a5ba45SMiklos Szeredi 	if (d->fd == -1)
221d8a5ba45SMiklos Szeredi 		return 0;
222d8a5ba45SMiklos Szeredi 
223d8a5ba45SMiklos Szeredi 	return 1;
224d8a5ba45SMiklos Szeredi }
225d8a5ba45SMiklos Szeredi 
226d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
227d8a5ba45SMiklos Szeredi {
228d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
229d8a5ba45SMiklos Szeredi 
230d8a5ba45SMiklos Szeredi 	seq_printf(m, ",user_id=%u", fc->user_id);
231d8a5ba45SMiklos Szeredi 	return 0;
232d8a5ba45SMiklos Szeredi }
233d8a5ba45SMiklos Szeredi 
234*334f485dSMiklos Szeredi static void free_conn(struct fuse_conn *fc)
235*334f485dSMiklos Szeredi {
236*334f485dSMiklos Szeredi 	while (!list_empty(&fc->unused_list)) {
237*334f485dSMiklos Szeredi 		struct fuse_req *req;
238*334f485dSMiklos Szeredi 		req = list_entry(fc->unused_list.next, struct fuse_req, list);
239*334f485dSMiklos Szeredi 		list_del(&req->list);
240*334f485dSMiklos Szeredi 		fuse_request_free(req);
241*334f485dSMiklos Szeredi 	}
242*334f485dSMiklos Szeredi 	kfree(fc);
243*334f485dSMiklos Szeredi }
244*334f485dSMiklos Szeredi 
245*334f485dSMiklos Szeredi /* Must be called with the fuse lock held */
246d8a5ba45SMiklos Szeredi void fuse_release_conn(struct fuse_conn *fc)
247d8a5ba45SMiklos Szeredi {
248*334f485dSMiklos Szeredi 	if (!fc->sb && !fc->file)
249*334f485dSMiklos Szeredi 		free_conn(fc);
250d8a5ba45SMiklos Szeredi }
251d8a5ba45SMiklos Szeredi 
252d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void)
253d8a5ba45SMiklos Szeredi {
254d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
255d8a5ba45SMiklos Szeredi 
256d8a5ba45SMiklos Szeredi 	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
257d8a5ba45SMiklos Szeredi 	if (fc != NULL) {
258*334f485dSMiklos Szeredi 		int i;
259d8a5ba45SMiklos Szeredi 		memset(fc, 0, sizeof(*fc));
260d8a5ba45SMiklos Szeredi 		fc->sb = NULL;
261*334f485dSMiklos Szeredi 		fc->file = NULL;
262d8a5ba45SMiklos Szeredi 		fc->user_id = 0;
263*334f485dSMiklos Szeredi 		init_waitqueue_head(&fc->waitq);
264*334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->pending);
265*334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->processing);
266*334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->unused_list);
267*334f485dSMiklos Szeredi 		sema_init(&fc->outstanding_sem, 0);
268*334f485dSMiklos Szeredi 		for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
269*334f485dSMiklos Szeredi 			struct fuse_req *req = fuse_request_alloc();
270*334f485dSMiklos Szeredi 			if (!req) {
271*334f485dSMiklos Szeredi 				free_conn(fc);
272*334f485dSMiklos Szeredi 				return NULL;
273*334f485dSMiklos Szeredi 			}
274*334f485dSMiklos Szeredi 			list_add(&req->list, &fc->unused_list);
275*334f485dSMiklos Szeredi 		}
276d8a5ba45SMiklos Szeredi 		fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
277d8a5ba45SMiklos Szeredi 		fc->bdi.unplug_io_fn = default_unplug_io_fn;
278*334f485dSMiklos Szeredi 		fc->reqctr = 0;
279d8a5ba45SMiklos Szeredi 	}
280d8a5ba45SMiklos Szeredi 	return fc;
281d8a5ba45SMiklos Szeredi }
282d8a5ba45SMiklos Szeredi 
283d8a5ba45SMiklos Szeredi static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
284d8a5ba45SMiklos Szeredi {
285d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
286d8a5ba45SMiklos Szeredi 
287*334f485dSMiklos Szeredi 	if (file->f_op != &fuse_dev_operations)
288*334f485dSMiklos Szeredi 		return ERR_PTR(-EINVAL);
289d8a5ba45SMiklos Szeredi 	fc = new_conn();
290d8a5ba45SMiklos Szeredi 	if (fc == NULL)
291*334f485dSMiklos Szeredi 		return ERR_PTR(-ENOMEM);
292d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
293*334f485dSMiklos Szeredi 	if (file->private_data) {
294*334f485dSMiklos Szeredi 		free_conn(fc);
295*334f485dSMiklos Szeredi 		fc = ERR_PTR(-EINVAL);
296*334f485dSMiklos Szeredi 	} else {
297*334f485dSMiklos Szeredi 		file->private_data = fc;
298d8a5ba45SMiklos Szeredi 		fc->sb = sb;
299*334f485dSMiklos Szeredi 		fc->file = file;
300*334f485dSMiklos Szeredi 	}
301d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
302d8a5ba45SMiklos Szeredi 	return fc;
303d8a5ba45SMiklos Szeredi }
304d8a5ba45SMiklos Szeredi 
305d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
306d8a5ba45SMiklos Szeredi {
307d8a5ba45SMiklos Szeredi 	struct fuse_attr attr;
308d8a5ba45SMiklos Szeredi 	memset(&attr, 0, sizeof(attr));
309d8a5ba45SMiklos Szeredi 
310d8a5ba45SMiklos Szeredi 	attr.mode = mode;
311d8a5ba45SMiklos Szeredi 	attr.ino = FUSE_ROOT_ID;
312d8a5ba45SMiklos Szeredi 	return fuse_iget(sb, 1, 0, &attr, 0);
313d8a5ba45SMiklos Szeredi }
314d8a5ba45SMiklos Szeredi 
315d8a5ba45SMiklos Szeredi static struct super_operations fuse_super_operations = {
316d8a5ba45SMiklos Szeredi 	.alloc_inode    = fuse_alloc_inode,
317d8a5ba45SMiklos Szeredi 	.destroy_inode  = fuse_destroy_inode,
318d8a5ba45SMiklos Szeredi 	.read_inode	= fuse_read_inode,
319d8a5ba45SMiklos Szeredi 	.clear_inode	= fuse_clear_inode,
320d8a5ba45SMiklos Szeredi 	.put_super	= fuse_put_super,
321d8a5ba45SMiklos Szeredi 	.show_options	= fuse_show_options,
322d8a5ba45SMiklos Szeredi };
323d8a5ba45SMiklos Szeredi 
324d8a5ba45SMiklos Szeredi static int inc_mount_count(void)
325d8a5ba45SMiklos Szeredi {
326d8a5ba45SMiklos Szeredi 	int success = 0;
327d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
328d8a5ba45SMiklos Szeredi 	mount_count ++;
329d8a5ba45SMiklos Szeredi 	if (mount_max == -1 || mount_count <= mount_max)
330d8a5ba45SMiklos Szeredi 		success = 1;
331d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
332d8a5ba45SMiklos Szeredi 	return success;
333d8a5ba45SMiklos Szeredi }
334d8a5ba45SMiklos Szeredi 
335d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent)
336d8a5ba45SMiklos Szeredi {
337d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
338d8a5ba45SMiklos Szeredi 	struct inode *root;
339d8a5ba45SMiklos Szeredi 	struct fuse_mount_data d;
340d8a5ba45SMiklos Szeredi 	struct file *file;
341d8a5ba45SMiklos Szeredi 	int err;
342d8a5ba45SMiklos Szeredi 
343d8a5ba45SMiklos Szeredi 	if (!parse_fuse_opt((char *) data, &d))
344d8a5ba45SMiklos Szeredi 		return -EINVAL;
345d8a5ba45SMiklos Szeredi 
346d8a5ba45SMiklos Szeredi 	sb->s_blocksize = PAGE_CACHE_SIZE;
347d8a5ba45SMiklos Szeredi 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
348d8a5ba45SMiklos Szeredi 	sb->s_magic = FUSE_SUPER_MAGIC;
349d8a5ba45SMiklos Szeredi 	sb->s_op = &fuse_super_operations;
350d8a5ba45SMiklos Szeredi 	sb->s_maxbytes = MAX_LFS_FILESIZE;
351d8a5ba45SMiklos Szeredi 
352d8a5ba45SMiklos Szeredi 	file = fget(d.fd);
353d8a5ba45SMiklos Szeredi 	if (!file)
354d8a5ba45SMiklos Szeredi 		return -EINVAL;
355d8a5ba45SMiklos Szeredi 
356d8a5ba45SMiklos Szeredi 	fc = get_conn(file, sb);
357d8a5ba45SMiklos Szeredi 	fput(file);
358*334f485dSMiklos Szeredi 	if (IS_ERR(fc))
359*334f485dSMiklos Szeredi 		return PTR_ERR(fc);
360d8a5ba45SMiklos Szeredi 
361d8a5ba45SMiklos Szeredi 	fc->user_id = d.user_id;
362d8a5ba45SMiklos Szeredi 
363d8a5ba45SMiklos Szeredi 	*get_fuse_conn_super_p(sb) = fc;
364d8a5ba45SMiklos Szeredi 
365d8a5ba45SMiklos Szeredi 	err = -ENFILE;
366d8a5ba45SMiklos Szeredi 	if (!inc_mount_count() && current->uid != 0)
367d8a5ba45SMiklos Szeredi 		goto err;
368d8a5ba45SMiklos Szeredi 
369d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
370d8a5ba45SMiklos Szeredi 	root = get_root_inode(sb, d.rootmode);
371d8a5ba45SMiklos Szeredi 	if (root == NULL)
372d8a5ba45SMiklos Szeredi 		goto err;
373d8a5ba45SMiklos Szeredi 
374d8a5ba45SMiklos Szeredi 	sb->s_root = d_alloc_root(root);
375d8a5ba45SMiklos Szeredi 	if (!sb->s_root) {
376d8a5ba45SMiklos Szeredi 		iput(root);
377d8a5ba45SMiklos Szeredi 		goto err;
378d8a5ba45SMiklos Szeredi 	}
379*334f485dSMiklos Szeredi 	fuse_send_init(fc);
380d8a5ba45SMiklos Szeredi 	return 0;
381d8a5ba45SMiklos Szeredi 
382d8a5ba45SMiklos Szeredi  err:
383d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
384d8a5ba45SMiklos Szeredi 	mount_count --;
385d8a5ba45SMiklos Szeredi 	fc->sb = NULL;
386d8a5ba45SMiklos Szeredi 	fuse_release_conn(fc);
387d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
388d8a5ba45SMiklos Szeredi 	*get_fuse_conn_super_p(sb) = NULL;
389d8a5ba45SMiklos Szeredi 	return err;
390d8a5ba45SMiklos Szeredi }
391d8a5ba45SMiklos Szeredi 
392d8a5ba45SMiklos Szeredi static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
393d8a5ba45SMiklos Szeredi 				       int flags, const char *dev_name,
394d8a5ba45SMiklos Szeredi 				       void *raw_data)
395d8a5ba45SMiklos Szeredi {
396d8a5ba45SMiklos Szeredi 	return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
397d8a5ba45SMiklos Szeredi }
398d8a5ba45SMiklos Szeredi 
399d8a5ba45SMiklos Szeredi static struct file_system_type fuse_fs_type = {
400d8a5ba45SMiklos Szeredi 	.owner		= THIS_MODULE,
401d8a5ba45SMiklos Szeredi 	.name		= "fuse",
402d8a5ba45SMiklos Szeredi 	.get_sb		= fuse_get_sb,
403d8a5ba45SMiklos Szeredi 	.kill_sb	= kill_anon_super,
404d8a5ba45SMiklos Szeredi };
405d8a5ba45SMiklos Szeredi 
406d8a5ba45SMiklos Szeredi static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
407d8a5ba45SMiklos Szeredi 				 unsigned long flags)
408d8a5ba45SMiklos Szeredi {
409d8a5ba45SMiklos Szeredi 	struct inode * inode = foo;
410d8a5ba45SMiklos Szeredi 
411d8a5ba45SMiklos Szeredi 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
412d8a5ba45SMiklos Szeredi 	    SLAB_CTOR_CONSTRUCTOR)
413d8a5ba45SMiklos Szeredi 		inode_init_once(inode);
414d8a5ba45SMiklos Szeredi }
415d8a5ba45SMiklos Szeredi 
416d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void)
417d8a5ba45SMiklos Szeredi {
418d8a5ba45SMiklos Szeredi 	int err;
419d8a5ba45SMiklos Szeredi 
420d8a5ba45SMiklos Szeredi 	err = register_filesystem(&fuse_fs_type);
421d8a5ba45SMiklos Szeredi 	if (err)
422d8a5ba45SMiklos Szeredi 		printk("fuse: failed to register filesystem\n");
423d8a5ba45SMiklos Szeredi 	else {
424d8a5ba45SMiklos Szeredi 		fuse_inode_cachep = kmem_cache_create("fuse_inode",
425d8a5ba45SMiklos Szeredi 						      sizeof(struct fuse_inode),
426d8a5ba45SMiklos Szeredi 						      0, SLAB_HWCACHE_ALIGN,
427d8a5ba45SMiklos Szeredi 						      fuse_inode_init_once, NULL);
428d8a5ba45SMiklos Szeredi 		if (!fuse_inode_cachep) {
429d8a5ba45SMiklos Szeredi 			unregister_filesystem(&fuse_fs_type);
430d8a5ba45SMiklos Szeredi 			err = -ENOMEM;
431d8a5ba45SMiklos Szeredi 		}
432d8a5ba45SMiklos Szeredi 	}
433d8a5ba45SMiklos Szeredi 
434d8a5ba45SMiklos Szeredi 	return err;
435d8a5ba45SMiklos Szeredi }
436d8a5ba45SMiklos Szeredi 
437d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void)
438d8a5ba45SMiklos Szeredi {
439d8a5ba45SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
440d8a5ba45SMiklos Szeredi 	kmem_cache_destroy(fuse_inode_cachep);
441d8a5ba45SMiklos Szeredi }
442d8a5ba45SMiklos Szeredi 
443d8a5ba45SMiklos Szeredi static int __init fuse_init(void)
444d8a5ba45SMiklos Szeredi {
445d8a5ba45SMiklos Szeredi 	int res;
446d8a5ba45SMiklos Szeredi 
447d8a5ba45SMiklos Szeredi 	printk("fuse init (API version %i.%i)\n",
448d8a5ba45SMiklos Szeredi 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
449d8a5ba45SMiklos Szeredi 
450d8a5ba45SMiklos Szeredi 	spin_lock_init(&fuse_lock);
451d8a5ba45SMiklos Szeredi 	res = fuse_fs_init();
452d8a5ba45SMiklos Szeredi 	if (res)
453d8a5ba45SMiklos Szeredi 		goto err;
454d8a5ba45SMiklos Szeredi 
455*334f485dSMiklos Szeredi 	res = fuse_dev_init();
456*334f485dSMiklos Szeredi 	if (res)
457*334f485dSMiklos Szeredi 		goto err_fs_cleanup;
458*334f485dSMiklos Szeredi 
459d8a5ba45SMiklos Szeredi 	return 0;
460d8a5ba45SMiklos Szeredi 
461*334f485dSMiklos Szeredi  err_fs_cleanup:
462*334f485dSMiklos Szeredi 	fuse_fs_cleanup();
463d8a5ba45SMiklos Szeredi  err:
464d8a5ba45SMiklos Szeredi 	return res;
465d8a5ba45SMiklos Szeredi }
466d8a5ba45SMiklos Szeredi 
467d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void)
468d8a5ba45SMiklos Szeredi {
469d8a5ba45SMiklos Szeredi 	printk(KERN_DEBUG "fuse exit\n");
470d8a5ba45SMiklos Szeredi 
471d8a5ba45SMiklos Szeredi 	fuse_fs_cleanup();
472*334f485dSMiklos Szeredi 	fuse_dev_cleanup();
473d8a5ba45SMiklos Szeredi }
474d8a5ba45SMiklos Szeredi 
475d8a5ba45SMiklos Szeredi module_init(fuse_init);
476d8a5ba45SMiklos Szeredi module_exit(fuse_exit);
477