xref: /openbmc/linux/fs/fuse/inode.c (revision e5e5558e)
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;
54e5e5558eSMiklos Szeredi 	fi->forget_req = fuse_request_alloc();
55e5e5558eSMiklos Szeredi 	if (!fi->forget_req) {
56e5e5558eSMiklos Szeredi 		kmem_cache_free(fuse_inode_cachep, inode);
57e5e5558eSMiklos Szeredi 		return NULL;
58e5e5558eSMiklos Szeredi 	}
59d8a5ba45SMiklos Szeredi 
60d8a5ba45SMiklos Szeredi 	return inode;
61d8a5ba45SMiklos Szeredi }
62d8a5ba45SMiklos Szeredi 
63d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode)
64d8a5ba45SMiklos Szeredi {
65e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
66e5e5558eSMiklos Szeredi 	if (fi->forget_req)
67e5e5558eSMiklos Szeredi 		fuse_request_free(fi->forget_req);
68d8a5ba45SMiklos Szeredi 	kmem_cache_free(fuse_inode_cachep, inode);
69d8a5ba45SMiklos Szeredi }
70d8a5ba45SMiklos Szeredi 
71d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode)
72d8a5ba45SMiklos Szeredi {
73d8a5ba45SMiklos Szeredi 	/* No op */
74d8a5ba45SMiklos Szeredi }
75d8a5ba45SMiklos Szeredi 
76e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
77e5e5558eSMiklos Szeredi 		      unsigned long nodeid, int version)
78e5e5558eSMiklos Szeredi {
79e5e5558eSMiklos Szeredi 	struct fuse_forget_in *inarg = &req->misc.forget_in;
80e5e5558eSMiklos Szeredi 	inarg->version = version;
81e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_FORGET;
82e5e5558eSMiklos Szeredi 	req->in.h.nodeid = nodeid;
83e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
84e5e5558eSMiklos Szeredi 	req->in.args[0].size = sizeof(struct fuse_forget_in);
85e5e5558eSMiklos Szeredi 	req->in.args[0].value = inarg;
86e5e5558eSMiklos Szeredi 	request_send_noreply(fc, req);
87e5e5558eSMiklos Szeredi }
88e5e5558eSMiklos Szeredi 
89d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode)
90d8a5ba45SMiklos Szeredi {
91e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
92e5e5558eSMiklos Szeredi 	if (fc) {
93e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
94e5e5558eSMiklos Szeredi 		fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
95e5e5558eSMiklos Szeredi 		fi->forget_req = NULL;
96e5e5558eSMiklos Szeredi 	}
97d8a5ba45SMiklos Szeredi }
98d8a5ba45SMiklos Szeredi 
99d8a5ba45SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
100d8a5ba45SMiklos Szeredi {
101d8a5ba45SMiklos Szeredi 	if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
102d8a5ba45SMiklos Szeredi 		invalidate_inode_pages(inode->i_mapping);
103d8a5ba45SMiklos Szeredi 
104d8a5ba45SMiklos Szeredi 	inode->i_ino     = attr->ino;
105d8a5ba45SMiklos Szeredi 	inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
106d8a5ba45SMiklos Szeredi 	inode->i_nlink   = attr->nlink;
107d8a5ba45SMiklos Szeredi 	inode->i_uid     = attr->uid;
108d8a5ba45SMiklos Szeredi 	inode->i_gid     = attr->gid;
109d8a5ba45SMiklos Szeredi 	i_size_write(inode, attr->size);
110d8a5ba45SMiklos Szeredi 	inode->i_blksize = PAGE_CACHE_SIZE;
111d8a5ba45SMiklos Szeredi 	inode->i_blocks  = attr->blocks;
112d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_sec   = attr->atime;
113d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_nsec  = attr->atimensec;
114d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_sec   = attr->mtime;
115d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_nsec  = attr->mtimensec;
116d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_sec   = attr->ctime;
117d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_nsec  = attr->ctimensec;
118d8a5ba45SMiklos Szeredi }
119d8a5ba45SMiklos Szeredi 
120d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
121d8a5ba45SMiklos Szeredi {
122d8a5ba45SMiklos Szeredi 	inode->i_mode = attr->mode & S_IFMT;
123d8a5ba45SMiklos Szeredi 	i_size_write(inode, attr->size);
124e5e5558eSMiklos Szeredi 	if (S_ISREG(inode->i_mode)) {
125e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
126e5e5558eSMiklos Szeredi 	} else if (S_ISDIR(inode->i_mode))
127e5e5558eSMiklos Szeredi 		fuse_init_dir(inode);
128e5e5558eSMiklos Szeredi 	else if (S_ISLNK(inode->i_mode))
129e5e5558eSMiklos Szeredi 		fuse_init_symlink(inode);
130e5e5558eSMiklos Szeredi 	else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
131e5e5558eSMiklos Szeredi 		 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
132e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
133e5e5558eSMiklos Szeredi 		init_special_inode(inode, inode->i_mode,
134e5e5558eSMiklos Szeredi 				   new_decode_dev(attr->rdev));
135e5e5558eSMiklos Szeredi 	} else {
136e5e5558eSMiklos Szeredi 		/* Don't let user create weird files */
137e5e5558eSMiklos Szeredi 		inode->i_mode = S_IFREG;
138e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
139e5e5558eSMiklos Szeredi 	}
140d8a5ba45SMiklos Szeredi }
141d8a5ba45SMiklos Szeredi 
142d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
143d8a5ba45SMiklos Szeredi {
144d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
145d8a5ba45SMiklos Szeredi 	if (get_node_id(inode) == nodeid)
146d8a5ba45SMiklos Szeredi 		return 1;
147d8a5ba45SMiklos Szeredi 	else
148d8a5ba45SMiklos Szeredi 		return 0;
149d8a5ba45SMiklos Szeredi }
150d8a5ba45SMiklos Szeredi 
151d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp)
152d8a5ba45SMiklos Szeredi {
153d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
154d8a5ba45SMiklos Szeredi 	get_fuse_inode(inode)->nodeid = nodeid;
155d8a5ba45SMiklos Szeredi 	return 0;
156d8a5ba45SMiklos Szeredi }
157d8a5ba45SMiklos Szeredi 
158d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
159d8a5ba45SMiklos Szeredi 			int generation, struct fuse_attr *attr, int version)
160d8a5ba45SMiklos Szeredi {
161d8a5ba45SMiklos Szeredi 	struct inode *inode;
162d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
163d8a5ba45SMiklos Szeredi 	int retried = 0;
164d8a5ba45SMiklos Szeredi 
165d8a5ba45SMiklos Szeredi  retry:
166d8a5ba45SMiklos Szeredi 	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
167d8a5ba45SMiklos Szeredi 	if (!inode)
168d8a5ba45SMiklos Szeredi 		return NULL;
169d8a5ba45SMiklos Szeredi 
170d8a5ba45SMiklos Szeredi 	if ((inode->i_state & I_NEW)) {
171d8a5ba45SMiklos Szeredi 		inode->i_generation = generation;
172d8a5ba45SMiklos Szeredi 		inode->i_data.backing_dev_info = &fc->bdi;
173d8a5ba45SMiklos Szeredi 		fuse_init_inode(inode, attr);
174d8a5ba45SMiklos Szeredi 		unlock_new_inode(inode);
175d8a5ba45SMiklos Szeredi 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
176d8a5ba45SMiklos Szeredi 		BUG_ON(retried);
177d8a5ba45SMiklos Szeredi 		/* Inode has changed type, any I/O on the old should fail */
178d8a5ba45SMiklos Szeredi 		make_bad_inode(inode);
179d8a5ba45SMiklos Szeredi 		iput(inode);
180d8a5ba45SMiklos Szeredi 		retried = 1;
181d8a5ba45SMiklos Szeredi 		goto retry;
182d8a5ba45SMiklos Szeredi 	}
183d8a5ba45SMiklos Szeredi 
184d8a5ba45SMiklos Szeredi 	fuse_change_attributes(inode, attr);
185d8a5ba45SMiklos Szeredi 	inode->i_version = version;
186d8a5ba45SMiklos Szeredi 	return inode;
187d8a5ba45SMiklos Szeredi }
188d8a5ba45SMiklos Szeredi 
189d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb)
190d8a5ba45SMiklos Szeredi {
191d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
192d8a5ba45SMiklos Szeredi 
193d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
194d8a5ba45SMiklos Szeredi 	mount_count --;
195d8a5ba45SMiklos Szeredi 	fc->sb = NULL;
196d8a5ba45SMiklos Szeredi 	fc->user_id = 0;
197334f485dSMiklos Szeredi 	/* Flush all readers on this fs */
198334f485dSMiklos Szeredi 	wake_up_all(&fc->waitq);
199d8a5ba45SMiklos Szeredi 	fuse_release_conn(fc);
200d8a5ba45SMiklos Szeredi 	*get_fuse_conn_super_p(sb) = NULL;
201d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
202d8a5ba45SMiklos Szeredi }
203d8a5ba45SMiklos Szeredi 
204e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
205e5e5558eSMiklos Szeredi {
206e5e5558eSMiklos Szeredi 	stbuf->f_type    = FUSE_SUPER_MAGIC;
207e5e5558eSMiklos Szeredi 	stbuf->f_bsize   = attr->bsize;
208e5e5558eSMiklos Szeredi 	stbuf->f_blocks  = attr->blocks;
209e5e5558eSMiklos Szeredi 	stbuf->f_bfree   = attr->bfree;
210e5e5558eSMiklos Szeredi 	stbuf->f_bavail  = attr->bavail;
211e5e5558eSMiklos Szeredi 	stbuf->f_files   = attr->files;
212e5e5558eSMiklos Szeredi 	stbuf->f_ffree   = attr->ffree;
213e5e5558eSMiklos Szeredi 	stbuf->f_namelen = attr->namelen;
214e5e5558eSMiklos Szeredi 	/* fsid is left zero */
215e5e5558eSMiklos Szeredi }
216e5e5558eSMiklos Szeredi 
217e5e5558eSMiklos Szeredi static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
218e5e5558eSMiklos Szeredi {
219e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
220e5e5558eSMiklos Szeredi 	struct fuse_req *req;
221e5e5558eSMiklos Szeredi 	struct fuse_statfs_out outarg;
222e5e5558eSMiklos Szeredi 	int err;
223e5e5558eSMiklos Szeredi 
224e5e5558eSMiklos Szeredi         req = fuse_get_request(fc);
225e5e5558eSMiklos Szeredi 	if (!req)
226e5e5558eSMiklos Szeredi 		return -ERESTARTSYS;
227e5e5558eSMiklos Szeredi 
228e5e5558eSMiklos Szeredi 	req->in.numargs = 0;
229e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_STATFS;
230e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
231e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
232e5e5558eSMiklos Szeredi 	req->out.args[0].value = &outarg;
233e5e5558eSMiklos Szeredi 	request_send(fc, req);
234e5e5558eSMiklos Szeredi 	err = req->out.h.error;
235e5e5558eSMiklos Szeredi 	if (!err)
236e5e5558eSMiklos Szeredi 		convert_fuse_statfs(buf, &outarg.st);
237e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
238e5e5558eSMiklos Szeredi 	return err;
239e5e5558eSMiklos Szeredi }
240e5e5558eSMiklos Szeredi 
241d8a5ba45SMiklos Szeredi enum {
242d8a5ba45SMiklos Szeredi 	OPT_FD,
243d8a5ba45SMiklos Szeredi 	OPT_ROOTMODE,
244d8a5ba45SMiklos Szeredi 	OPT_USER_ID,
245d8a5ba45SMiklos Szeredi 	OPT_DEFAULT_PERMISSIONS,
246d8a5ba45SMiklos Szeredi 	OPT_ALLOW_OTHER,
247d8a5ba45SMiklos Szeredi 	OPT_ALLOW_ROOT,
248d8a5ba45SMiklos Szeredi 	OPT_KERNEL_CACHE,
249d8a5ba45SMiklos Szeredi 	OPT_ERR
250d8a5ba45SMiklos Szeredi };
251d8a5ba45SMiklos Szeredi 
252d8a5ba45SMiklos Szeredi static match_table_t tokens = {
253d8a5ba45SMiklos Szeredi 	{OPT_FD,			"fd=%u"},
254d8a5ba45SMiklos Szeredi 	{OPT_ROOTMODE,			"rootmode=%o"},
255d8a5ba45SMiklos Szeredi 	{OPT_USER_ID,			"user_id=%u"},
256d8a5ba45SMiklos Szeredi 	{OPT_DEFAULT_PERMISSIONS,	"default_permissions"},
257d8a5ba45SMiklos Szeredi 	{OPT_ALLOW_OTHER,		"allow_other"},
258d8a5ba45SMiklos Szeredi 	{OPT_ALLOW_ROOT,		"allow_root"},
259d8a5ba45SMiklos Szeredi 	{OPT_KERNEL_CACHE,		"kernel_cache"},
260d8a5ba45SMiklos Szeredi 	{OPT_ERR,			NULL}
261d8a5ba45SMiklos Szeredi };
262d8a5ba45SMiklos Szeredi 
263d8a5ba45SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
264d8a5ba45SMiklos Szeredi {
265d8a5ba45SMiklos Szeredi 	char *p;
266d8a5ba45SMiklos Szeredi 	memset(d, 0, sizeof(struct fuse_mount_data));
267d8a5ba45SMiklos Szeredi 	d->fd = -1;
268d8a5ba45SMiklos Szeredi 
269d8a5ba45SMiklos Szeredi 	while ((p = strsep(&opt, ",")) != NULL) {
270d8a5ba45SMiklos Szeredi 		int token;
271d8a5ba45SMiklos Szeredi 		int value;
272d8a5ba45SMiklos Szeredi 		substring_t args[MAX_OPT_ARGS];
273d8a5ba45SMiklos Szeredi 		if (!*p)
274d8a5ba45SMiklos Szeredi 			continue;
275d8a5ba45SMiklos Szeredi 
276d8a5ba45SMiklos Szeredi 		token = match_token(p, tokens, args);
277d8a5ba45SMiklos Szeredi 		switch (token) {
278d8a5ba45SMiklos Szeredi 		case OPT_FD:
279d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
280d8a5ba45SMiklos Szeredi 				return 0;
281d8a5ba45SMiklos Szeredi 			d->fd = value;
282d8a5ba45SMiklos Szeredi 			break;
283d8a5ba45SMiklos Szeredi 
284d8a5ba45SMiklos Szeredi 		case OPT_ROOTMODE:
285d8a5ba45SMiklos Szeredi 			if (match_octal(&args[0], &value))
286d8a5ba45SMiklos Szeredi 				return 0;
287d8a5ba45SMiklos Szeredi 			d->rootmode = value;
288d8a5ba45SMiklos Szeredi 			break;
289d8a5ba45SMiklos Szeredi 
290d8a5ba45SMiklos Szeredi 		case OPT_USER_ID:
291d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
292d8a5ba45SMiklos Szeredi 				return 0;
293d8a5ba45SMiklos Szeredi 			d->user_id = value;
294d8a5ba45SMiklos Szeredi 			break;
295d8a5ba45SMiklos Szeredi 
296d8a5ba45SMiklos Szeredi 		default:
297d8a5ba45SMiklos Szeredi 			return 0;
298d8a5ba45SMiklos Szeredi 		}
299d8a5ba45SMiklos Szeredi 	}
300d8a5ba45SMiklos Szeredi 	if (d->fd == -1)
301d8a5ba45SMiklos Szeredi 		return 0;
302d8a5ba45SMiklos Szeredi 
303d8a5ba45SMiklos Szeredi 	return 1;
304d8a5ba45SMiklos Szeredi }
305d8a5ba45SMiklos Szeredi 
306d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
307d8a5ba45SMiklos Szeredi {
308d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
309d8a5ba45SMiklos Szeredi 
310d8a5ba45SMiklos Szeredi 	seq_printf(m, ",user_id=%u", fc->user_id);
311d8a5ba45SMiklos Szeredi 	return 0;
312d8a5ba45SMiklos Szeredi }
313d8a5ba45SMiklos Szeredi 
314334f485dSMiklos Szeredi static void free_conn(struct fuse_conn *fc)
315334f485dSMiklos Szeredi {
316334f485dSMiklos Szeredi 	while (!list_empty(&fc->unused_list)) {
317334f485dSMiklos Szeredi 		struct fuse_req *req;
318334f485dSMiklos Szeredi 		req = list_entry(fc->unused_list.next, struct fuse_req, list);
319334f485dSMiklos Szeredi 		list_del(&req->list);
320334f485dSMiklos Szeredi 		fuse_request_free(req);
321334f485dSMiklos Szeredi 	}
322334f485dSMiklos Szeredi 	kfree(fc);
323334f485dSMiklos Szeredi }
324334f485dSMiklos Szeredi 
325334f485dSMiklos Szeredi /* Must be called with the fuse lock held */
326d8a5ba45SMiklos Szeredi void fuse_release_conn(struct fuse_conn *fc)
327d8a5ba45SMiklos Szeredi {
328334f485dSMiklos Szeredi 	if (!fc->sb && !fc->file)
329334f485dSMiklos Szeredi 		free_conn(fc);
330d8a5ba45SMiklos Szeredi }
331d8a5ba45SMiklos Szeredi 
332d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void)
333d8a5ba45SMiklos Szeredi {
334d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
335d8a5ba45SMiklos Szeredi 
336d8a5ba45SMiklos Szeredi 	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
337d8a5ba45SMiklos Szeredi 	if (fc != NULL) {
338334f485dSMiklos Szeredi 		int i;
339d8a5ba45SMiklos Szeredi 		memset(fc, 0, sizeof(*fc));
340d8a5ba45SMiklos Szeredi 		fc->sb = NULL;
341334f485dSMiklos Szeredi 		fc->file = NULL;
342d8a5ba45SMiklos Szeredi 		fc->user_id = 0;
343334f485dSMiklos Szeredi 		init_waitqueue_head(&fc->waitq);
344334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->pending);
345334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->processing);
346334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->unused_list);
347334f485dSMiklos Szeredi 		sema_init(&fc->outstanding_sem, 0);
348334f485dSMiklos Szeredi 		for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
349334f485dSMiklos Szeredi 			struct fuse_req *req = fuse_request_alloc();
350334f485dSMiklos Szeredi 			if (!req) {
351334f485dSMiklos Szeredi 				free_conn(fc);
352334f485dSMiklos Szeredi 				return NULL;
353334f485dSMiklos Szeredi 			}
354334f485dSMiklos Szeredi 			list_add(&req->list, &fc->unused_list);
355334f485dSMiklos Szeredi 		}
356d8a5ba45SMiklos Szeredi 		fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
357d8a5ba45SMiklos Szeredi 		fc->bdi.unplug_io_fn = default_unplug_io_fn;
358334f485dSMiklos Szeredi 		fc->reqctr = 0;
359d8a5ba45SMiklos Szeredi 	}
360d8a5ba45SMiklos Szeredi 	return fc;
361d8a5ba45SMiklos Szeredi }
362d8a5ba45SMiklos Szeredi 
363d8a5ba45SMiklos Szeredi static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
364d8a5ba45SMiklos Szeredi {
365d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
366d8a5ba45SMiklos Szeredi 
367334f485dSMiklos Szeredi 	if (file->f_op != &fuse_dev_operations)
368334f485dSMiklos Szeredi 		return ERR_PTR(-EINVAL);
369d8a5ba45SMiklos Szeredi 	fc = new_conn();
370d8a5ba45SMiklos Szeredi 	if (fc == NULL)
371334f485dSMiklos Szeredi 		return ERR_PTR(-ENOMEM);
372d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
373334f485dSMiklos Szeredi 	if (file->private_data) {
374334f485dSMiklos Szeredi 		free_conn(fc);
375334f485dSMiklos Szeredi 		fc = ERR_PTR(-EINVAL);
376334f485dSMiklos Szeredi 	} else {
377334f485dSMiklos Szeredi 		file->private_data = fc;
378d8a5ba45SMiklos Szeredi 		fc->sb = sb;
379334f485dSMiklos Szeredi 		fc->file = file;
380334f485dSMiklos Szeredi 	}
381d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
382d8a5ba45SMiklos Szeredi 	return fc;
383d8a5ba45SMiklos Szeredi }
384d8a5ba45SMiklos Szeredi 
385d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
386d8a5ba45SMiklos Szeredi {
387d8a5ba45SMiklos Szeredi 	struct fuse_attr attr;
388d8a5ba45SMiklos Szeredi 	memset(&attr, 0, sizeof(attr));
389d8a5ba45SMiklos Szeredi 
390d8a5ba45SMiklos Szeredi 	attr.mode = mode;
391d8a5ba45SMiklos Szeredi 	attr.ino = FUSE_ROOT_ID;
392d8a5ba45SMiklos Szeredi 	return fuse_iget(sb, 1, 0, &attr, 0);
393d8a5ba45SMiklos Szeredi }
394d8a5ba45SMiklos Szeredi 
395d8a5ba45SMiklos Szeredi static struct super_operations fuse_super_operations = {
396d8a5ba45SMiklos Szeredi 	.alloc_inode    = fuse_alloc_inode,
397d8a5ba45SMiklos Szeredi 	.destroy_inode  = fuse_destroy_inode,
398d8a5ba45SMiklos Szeredi 	.read_inode	= fuse_read_inode,
399d8a5ba45SMiklos Szeredi 	.clear_inode	= fuse_clear_inode,
400d8a5ba45SMiklos Szeredi 	.put_super	= fuse_put_super,
401e5e5558eSMiklos Szeredi 	.statfs		= fuse_statfs,
402d8a5ba45SMiklos Szeredi 	.show_options	= fuse_show_options,
403d8a5ba45SMiklos Szeredi };
404d8a5ba45SMiklos Szeredi 
405d8a5ba45SMiklos Szeredi static int inc_mount_count(void)
406d8a5ba45SMiklos Szeredi {
407d8a5ba45SMiklos Szeredi 	int success = 0;
408d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
409d8a5ba45SMiklos Szeredi 	mount_count ++;
410d8a5ba45SMiklos Szeredi 	if (mount_max == -1 || mount_count <= mount_max)
411d8a5ba45SMiklos Szeredi 		success = 1;
412d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
413d8a5ba45SMiklos Szeredi 	return success;
414d8a5ba45SMiklos Szeredi }
415d8a5ba45SMiklos Szeredi 
416d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent)
417d8a5ba45SMiklos Szeredi {
418d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
419d8a5ba45SMiklos Szeredi 	struct inode *root;
420d8a5ba45SMiklos Szeredi 	struct fuse_mount_data d;
421d8a5ba45SMiklos Szeredi 	struct file *file;
422d8a5ba45SMiklos Szeredi 	int err;
423d8a5ba45SMiklos Szeredi 
424d8a5ba45SMiklos Szeredi 	if (!parse_fuse_opt((char *) data, &d))
425d8a5ba45SMiklos Szeredi 		return -EINVAL;
426d8a5ba45SMiklos Szeredi 
427d8a5ba45SMiklos Szeredi 	sb->s_blocksize = PAGE_CACHE_SIZE;
428d8a5ba45SMiklos Szeredi 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
429d8a5ba45SMiklos Szeredi 	sb->s_magic = FUSE_SUPER_MAGIC;
430d8a5ba45SMiklos Szeredi 	sb->s_op = &fuse_super_operations;
431d8a5ba45SMiklos Szeredi 	sb->s_maxbytes = MAX_LFS_FILESIZE;
432d8a5ba45SMiklos Szeredi 
433d8a5ba45SMiklos Szeredi 	file = fget(d.fd);
434d8a5ba45SMiklos Szeredi 	if (!file)
435d8a5ba45SMiklos Szeredi 		return -EINVAL;
436d8a5ba45SMiklos Szeredi 
437d8a5ba45SMiklos Szeredi 	fc = get_conn(file, sb);
438d8a5ba45SMiklos Szeredi 	fput(file);
439334f485dSMiklos Szeredi 	if (IS_ERR(fc))
440334f485dSMiklos Szeredi 		return PTR_ERR(fc);
441d8a5ba45SMiklos Szeredi 
442d8a5ba45SMiklos Szeredi 	fc->user_id = d.user_id;
443d8a5ba45SMiklos Szeredi 
444d8a5ba45SMiklos Szeredi 	*get_fuse_conn_super_p(sb) = fc;
445d8a5ba45SMiklos Szeredi 
446d8a5ba45SMiklos Szeredi 	err = -ENFILE;
447d8a5ba45SMiklos Szeredi 	if (!inc_mount_count() && current->uid != 0)
448d8a5ba45SMiklos Szeredi 		goto err;
449d8a5ba45SMiklos Szeredi 
450d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
451d8a5ba45SMiklos Szeredi 	root = get_root_inode(sb, d.rootmode);
452d8a5ba45SMiklos Szeredi 	if (root == NULL)
453d8a5ba45SMiklos Szeredi 		goto err;
454d8a5ba45SMiklos Szeredi 
455d8a5ba45SMiklos Szeredi 	sb->s_root = d_alloc_root(root);
456d8a5ba45SMiklos Szeredi 	if (!sb->s_root) {
457d8a5ba45SMiklos Szeredi 		iput(root);
458d8a5ba45SMiklos Szeredi 		goto err;
459d8a5ba45SMiklos Szeredi 	}
460334f485dSMiklos Szeredi 	fuse_send_init(fc);
461d8a5ba45SMiklos Szeredi 	return 0;
462d8a5ba45SMiklos Szeredi 
463d8a5ba45SMiklos Szeredi  err:
464d8a5ba45SMiklos Szeredi 	spin_lock(&fuse_lock);
465d8a5ba45SMiklos Szeredi 	mount_count --;
466d8a5ba45SMiklos Szeredi 	fc->sb = NULL;
467d8a5ba45SMiklos Szeredi 	fuse_release_conn(fc);
468d8a5ba45SMiklos Szeredi 	spin_unlock(&fuse_lock);
469d8a5ba45SMiklos Szeredi 	*get_fuse_conn_super_p(sb) = NULL;
470d8a5ba45SMiklos Szeredi 	return err;
471d8a5ba45SMiklos Szeredi }
472d8a5ba45SMiklos Szeredi 
473d8a5ba45SMiklos Szeredi static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
474d8a5ba45SMiklos Szeredi 				       int flags, const char *dev_name,
475d8a5ba45SMiklos Szeredi 				       void *raw_data)
476d8a5ba45SMiklos Szeredi {
477d8a5ba45SMiklos Szeredi 	return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
478d8a5ba45SMiklos Szeredi }
479d8a5ba45SMiklos Szeredi 
480d8a5ba45SMiklos Szeredi static struct file_system_type fuse_fs_type = {
481d8a5ba45SMiklos Szeredi 	.owner		= THIS_MODULE,
482d8a5ba45SMiklos Szeredi 	.name		= "fuse",
483d8a5ba45SMiklos Szeredi 	.get_sb		= fuse_get_sb,
484d8a5ba45SMiklos Szeredi 	.kill_sb	= kill_anon_super,
485d8a5ba45SMiklos Szeredi };
486d8a5ba45SMiklos Szeredi 
487d8a5ba45SMiklos Szeredi static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
488d8a5ba45SMiklos Szeredi 				 unsigned long flags)
489d8a5ba45SMiklos Szeredi {
490d8a5ba45SMiklos Szeredi 	struct inode * inode = foo;
491d8a5ba45SMiklos Szeredi 
492d8a5ba45SMiklos Szeredi 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
493d8a5ba45SMiklos Szeredi 	    SLAB_CTOR_CONSTRUCTOR)
494d8a5ba45SMiklos Szeredi 		inode_init_once(inode);
495d8a5ba45SMiklos Szeredi }
496d8a5ba45SMiklos Szeredi 
497d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void)
498d8a5ba45SMiklos Szeredi {
499d8a5ba45SMiklos Szeredi 	int err;
500d8a5ba45SMiklos Szeredi 
501d8a5ba45SMiklos Szeredi 	err = register_filesystem(&fuse_fs_type);
502d8a5ba45SMiklos Szeredi 	if (err)
503d8a5ba45SMiklos Szeredi 		printk("fuse: failed to register filesystem\n");
504d8a5ba45SMiklos Szeredi 	else {
505d8a5ba45SMiklos Szeredi 		fuse_inode_cachep = kmem_cache_create("fuse_inode",
506d8a5ba45SMiklos Szeredi 						      sizeof(struct fuse_inode),
507d8a5ba45SMiklos Szeredi 						      0, SLAB_HWCACHE_ALIGN,
508d8a5ba45SMiklos Szeredi 						      fuse_inode_init_once, NULL);
509d8a5ba45SMiklos Szeredi 		if (!fuse_inode_cachep) {
510d8a5ba45SMiklos Szeredi 			unregister_filesystem(&fuse_fs_type);
511d8a5ba45SMiklos Szeredi 			err = -ENOMEM;
512d8a5ba45SMiklos Szeredi 		}
513d8a5ba45SMiklos Szeredi 	}
514d8a5ba45SMiklos Szeredi 
515d8a5ba45SMiklos Szeredi 	return err;
516d8a5ba45SMiklos Szeredi }
517d8a5ba45SMiklos Szeredi 
518d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void)
519d8a5ba45SMiklos Szeredi {
520d8a5ba45SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
521d8a5ba45SMiklos Szeredi 	kmem_cache_destroy(fuse_inode_cachep);
522d8a5ba45SMiklos Szeredi }
523d8a5ba45SMiklos Szeredi 
524d8a5ba45SMiklos Szeredi static int __init fuse_init(void)
525d8a5ba45SMiklos Szeredi {
526d8a5ba45SMiklos Szeredi 	int res;
527d8a5ba45SMiklos Szeredi 
528d8a5ba45SMiklos Szeredi 	printk("fuse init (API version %i.%i)\n",
529d8a5ba45SMiklos Szeredi 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
530d8a5ba45SMiklos Szeredi 
531d8a5ba45SMiklos Szeredi 	spin_lock_init(&fuse_lock);
532d8a5ba45SMiklos Szeredi 	res = fuse_fs_init();
533d8a5ba45SMiklos Szeredi 	if (res)
534d8a5ba45SMiklos Szeredi 		goto err;
535d8a5ba45SMiklos Szeredi 
536334f485dSMiklos Szeredi 	res = fuse_dev_init();
537334f485dSMiklos Szeredi 	if (res)
538334f485dSMiklos Szeredi 		goto err_fs_cleanup;
539334f485dSMiklos Szeredi 
540d8a5ba45SMiklos Szeredi 	return 0;
541d8a5ba45SMiklos Szeredi 
542334f485dSMiklos Szeredi  err_fs_cleanup:
543334f485dSMiklos Szeredi 	fuse_fs_cleanup();
544d8a5ba45SMiklos Szeredi  err:
545d8a5ba45SMiklos Szeredi 	return res;
546d8a5ba45SMiklos Szeredi }
547d8a5ba45SMiklos Szeredi 
548d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void)
549d8a5ba45SMiklos Szeredi {
550d8a5ba45SMiklos Szeredi 	printk(KERN_DEBUG "fuse exit\n");
551d8a5ba45SMiklos Szeredi 
552d8a5ba45SMiklos Szeredi 	fuse_fs_cleanup();
553334f485dSMiklos Szeredi 	fuse_dev_cleanup();
554d8a5ba45SMiklos Szeredi }
555d8a5ba45SMiklos Szeredi 
556d8a5ba45SMiklos Szeredi module_init(fuse_init);
557d8a5ba45SMiklos Szeredi module_exit(fuse_exit);
558