xref: /openbmc/linux/fs/fuse/inode.c (revision b1009979)
1d8a5ba45SMiklos Szeredi /*
2d8a5ba45SMiklos Szeredi   FUSE: Filesystem in Userspace
3d7133114SMiklos Szeredi   Copyright (C) 2001-2006  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/seq_file.h>
15d8a5ba45SMiklos Szeredi #include <linux/init.h>
16d8a5ba45SMiklos Szeredi #include <linux/module.h>
17d8a5ba45SMiklos Szeredi #include <linux/parser.h>
18d8a5ba45SMiklos Szeredi #include <linux/statfs.h>
199c8ef561SMiklos Szeredi #include <linux/random.h>
20e8edc6e0SAlexey Dobriyan #include <linux/sched.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 
26e18b890bSChristoph Lameter static struct kmem_cache *fuse_inode_cachep;
27bafa9654SMiklos Szeredi struct list_head fuse_conn_list;
28bafa9654SMiklos Szeredi DEFINE_MUTEX(fuse_mutex);
29d8a5ba45SMiklos Szeredi 
30d8a5ba45SMiklos Szeredi #define FUSE_SUPER_MAGIC 0x65735546
31d8a5ba45SMiklos Szeredi 
32d8a5ba45SMiklos Szeredi struct fuse_mount_data {
33d8a5ba45SMiklos Szeredi 	int fd;
34d8a5ba45SMiklos Szeredi 	unsigned rootmode;
35d8a5ba45SMiklos Szeredi 	unsigned user_id;
3687729a55SMiklos Szeredi 	unsigned group_id;
375a533682SMiklos Szeredi 	unsigned fd_present : 1;
385a533682SMiklos Szeredi 	unsigned rootmode_present : 1;
395a533682SMiklos Szeredi 	unsigned user_id_present : 1;
405a533682SMiklos Szeredi 	unsigned group_id_present : 1;
411e9a4ed9SMiklos Szeredi 	unsigned flags;
42db50b96cSMiklos Szeredi 	unsigned max_read;
43d8091614SMiklos Szeredi 	unsigned blksize;
44d8a5ba45SMiklos Szeredi };
45d8a5ba45SMiklos Szeredi 
46d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb)
47d8a5ba45SMiklos Szeredi {
48d8a5ba45SMiklos Szeredi 	struct inode *inode;
49d8a5ba45SMiklos Szeredi 	struct fuse_inode *fi;
50d8a5ba45SMiklos Szeredi 
51e94b1766SChristoph Lameter 	inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL);
52d8a5ba45SMiklos Szeredi 	if (!inode)
53d8a5ba45SMiklos Szeredi 		return NULL;
54d8a5ba45SMiklos Szeredi 
55d8a5ba45SMiklos Szeredi 	fi = get_fuse_inode(inode);
560a0898cfSMiklos Szeredi 	fi->i_time = 0;
57d8a5ba45SMiklos Szeredi 	fi->nodeid = 0;
589e6268dbSMiklos Szeredi 	fi->nlookup = 0;
59e5e5558eSMiklos Szeredi 	fi->forget_req = fuse_request_alloc();
60e5e5558eSMiklos Szeredi 	if (!fi->forget_req) {
61e5e5558eSMiklos Szeredi 		kmem_cache_free(fuse_inode_cachep, inode);
62e5e5558eSMiklos Szeredi 		return NULL;
63e5e5558eSMiklos Szeredi 	}
64d8a5ba45SMiklos Szeredi 
65d8a5ba45SMiklos Szeredi 	return inode;
66d8a5ba45SMiklos Szeredi }
67d8a5ba45SMiklos Szeredi 
68d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode)
69d8a5ba45SMiklos Szeredi {
70e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
71e5e5558eSMiklos Szeredi 	if (fi->forget_req)
72e5e5558eSMiklos Szeredi 		fuse_request_free(fi->forget_req);
73d8a5ba45SMiklos Szeredi 	kmem_cache_free(fuse_inode_cachep, inode);
74d8a5ba45SMiklos Szeredi }
75d8a5ba45SMiklos Szeredi 
76d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode)
77d8a5ba45SMiklos Szeredi {
78d8a5ba45SMiklos Szeredi 	/* No op */
79d8a5ba45SMiklos Szeredi }
80d8a5ba45SMiklos Szeredi 
81e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
829e6268dbSMiklos Szeredi 		      unsigned long nodeid, u64 nlookup)
83e5e5558eSMiklos Szeredi {
84e5e5558eSMiklos Szeredi 	struct fuse_forget_in *inarg = &req->misc.forget_in;
859e6268dbSMiklos Szeredi 	inarg->nlookup = nlookup;
86e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_FORGET;
87e5e5558eSMiklos Szeredi 	req->in.h.nodeid = nodeid;
88e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
89e5e5558eSMiklos Szeredi 	req->in.args[0].size = sizeof(struct fuse_forget_in);
90e5e5558eSMiklos Szeredi 	req->in.args[0].value = inarg;
91e5e5558eSMiklos Szeredi 	request_send_noreply(fc, req);
92e5e5558eSMiklos Szeredi }
93e5e5558eSMiklos Szeredi 
94d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode)
95d8a5ba45SMiklos Szeredi {
961e9a4ed9SMiklos Szeredi 	if (inode->i_sb->s_flags & MS_ACTIVE) {
97e5e5558eSMiklos Szeredi 		struct fuse_conn *fc = get_fuse_conn(inode);
98e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
999e6268dbSMiklos Szeredi 		fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
100e5e5558eSMiklos Szeredi 		fi->forget_req = NULL;
101e5e5558eSMiklos Szeredi 	}
102d8a5ba45SMiklos Szeredi }
103d8a5ba45SMiklos Szeredi 
10471421259SMiklos Szeredi static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
10571421259SMiklos Szeredi {
10671421259SMiklos Szeredi 	if (*flags & MS_MANDLOCK)
10771421259SMiklos Szeredi 		return -EINVAL;
10871421259SMiklos Szeredi 
10971421259SMiklos Szeredi 	return 0;
11071421259SMiklos Szeredi }
11171421259SMiklos Szeredi 
112e00d2c2dSMiklos Szeredi static void fuse_truncate(struct address_space *mapping, loff_t offset)
113e00d2c2dSMiklos Szeredi {
114e00d2c2dSMiklos Szeredi 	/* See vmtruncate() */
115e00d2c2dSMiklos Szeredi 	unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
116e00d2c2dSMiklos Szeredi 	truncate_inode_pages(mapping, offset);
117e00d2c2dSMiklos Szeredi 	unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
118e00d2c2dSMiklos Szeredi }
119e00d2c2dSMiklos Szeredi 
120d8a5ba45SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
121d8a5ba45SMiklos Szeredi {
1229ffbb916SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
123e00d2c2dSMiklos Szeredi 	loff_t oldsize;
124d8a5ba45SMiklos Szeredi 
125d8a5ba45SMiklos Szeredi 	inode->i_ino     = attr->ino;
126d8a5ba45SMiklos Szeredi 	inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
127d8a5ba45SMiklos Szeredi 	inode->i_nlink   = attr->nlink;
128d8a5ba45SMiklos Szeredi 	inode->i_uid     = attr->uid;
129d8a5ba45SMiklos Szeredi 	inode->i_gid     = attr->gid;
130d8a5ba45SMiklos Szeredi 	inode->i_blocks  = attr->blocks;
131d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_sec   = attr->atime;
132d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_nsec  = attr->atimensec;
133d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_sec   = attr->mtime;
134d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_nsec  = attr->mtimensec;
135d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_sec   = attr->ctime;
136d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_nsec  = attr->ctimensec;
137e00d2c2dSMiklos Szeredi 
138e00d2c2dSMiklos Szeredi 	spin_lock(&fc->lock);
139e00d2c2dSMiklos Szeredi 	oldsize = inode->i_size;
140e00d2c2dSMiklos Szeredi 	i_size_write(inode, attr->size);
141e00d2c2dSMiklos Szeredi 	spin_unlock(&fc->lock);
142e00d2c2dSMiklos Szeredi 
143e00d2c2dSMiklos Szeredi 	if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
144e00d2c2dSMiklos Szeredi 		if (attr->size < oldsize)
145e00d2c2dSMiklos Szeredi 			fuse_truncate(inode->i_mapping, attr->size);
146b1009979SMiklos Szeredi 		invalidate_inode_pages2(inode->i_mapping);
147e00d2c2dSMiklos Szeredi 	}
148d8a5ba45SMiklos Szeredi }
149d8a5ba45SMiklos Szeredi 
150d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
151d8a5ba45SMiklos Szeredi {
152d8a5ba45SMiklos Szeredi 	inode->i_mode = attr->mode & S_IFMT;
1539ffbb916SMiklos Szeredi 	inode->i_size = attr->size;
154e5e5558eSMiklos Szeredi 	if (S_ISREG(inode->i_mode)) {
155e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
156b6aeadedSMiklos Szeredi 		fuse_init_file_inode(inode);
157e5e5558eSMiklos Szeredi 	} else if (S_ISDIR(inode->i_mode))
158e5e5558eSMiklos Szeredi 		fuse_init_dir(inode);
159e5e5558eSMiklos Szeredi 	else if (S_ISLNK(inode->i_mode))
160e5e5558eSMiklos Szeredi 		fuse_init_symlink(inode);
161e5e5558eSMiklos Szeredi 	else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
162e5e5558eSMiklos Szeredi 		 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
163e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
164e5e5558eSMiklos Szeredi 		init_special_inode(inode, inode->i_mode,
165e5e5558eSMiklos Szeredi 				   new_decode_dev(attr->rdev));
16639ee059aSMiklos Szeredi 	} else
16739ee059aSMiklos Szeredi 		BUG();
168d8a5ba45SMiklos Szeredi }
169d8a5ba45SMiklos Szeredi 
170d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
171d8a5ba45SMiklos Szeredi {
172d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
173d8a5ba45SMiklos Szeredi 	if (get_node_id(inode) == nodeid)
174d8a5ba45SMiklos Szeredi 		return 1;
175d8a5ba45SMiklos Szeredi 	else
176d8a5ba45SMiklos Szeredi 		return 0;
177d8a5ba45SMiklos Szeredi }
178d8a5ba45SMiklos Szeredi 
179d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp)
180d8a5ba45SMiklos Szeredi {
181d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
182d8a5ba45SMiklos Szeredi 	get_fuse_inode(inode)->nodeid = nodeid;
183d8a5ba45SMiklos Szeredi 	return 0;
184d8a5ba45SMiklos Szeredi }
185d8a5ba45SMiklos Szeredi 
186d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
1879e6268dbSMiklos Szeredi 			int generation, struct fuse_attr *attr)
188d8a5ba45SMiklos Szeredi {
189d8a5ba45SMiklos Szeredi 	struct inode *inode;
1909e6268dbSMiklos Szeredi 	struct fuse_inode *fi;
191d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
192d8a5ba45SMiklos Szeredi 
193d8a5ba45SMiklos Szeredi  retry:
194d8a5ba45SMiklos Szeredi 	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
195d8a5ba45SMiklos Szeredi 	if (!inode)
196d8a5ba45SMiklos Szeredi 		return NULL;
197d8a5ba45SMiklos Szeredi 
198d8a5ba45SMiklos Szeredi 	if ((inode->i_state & I_NEW)) {
199b36c31baSMiklos Szeredi 		inode->i_flags |= S_NOATIME|S_NOCMTIME;
200d8a5ba45SMiklos Szeredi 		inode->i_generation = generation;
201d8a5ba45SMiklos Szeredi 		inode->i_data.backing_dev_info = &fc->bdi;
202d8a5ba45SMiklos Szeredi 		fuse_init_inode(inode, attr);
203d8a5ba45SMiklos Szeredi 		unlock_new_inode(inode);
204d8a5ba45SMiklos Szeredi 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
205d8a5ba45SMiklos Szeredi 		/* Inode has changed type, any I/O on the old should fail */
206d8a5ba45SMiklos Szeredi 		make_bad_inode(inode);
207d8a5ba45SMiklos Szeredi 		iput(inode);
208d8a5ba45SMiklos Szeredi 		goto retry;
209d8a5ba45SMiklos Szeredi 	}
210d8a5ba45SMiklos Szeredi 
2119e6268dbSMiklos Szeredi 	fi = get_fuse_inode(inode);
2128da5ff23SMiklos Szeredi 	spin_lock(&fc->lock);
2139e6268dbSMiklos Szeredi 	fi->nlookup ++;
2148da5ff23SMiklos Szeredi 	spin_unlock(&fc->lock);
215d8a5ba45SMiklos Szeredi 	fuse_change_attributes(inode, attr);
216d8a5ba45SMiklos Szeredi 	return inode;
217d8a5ba45SMiklos Szeredi }
218d8a5ba45SMiklos Szeredi 
2198b512d9aSTrond Myklebust static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
22069a53bf2SMiklos Szeredi {
2218b512d9aSTrond Myklebust 	if (flags & MNT_FORCE)
2228b512d9aSTrond Myklebust 		fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
22369a53bf2SMiklos Szeredi }
22469a53bf2SMiklos Szeredi 
2250ec7ca41SMiklos Szeredi static void fuse_send_destroy(struct fuse_conn *fc)
2260ec7ca41SMiklos Szeredi {
2270ec7ca41SMiklos Szeredi 	struct fuse_req *req = fc->destroy_req;
2280ec7ca41SMiklos Szeredi 	if (req && fc->conn_init) {
2290ec7ca41SMiklos Szeredi 		fc->destroy_req = NULL;
2300ec7ca41SMiklos Szeredi 		req->in.h.opcode = FUSE_DESTROY;
2310ec7ca41SMiklos Szeredi 		req->force = 1;
2320ec7ca41SMiklos Szeredi 		request_send(fc, req);
2330ec7ca41SMiklos Szeredi 		fuse_put_request(fc, req);
2340ec7ca41SMiklos Szeredi 	}
2350ec7ca41SMiklos Szeredi }
2360ec7ca41SMiklos Szeredi 
237d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb)
238d8a5ba45SMiklos Szeredi {
239d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
240d8a5ba45SMiklos Szeredi 
2410ec7ca41SMiklos Szeredi 	fuse_send_destroy(fc);
242d7133114SMiklos Szeredi 	spin_lock(&fc->lock);
2439ba7cbbaSMiklos Szeredi 	fc->connected = 0;
24451eb01e7SMiklos Szeredi 	fc->blocked = 0;
245d7133114SMiklos Szeredi 	spin_unlock(&fc->lock);
246334f485dSMiklos Szeredi 	/* Flush all readers on this fs */
247385a17bfSJeff Dike 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
248334f485dSMiklos Szeredi 	wake_up_all(&fc->waitq);
24951eb01e7SMiklos Szeredi 	wake_up_all(&fc->blocked_waitq);
250de5e3decSMiklos Szeredi 	wake_up_all(&fc->reserved_req_waitq);
251bafa9654SMiklos Szeredi 	mutex_lock(&fuse_mutex);
252bafa9654SMiklos Szeredi 	list_del(&fc->entry);
253bafa9654SMiklos Szeredi 	fuse_ctl_remove_conn(fc);
254bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
255bafa9654SMiklos Szeredi 	fuse_conn_put(fc);
256d8a5ba45SMiklos Szeredi }
257d8a5ba45SMiklos Szeredi 
258e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
259e5e5558eSMiklos Szeredi {
260e5e5558eSMiklos Szeredi 	stbuf->f_type    = FUSE_SUPER_MAGIC;
261e5e5558eSMiklos Szeredi 	stbuf->f_bsize   = attr->bsize;
262de5f1202SMiklos Szeredi 	stbuf->f_frsize  = attr->frsize;
263e5e5558eSMiklos Szeredi 	stbuf->f_blocks  = attr->blocks;
264e5e5558eSMiklos Szeredi 	stbuf->f_bfree   = attr->bfree;
265e5e5558eSMiklos Szeredi 	stbuf->f_bavail  = attr->bavail;
266e5e5558eSMiklos Szeredi 	stbuf->f_files   = attr->files;
267e5e5558eSMiklos Szeredi 	stbuf->f_ffree   = attr->ffree;
268e5e5558eSMiklos Szeredi 	stbuf->f_namelen = attr->namelen;
269e5e5558eSMiklos Szeredi 	/* fsid is left zero */
270e5e5558eSMiklos Szeredi }
271e5e5558eSMiklos Szeredi 
272726c3342SDavid Howells static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
273e5e5558eSMiklos Szeredi {
274726c3342SDavid Howells 	struct super_block *sb = dentry->d_sb;
275e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
276e5e5558eSMiklos Szeredi 	struct fuse_req *req;
277e5e5558eSMiklos Szeredi 	struct fuse_statfs_out outarg;
278e5e5558eSMiklos Szeredi 	int err;
279e5e5558eSMiklos Szeredi 
280ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
281ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
282ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
283e5e5558eSMiklos Szeredi 
284de5f1202SMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
285e5e5558eSMiklos Szeredi 	req->in.numargs = 0;
286e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_STATFS;
2875b35e8e5SMiklos Szeredi 	req->in.h.nodeid = get_node_id(dentry->d_inode);
288e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
289de5f1202SMiklos Szeredi 	req->out.args[0].size =
290de5f1202SMiklos Szeredi 		fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
291e5e5558eSMiklos Szeredi 	req->out.args[0].value = &outarg;
292e5e5558eSMiklos Szeredi 	request_send(fc, req);
293e5e5558eSMiklos Szeredi 	err = req->out.h.error;
294e5e5558eSMiklos Szeredi 	if (!err)
295e5e5558eSMiklos Szeredi 		convert_fuse_statfs(buf, &outarg.st);
296e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
297e5e5558eSMiklos Szeredi 	return err;
298e5e5558eSMiklos Szeredi }
299e5e5558eSMiklos Szeredi 
300d8a5ba45SMiklos Szeredi enum {
301d8a5ba45SMiklos Szeredi 	OPT_FD,
302d8a5ba45SMiklos Szeredi 	OPT_ROOTMODE,
303d8a5ba45SMiklos Szeredi 	OPT_USER_ID,
30487729a55SMiklos Szeredi 	OPT_GROUP_ID,
305d8a5ba45SMiklos Szeredi 	OPT_DEFAULT_PERMISSIONS,
306d8a5ba45SMiklos Szeredi 	OPT_ALLOW_OTHER,
307db50b96cSMiklos Szeredi 	OPT_MAX_READ,
308d8091614SMiklos Szeredi 	OPT_BLKSIZE,
309d8a5ba45SMiklos Szeredi 	OPT_ERR
310d8a5ba45SMiklos Szeredi };
311d8a5ba45SMiklos Szeredi 
312d8a5ba45SMiklos Szeredi static match_table_t tokens = {
313d8a5ba45SMiklos Szeredi 	{OPT_FD,			"fd=%u"},
314d8a5ba45SMiklos Szeredi 	{OPT_ROOTMODE,			"rootmode=%o"},
315d8a5ba45SMiklos Szeredi 	{OPT_USER_ID,			"user_id=%u"},
31687729a55SMiklos Szeredi 	{OPT_GROUP_ID,			"group_id=%u"},
317d8a5ba45SMiklos Szeredi 	{OPT_DEFAULT_PERMISSIONS,	"default_permissions"},
318d8a5ba45SMiklos Szeredi 	{OPT_ALLOW_OTHER,		"allow_other"},
319db50b96cSMiklos Szeredi 	{OPT_MAX_READ,			"max_read=%u"},
320d8091614SMiklos Szeredi 	{OPT_BLKSIZE,			"blksize=%u"},
321d8a5ba45SMiklos Szeredi 	{OPT_ERR,			NULL}
322d8a5ba45SMiklos Szeredi };
323d8a5ba45SMiklos Szeredi 
324d8091614SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
325d8a5ba45SMiklos Szeredi {
326d8a5ba45SMiklos Szeredi 	char *p;
327d8a5ba45SMiklos Szeredi 	memset(d, 0, sizeof(struct fuse_mount_data));
328db50b96cSMiklos Szeredi 	d->max_read = ~0;
329d8091614SMiklos Szeredi 	d->blksize = 512;
330d8a5ba45SMiklos Szeredi 
331d8a5ba45SMiklos Szeredi 	while ((p = strsep(&opt, ",")) != NULL) {
332d8a5ba45SMiklos Szeredi 		int token;
333d8a5ba45SMiklos Szeredi 		int value;
334d8a5ba45SMiklos Szeredi 		substring_t args[MAX_OPT_ARGS];
335d8a5ba45SMiklos Szeredi 		if (!*p)
336d8a5ba45SMiklos Szeredi 			continue;
337d8a5ba45SMiklos Szeredi 
338d8a5ba45SMiklos Szeredi 		token = match_token(p, tokens, args);
339d8a5ba45SMiklos Szeredi 		switch (token) {
340d8a5ba45SMiklos Szeredi 		case OPT_FD:
341d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
342d8a5ba45SMiklos Szeredi 				return 0;
343d8a5ba45SMiklos Szeredi 			d->fd = value;
3445a533682SMiklos Szeredi 			d->fd_present = 1;
345d8a5ba45SMiklos Szeredi 			break;
346d8a5ba45SMiklos Szeredi 
347d8a5ba45SMiklos Szeredi 		case OPT_ROOTMODE:
348d8a5ba45SMiklos Szeredi 			if (match_octal(&args[0], &value))
349d8a5ba45SMiklos Szeredi 				return 0;
350a5bfffacSTimo Savola 			if (!fuse_valid_type(value))
351a5bfffacSTimo Savola 				return 0;
352d8a5ba45SMiklos Szeredi 			d->rootmode = value;
3535a533682SMiklos Szeredi 			d->rootmode_present = 1;
354d8a5ba45SMiklos Szeredi 			break;
355d8a5ba45SMiklos Szeredi 
356d8a5ba45SMiklos Szeredi 		case OPT_USER_ID:
357d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
358d8a5ba45SMiklos Szeredi 				return 0;
359d8a5ba45SMiklos Szeredi 			d->user_id = value;
3605a533682SMiklos Szeredi 			d->user_id_present = 1;
361d8a5ba45SMiklos Szeredi 			break;
362d8a5ba45SMiklos Szeredi 
36387729a55SMiklos Szeredi 		case OPT_GROUP_ID:
36487729a55SMiklos Szeredi 			if (match_int(&args[0], &value))
36587729a55SMiklos Szeredi 				return 0;
36687729a55SMiklos Szeredi 			d->group_id = value;
3675a533682SMiklos Szeredi 			d->group_id_present = 1;
36887729a55SMiklos Szeredi 			break;
36987729a55SMiklos Szeredi 
3701e9a4ed9SMiklos Szeredi 		case OPT_DEFAULT_PERMISSIONS:
3711e9a4ed9SMiklos Szeredi 			d->flags |= FUSE_DEFAULT_PERMISSIONS;
3721e9a4ed9SMiklos Szeredi 			break;
3731e9a4ed9SMiklos Szeredi 
3741e9a4ed9SMiklos Szeredi 		case OPT_ALLOW_OTHER:
3751e9a4ed9SMiklos Szeredi 			d->flags |= FUSE_ALLOW_OTHER;
3761e9a4ed9SMiklos Szeredi 			break;
3771e9a4ed9SMiklos Szeredi 
378db50b96cSMiklos Szeredi 		case OPT_MAX_READ:
379db50b96cSMiklos Szeredi 			if (match_int(&args[0], &value))
380db50b96cSMiklos Szeredi 				return 0;
381db50b96cSMiklos Szeredi 			d->max_read = value;
382db50b96cSMiklos Szeredi 			break;
383db50b96cSMiklos Szeredi 
384d8091614SMiklos Szeredi 		case OPT_BLKSIZE:
385d8091614SMiklos Szeredi 			if (!is_bdev || match_int(&args[0], &value))
386d8091614SMiklos Szeredi 				return 0;
387d8091614SMiklos Szeredi 			d->blksize = value;
388d8091614SMiklos Szeredi 			break;
389d8091614SMiklos Szeredi 
390d8a5ba45SMiklos Szeredi 		default:
391d8a5ba45SMiklos Szeredi 			return 0;
392d8a5ba45SMiklos Szeredi 		}
393d8a5ba45SMiklos Szeredi 	}
3945a533682SMiklos Szeredi 
3955a533682SMiklos Szeredi 	if (!d->fd_present || !d->rootmode_present ||
3965a533682SMiklos Szeredi 	    !d->user_id_present || !d->group_id_present)
397d8a5ba45SMiklos Szeredi 		return 0;
398d8a5ba45SMiklos Szeredi 
399d8a5ba45SMiklos Szeredi 	return 1;
400d8a5ba45SMiklos Szeredi }
401d8a5ba45SMiklos Szeredi 
402d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
403d8a5ba45SMiklos Szeredi {
404d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
405d8a5ba45SMiklos Szeredi 
406d8a5ba45SMiklos Szeredi 	seq_printf(m, ",user_id=%u", fc->user_id);
40787729a55SMiklos Szeredi 	seq_printf(m, ",group_id=%u", fc->group_id);
4081e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
4091e9a4ed9SMiklos Szeredi 		seq_puts(m, ",default_permissions");
4101e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
4111e9a4ed9SMiklos Szeredi 		seq_puts(m, ",allow_other");
412db50b96cSMiklos Szeredi 	if (fc->max_read != ~0)
413db50b96cSMiklos Szeredi 		seq_printf(m, ",max_read=%u", fc->max_read);
414d8a5ba45SMiklos Szeredi 	return 0;
415d8a5ba45SMiklos Szeredi }
416d8a5ba45SMiklos Szeredi 
417d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void)
418d8a5ba45SMiklos Szeredi {
419d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
420e0bf68ddSPeter Zijlstra 	int err;
421d8a5ba45SMiklos Szeredi 
4226383bdaaSMiklos Szeredi 	fc = kzalloc(sizeof(*fc), GFP_KERNEL);
423f543f253SMiklos Szeredi 	if (fc) {
424d7133114SMiklos Szeredi 		spin_lock_init(&fc->lock);
425d2a85164SMiklos Szeredi 		mutex_init(&fc->inst_mutex);
426bafa9654SMiklos Szeredi 		atomic_set(&fc->count, 1);
427334f485dSMiklos Szeredi 		init_waitqueue_head(&fc->waitq);
42808a53cdcSMiklos Szeredi 		init_waitqueue_head(&fc->blocked_waitq);
429de5e3decSMiklos Szeredi 		init_waitqueue_head(&fc->reserved_req_waitq);
430334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->pending);
431334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->processing);
432d77a1d5bSMiklos Szeredi 		INIT_LIST_HEAD(&fc->io);
433a4d27e75SMiklos Szeredi 		INIT_LIST_HEAD(&fc->interrupts);
434095da6cbSMiklos Szeredi 		atomic_set(&fc->num_waiting, 0);
435d8a5ba45SMiklos Szeredi 		fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
436d8a5ba45SMiklos Szeredi 		fc->bdi.unplug_io_fn = default_unplug_io_fn;
437e0bf68ddSPeter Zijlstra 		err = bdi_init(&fc->bdi);
438e0bf68ddSPeter Zijlstra 		if (err) {
439e0bf68ddSPeter Zijlstra 			kfree(fc);
440e0bf68ddSPeter Zijlstra 			fc = NULL;
441e0bf68ddSPeter Zijlstra 			goto out;
442e0bf68ddSPeter Zijlstra 		}
443334f485dSMiklos Szeredi 		fc->reqctr = 0;
44408a53cdcSMiklos Szeredi 		fc->blocked = 1;
4459c8ef561SMiklos Szeredi 		get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
446d8a5ba45SMiklos Szeredi 	}
447e0bf68ddSPeter Zijlstra out:
448d8a5ba45SMiklos Szeredi 	return fc;
449d8a5ba45SMiklos Szeredi }
450d8a5ba45SMiklos Szeredi 
451bafa9654SMiklos Szeredi void fuse_conn_put(struct fuse_conn *fc)
452bafa9654SMiklos Szeredi {
453d2a85164SMiklos Szeredi 	if (atomic_dec_and_test(&fc->count)) {
4540ec7ca41SMiklos Szeredi 		if (fc->destroy_req)
4550ec7ca41SMiklos Szeredi 			fuse_request_free(fc->destroy_req);
456d2a85164SMiklos Szeredi 		mutex_destroy(&fc->inst_mutex);
457e0bf68ddSPeter Zijlstra 		bdi_destroy(&fc->bdi);
458bafa9654SMiklos Szeredi 		kfree(fc);
459bafa9654SMiklos Szeredi 	}
460d2a85164SMiklos Szeredi }
461bafa9654SMiklos Szeredi 
462bafa9654SMiklos Szeredi struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
463bafa9654SMiklos Szeredi {
464bafa9654SMiklos Szeredi 	atomic_inc(&fc->count);
465bafa9654SMiklos Szeredi 	return fc;
466bafa9654SMiklos Szeredi }
467bafa9654SMiklos Szeredi 
468d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
469d8a5ba45SMiklos Szeredi {
470d8a5ba45SMiklos Szeredi 	struct fuse_attr attr;
471d8a5ba45SMiklos Szeredi 	memset(&attr, 0, sizeof(attr));
472d8a5ba45SMiklos Szeredi 
473d8a5ba45SMiklos Szeredi 	attr.mode = mode;
474d8a5ba45SMiklos Szeredi 	attr.ino = FUSE_ROOT_ID;
4759e6268dbSMiklos Szeredi 	return fuse_iget(sb, 1, 0, &attr);
476d8a5ba45SMiklos Szeredi }
477d8a5ba45SMiklos Szeredi 
478ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = {
479d8a5ba45SMiklos Szeredi 	.alloc_inode    = fuse_alloc_inode,
480d8a5ba45SMiklos Szeredi 	.destroy_inode  = fuse_destroy_inode,
481d8a5ba45SMiklos Szeredi 	.read_inode	= fuse_read_inode,
482d8a5ba45SMiklos Szeredi 	.clear_inode	= fuse_clear_inode,
483ead5f0b5SMiklos Szeredi 	.drop_inode	= generic_delete_inode,
48471421259SMiklos Szeredi 	.remount_fs	= fuse_remount_fs,
485d8a5ba45SMiklos Szeredi 	.put_super	= fuse_put_super,
48669a53bf2SMiklos Szeredi 	.umount_begin	= fuse_umount_begin,
487e5e5558eSMiklos Szeredi 	.statfs		= fuse_statfs,
488d8a5ba45SMiklos Szeredi 	.show_options	= fuse_show_options,
489d8a5ba45SMiklos Szeredi };
490d8a5ba45SMiklos Szeredi 
4919b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
4929b9a0469SMiklos Szeredi {
4939b9a0469SMiklos Szeredi 	struct fuse_init_out *arg = &req->misc.init_out;
4949b9a0469SMiklos Szeredi 
4959b9a0469SMiklos Szeredi 	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
4969b9a0469SMiklos Szeredi 		fc->conn_error = 1;
4979b9a0469SMiklos Szeredi 	else {
4989cd68455SMiklos Szeredi 		unsigned long ra_pages;
4999cd68455SMiklos Szeredi 
5009cd68455SMiklos Szeredi 		if (arg->minor >= 6) {
5019cd68455SMiklos Szeredi 			ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
5029cd68455SMiklos Szeredi 			if (arg->flags & FUSE_ASYNC_READ)
5039cd68455SMiklos Szeredi 				fc->async_read = 1;
50471421259SMiklos Szeredi 			if (!(arg->flags & FUSE_POSIX_LOCKS))
50571421259SMiklos Szeredi 				fc->no_lock = 1;
50671421259SMiklos Szeredi 		} else {
5079cd68455SMiklos Szeredi 			ra_pages = fc->max_read / PAGE_CACHE_SIZE;
50871421259SMiklos Szeredi 			fc->no_lock = 1;
50971421259SMiklos Szeredi 		}
5109cd68455SMiklos Szeredi 
5119cd68455SMiklos Szeredi 		fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
5129b9a0469SMiklos Szeredi 		fc->minor = arg->minor;
5139b9a0469SMiklos Szeredi 		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
5140ec7ca41SMiklos Szeredi 		fc->conn_init = 1;
5159b9a0469SMiklos Szeredi 	}
5169b9a0469SMiklos Szeredi 	fuse_put_request(fc, req);
51708a53cdcSMiklos Szeredi 	fc->blocked = 0;
51808a53cdcSMiklos Szeredi 	wake_up_all(&fc->blocked_waitq);
5199b9a0469SMiklos Szeredi }
5209b9a0469SMiklos Szeredi 
521ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
5229b9a0469SMiklos Szeredi {
5239b9a0469SMiklos Szeredi 	struct fuse_init_in *arg = &req->misc.init_in;
524095da6cbSMiklos Szeredi 
5259b9a0469SMiklos Szeredi 	arg->major = FUSE_KERNEL_VERSION;
5269b9a0469SMiklos Szeredi 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
5279cd68455SMiklos Szeredi 	arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
52871421259SMiklos Szeredi 	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
5299b9a0469SMiklos Szeredi 	req->in.h.opcode = FUSE_INIT;
5309b9a0469SMiklos Szeredi 	req->in.numargs = 1;
5319b9a0469SMiklos Szeredi 	req->in.args[0].size = sizeof(*arg);
5329b9a0469SMiklos Szeredi 	req->in.args[0].value = arg;
5339b9a0469SMiklos Szeredi 	req->out.numargs = 1;
5349b9a0469SMiklos Szeredi 	/* Variable length arguement used for backward compatibility
5359b9a0469SMiklos Szeredi 	   with interface version < 7.5.  Rest of init_out is zeroed
5369b9a0469SMiklos Szeredi 	   by do_get_request(), so a short reply is not a problem */
5379b9a0469SMiklos Szeredi 	req->out.argvar = 1;
5389b9a0469SMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_init_out);
5399b9a0469SMiklos Szeredi 	req->out.args[0].value = &req->misc.init_out;
5409b9a0469SMiklos Szeredi 	req->end = process_init_reply;
5419b9a0469SMiklos Szeredi 	request_send_background(fc, req);
5429b9a0469SMiklos Szeredi }
5439b9a0469SMiklos Szeredi 
544bafa9654SMiklos Szeredi static u64 conn_id(void)
545f543f253SMiklos Szeredi {
546bafa9654SMiklos Szeredi 	static u64 ctr = 1;
5470720b315SMiklos Szeredi 	return ctr++;
548f543f253SMiklos Szeredi }
549f543f253SMiklos Szeredi 
550d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent)
551d8a5ba45SMiklos Szeredi {
552d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
553d8a5ba45SMiklos Szeredi 	struct inode *root;
554d8a5ba45SMiklos Szeredi 	struct fuse_mount_data d;
555d8a5ba45SMiklos Szeredi 	struct file *file;
556f543f253SMiklos Szeredi 	struct dentry *root_dentry;
557ce1d5a49SMiklos Szeredi 	struct fuse_req *init_req;
558d8a5ba45SMiklos Szeredi 	int err;
559d8091614SMiklos Szeredi 	int is_bdev = sb->s_bdev != NULL;
560d8a5ba45SMiklos Szeredi 
56171421259SMiklos Szeredi 	if (sb->s_flags & MS_MANDLOCK)
56271421259SMiklos Szeredi 		return -EINVAL;
56371421259SMiklos Szeredi 
564d8091614SMiklos Szeredi 	if (!parse_fuse_opt((char *) data, &d, is_bdev))
565d8a5ba45SMiklos Szeredi 		return -EINVAL;
566d8a5ba45SMiklos Szeredi 
567d8091614SMiklos Szeredi 	if (is_bdev) {
568875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK
569d8091614SMiklos Szeredi 		if (!sb_set_blocksize(sb, d.blksize))
570d8091614SMiklos Szeredi 			return -EINVAL;
571875d95ecSMiklos Szeredi #endif
572d8091614SMiklos Szeredi 	} else {
573d8a5ba45SMiklos Szeredi 		sb->s_blocksize = PAGE_CACHE_SIZE;
574d8a5ba45SMiklos Szeredi 		sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
575d8091614SMiklos Szeredi 	}
576d8a5ba45SMiklos Szeredi 	sb->s_magic = FUSE_SUPER_MAGIC;
577d8a5ba45SMiklos Szeredi 	sb->s_op = &fuse_super_operations;
578d8a5ba45SMiklos Szeredi 	sb->s_maxbytes = MAX_LFS_FILESIZE;
579d8a5ba45SMiklos Szeredi 
580d8a5ba45SMiklos Szeredi 	file = fget(d.fd);
581d8a5ba45SMiklos Szeredi 	if (!file)
582d8a5ba45SMiklos Szeredi 		return -EINVAL;
583d8a5ba45SMiklos Szeredi 
5840720b315SMiklos Szeredi 	if (file->f_op != &fuse_dev_operations)
5850720b315SMiklos Szeredi 		return -EINVAL;
5860720b315SMiklos Szeredi 
5870720b315SMiklos Szeredi 	fc = new_conn();
5880720b315SMiklos Szeredi 	if (!fc)
5890720b315SMiklos Szeredi 		return -ENOMEM;
590d8a5ba45SMiklos Szeredi 
5911e9a4ed9SMiklos Szeredi 	fc->flags = d.flags;
592d8a5ba45SMiklos Szeredi 	fc->user_id = d.user_id;
59387729a55SMiklos Szeredi 	fc->group_id = d.group_id;
594db50b96cSMiklos Szeredi 	fc->max_read = d.max_read;
595d8a5ba45SMiklos Szeredi 
596f543f253SMiklos Szeredi 	/* Used by get_root_inode() */
597f543f253SMiklos Szeredi 	sb->s_fs_info = fc;
598f543f253SMiklos Szeredi 
599d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
600d8a5ba45SMiklos Szeredi 	root = get_root_inode(sb, d.rootmode);
601f543f253SMiklos Szeredi 	if (!root)
602d8a5ba45SMiklos Szeredi 		goto err;
603d8a5ba45SMiklos Szeredi 
604f543f253SMiklos Szeredi 	root_dentry = d_alloc_root(root);
605f543f253SMiklos Szeredi 	if (!root_dentry) {
606d8a5ba45SMiklos Szeredi 		iput(root);
607d8a5ba45SMiklos Szeredi 		goto err;
608d8a5ba45SMiklos Szeredi 	}
609f543f253SMiklos Szeredi 
610ce1d5a49SMiklos Szeredi 	init_req = fuse_request_alloc();
611ce1d5a49SMiklos Szeredi 	if (!init_req)
612ce1d5a49SMiklos Szeredi 		goto err_put_root;
613ce1d5a49SMiklos Szeredi 
6140ec7ca41SMiklos Szeredi 	if (is_bdev) {
6150ec7ca41SMiklos Szeredi 		fc->destroy_req = fuse_request_alloc();
6160ec7ca41SMiklos Szeredi 		if (!fc->destroy_req)
6170ec7ca41SMiklos Szeredi 			goto err_put_root;
6180ec7ca41SMiklos Szeredi 	}
6190ec7ca41SMiklos Szeredi 
620bafa9654SMiklos Szeredi 	mutex_lock(&fuse_mutex);
6218aa09a50SMiklos Szeredi 	err = -EINVAL;
6228aa09a50SMiklos Szeredi 	if (file->private_data)
623bafa9654SMiklos Szeredi 		goto err_unlock;
6248aa09a50SMiklos Szeredi 
625bafa9654SMiklos Szeredi 	fc->id = conn_id();
626bafa9654SMiklos Szeredi 	err = fuse_ctl_add_conn(fc);
627bafa9654SMiklos Szeredi 	if (err)
628bafa9654SMiklos Szeredi 		goto err_unlock;
629bafa9654SMiklos Szeredi 
630bafa9654SMiklos Szeredi 	list_add_tail(&fc->entry, &fuse_conn_list);
631f543f253SMiklos Szeredi 	sb->s_root = root_dentry;
632f543f253SMiklos Szeredi 	fc->connected = 1;
633bafa9654SMiklos Szeredi 	file->private_data = fuse_conn_get(fc);
634bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
6350720b315SMiklos Szeredi 	/*
6360720b315SMiklos Szeredi 	 * atomic_dec_and_test() in fput() provides the necessary
6370720b315SMiklos Szeredi 	 * memory barrier for file->private_data to be visible on all
6380720b315SMiklos Szeredi 	 * CPUs after this
6390720b315SMiklos Szeredi 	 */
6400720b315SMiklos Szeredi 	fput(file);
641f543f253SMiklos Szeredi 
642ce1d5a49SMiklos Szeredi 	fuse_send_init(fc, init_req);
643f543f253SMiklos Szeredi 
644d8a5ba45SMiklos Szeredi 	return 0;
645d8a5ba45SMiklos Szeredi 
646bafa9654SMiklos Szeredi  err_unlock:
647bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
648ce1d5a49SMiklos Szeredi 	fuse_request_free(init_req);
649f543f253SMiklos Szeredi  err_put_root:
650f543f253SMiklos Szeredi 	dput(root_dentry);
651d8a5ba45SMiklos Szeredi  err:
6520720b315SMiklos Szeredi 	fput(file);
653bafa9654SMiklos Szeredi 	fuse_conn_put(fc);
654d8a5ba45SMiklos Szeredi 	return err;
655d8a5ba45SMiklos Szeredi }
656d8a5ba45SMiklos Szeredi 
657454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type,
658d8a5ba45SMiklos Szeredi 		       int flags, const char *dev_name,
659454e2398SDavid Howells 		       void *raw_data, struct vfsmount *mnt)
660d8a5ba45SMiklos Szeredi {
661454e2398SDavid Howells 	return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
662d8a5ba45SMiklos Szeredi }
663d8a5ba45SMiklos Szeredi 
664875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = {
665875d95ecSMiklos Szeredi 	.owner		= THIS_MODULE,
666875d95ecSMiklos Szeredi 	.name		= "fuse",
66779c0b2dfSMiklos Szeredi 	.fs_flags	= FS_HAS_SUBTYPE,
668875d95ecSMiklos Szeredi 	.get_sb		= fuse_get_sb,
669875d95ecSMiklos Szeredi 	.kill_sb	= kill_anon_super,
670875d95ecSMiklos Szeredi };
671875d95ecSMiklos Szeredi 
672875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK
673d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type,
674d6392f87SMiklos Szeredi 			   int flags, const char *dev_name,
675d6392f87SMiklos Szeredi 			   void *raw_data, struct vfsmount *mnt)
676d6392f87SMiklos Szeredi {
677d6392f87SMiklos Szeredi 	return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super,
678d6392f87SMiklos Szeredi 			   mnt);
679d6392f87SMiklos Szeredi }
680d6392f87SMiklos Szeredi 
681d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = {
682d6392f87SMiklos Szeredi 	.owner		= THIS_MODULE,
683d6392f87SMiklos Szeredi 	.name		= "fuseblk",
684d6392f87SMiklos Szeredi 	.get_sb		= fuse_get_sb_blk,
685d6392f87SMiklos Szeredi 	.kill_sb	= kill_block_super,
686edad01e2SAlexey Dobriyan 	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
687d6392f87SMiklos Szeredi };
688d6392f87SMiklos Szeredi 
689875d95ecSMiklos Szeredi static inline int register_fuseblk(void)
690875d95ecSMiklos Szeredi {
691875d95ecSMiklos Szeredi 	return register_filesystem(&fuseblk_fs_type);
692875d95ecSMiklos Szeredi }
693875d95ecSMiklos Szeredi 
694875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void)
695875d95ecSMiklos Szeredi {
696875d95ecSMiklos Szeredi 	unregister_filesystem(&fuseblk_fs_type);
697875d95ecSMiklos Szeredi }
698875d95ecSMiklos Szeredi #else
699875d95ecSMiklos Szeredi static inline int register_fuseblk(void)
700875d95ecSMiklos Szeredi {
701875d95ecSMiklos Szeredi 	return 0;
702875d95ecSMiklos Szeredi }
703875d95ecSMiklos Szeredi 
704875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void)
705875d95ecSMiklos Szeredi {
706875d95ecSMiklos Szeredi }
707875d95ecSMiklos Szeredi #endif
708875d95ecSMiklos Szeredi 
709f543f253SMiklos Szeredi static decl_subsys(fuse, NULL, NULL);
710bafa9654SMiklos Szeredi static decl_subsys(connections, NULL, NULL);
711f543f253SMiklos Szeredi 
7124ba9b9d0SChristoph Lameter static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
713d8a5ba45SMiklos Szeredi {
714d8a5ba45SMiklos Szeredi 	struct inode * inode = foo;
715d8a5ba45SMiklos Szeredi 
716d8a5ba45SMiklos Szeredi 	inode_init_once(inode);
717d8a5ba45SMiklos Szeredi }
718d8a5ba45SMiklos Szeredi 
719d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void)
720d8a5ba45SMiklos Szeredi {
721d8a5ba45SMiklos Szeredi 	int err;
722d8a5ba45SMiklos Szeredi 
723d8a5ba45SMiklos Szeredi 	err = register_filesystem(&fuse_fs_type);
724d8a5ba45SMiklos Szeredi 	if (err)
725d6392f87SMiklos Szeredi 		goto out;
726d6392f87SMiklos Szeredi 
727875d95ecSMiklos Szeredi 	err = register_fuseblk();
728d6392f87SMiklos Szeredi 	if (err)
729d6392f87SMiklos Szeredi 		goto out_unreg;
730d6392f87SMiklos Szeredi 
731d8a5ba45SMiklos Szeredi 	fuse_inode_cachep = kmem_cache_create("fuse_inode",
732d8a5ba45SMiklos Szeredi 					      sizeof(struct fuse_inode),
733d8a5ba45SMiklos Szeredi 					      0, SLAB_HWCACHE_ALIGN,
73420c2df83SPaul Mundt 					      fuse_inode_init_once);
735d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
736d6392f87SMiklos Szeredi 	if (!fuse_inode_cachep)
737d6392f87SMiklos Szeredi 		goto out_unreg2;
738d8a5ba45SMiklos Szeredi 
739d6392f87SMiklos Szeredi 	return 0;
740d6392f87SMiklos Szeredi 
741d6392f87SMiklos Szeredi  out_unreg2:
742875d95ecSMiklos Szeredi 	unregister_fuseblk();
743d6392f87SMiklos Szeredi  out_unreg:
744d6392f87SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
745d6392f87SMiklos Szeredi  out:
746d8a5ba45SMiklos Szeredi 	return err;
747d8a5ba45SMiklos Szeredi }
748d8a5ba45SMiklos Szeredi 
749d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void)
750d8a5ba45SMiklos Szeredi {
751d8a5ba45SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
752875d95ecSMiklos Szeredi 	unregister_fuseblk();
753d8a5ba45SMiklos Szeredi 	kmem_cache_destroy(fuse_inode_cachep);
754d8a5ba45SMiklos Szeredi }
755d8a5ba45SMiklos Szeredi 
756f543f253SMiklos Szeredi static int fuse_sysfs_init(void)
757f543f253SMiklos Szeredi {
758f543f253SMiklos Szeredi 	int err;
759f543f253SMiklos Szeredi 
760823bccfcSGreg Kroah-Hartman 	kobj_set_kset_s(&fuse_subsys, fs_subsys);
761f543f253SMiklos Szeredi 	err = subsystem_register(&fuse_subsys);
762f543f253SMiklos Szeredi 	if (err)
763f543f253SMiklos Szeredi 		goto out_err;
764f543f253SMiklos Szeredi 
765823bccfcSGreg Kroah-Hartman 	kobj_set_kset_s(&connections_subsys, fuse_subsys);
766f543f253SMiklos Szeredi 	err = subsystem_register(&connections_subsys);
767f543f253SMiklos Szeredi 	if (err)
768f543f253SMiklos Szeredi 		goto out_fuse_unregister;
769f543f253SMiklos Szeredi 
770f543f253SMiklos Szeredi 	return 0;
771f543f253SMiklos Szeredi 
772f543f253SMiklos Szeredi  out_fuse_unregister:
773f543f253SMiklos Szeredi 	subsystem_unregister(&fuse_subsys);
774f543f253SMiklos Szeredi  out_err:
775f543f253SMiklos Szeredi 	return err;
776f543f253SMiklos Szeredi }
777f543f253SMiklos Szeredi 
778f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void)
779f543f253SMiklos Szeredi {
780f543f253SMiklos Szeredi 	subsystem_unregister(&connections_subsys);
781f543f253SMiklos Szeredi 	subsystem_unregister(&fuse_subsys);
782f543f253SMiklos Szeredi }
783f543f253SMiklos Szeredi 
784d8a5ba45SMiklos Szeredi static int __init fuse_init(void)
785d8a5ba45SMiklos Szeredi {
786d8a5ba45SMiklos Szeredi 	int res;
787d8a5ba45SMiklos Szeredi 
788d8a5ba45SMiklos Szeredi 	printk("fuse init (API version %i.%i)\n",
789d8a5ba45SMiklos Szeredi 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
790d8a5ba45SMiklos Szeredi 
791bafa9654SMiklos Szeredi 	INIT_LIST_HEAD(&fuse_conn_list);
792d8a5ba45SMiklos Szeredi 	res = fuse_fs_init();
793d8a5ba45SMiklos Szeredi 	if (res)
794d8a5ba45SMiklos Szeredi 		goto err;
795d8a5ba45SMiklos Szeredi 
796334f485dSMiklos Szeredi 	res = fuse_dev_init();
797334f485dSMiklos Szeredi 	if (res)
798334f485dSMiklos Szeredi 		goto err_fs_cleanup;
799334f485dSMiklos Szeredi 
800f543f253SMiklos Szeredi 	res = fuse_sysfs_init();
801f543f253SMiklos Szeredi 	if (res)
802f543f253SMiklos Szeredi 		goto err_dev_cleanup;
803f543f253SMiklos Szeredi 
804bafa9654SMiklos Szeredi 	res = fuse_ctl_init();
805bafa9654SMiklos Szeredi 	if (res)
806bafa9654SMiklos Szeredi 		goto err_sysfs_cleanup;
807bafa9654SMiklos Szeredi 
808d8a5ba45SMiklos Szeredi 	return 0;
809d8a5ba45SMiklos Szeredi 
810bafa9654SMiklos Szeredi  err_sysfs_cleanup:
811bafa9654SMiklos Szeredi 	fuse_sysfs_cleanup();
812f543f253SMiklos Szeredi  err_dev_cleanup:
813f543f253SMiklos Szeredi 	fuse_dev_cleanup();
814334f485dSMiklos Szeredi  err_fs_cleanup:
815334f485dSMiklos Szeredi 	fuse_fs_cleanup();
816d8a5ba45SMiklos Szeredi  err:
817d8a5ba45SMiklos Szeredi 	return res;
818d8a5ba45SMiklos Szeredi }
819d8a5ba45SMiklos Szeredi 
820d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void)
821d8a5ba45SMiklos Szeredi {
822d8a5ba45SMiklos Szeredi 	printk(KERN_DEBUG "fuse exit\n");
823d8a5ba45SMiklos Szeredi 
824bafa9654SMiklos Szeredi 	fuse_ctl_cleanup();
825f543f253SMiklos Szeredi 	fuse_sysfs_cleanup();
826d8a5ba45SMiklos Szeredi 	fuse_fs_cleanup();
827334f485dSMiklos Szeredi 	fuse_dev_cleanup();
828d8a5ba45SMiklos Szeredi }
829d8a5ba45SMiklos Szeredi 
830d8a5ba45SMiklos Szeredi module_init(fuse_init);
831d8a5ba45SMiklos Szeredi module_exit(fuse_exit);
832