xref: /openbmc/linux/fs/fuse/inode.c (revision 074406fa)
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;
475*074406faSMiklos Szeredi 	attr.nlink = 1;
4769e6268dbSMiklos Szeredi 	return fuse_iget(sb, 1, 0, &attr);
477d8a5ba45SMiklos Szeredi }
478d8a5ba45SMiklos Szeredi 
479ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = {
480d8a5ba45SMiklos Szeredi 	.alloc_inode    = fuse_alloc_inode,
481d8a5ba45SMiklos Szeredi 	.destroy_inode  = fuse_destroy_inode,
482d8a5ba45SMiklos Szeredi 	.read_inode	= fuse_read_inode,
483d8a5ba45SMiklos Szeredi 	.clear_inode	= fuse_clear_inode,
484ead5f0b5SMiklos Szeredi 	.drop_inode	= generic_delete_inode,
48571421259SMiklos Szeredi 	.remount_fs	= fuse_remount_fs,
486d8a5ba45SMiklos Szeredi 	.put_super	= fuse_put_super,
48769a53bf2SMiklos Szeredi 	.umount_begin	= fuse_umount_begin,
488e5e5558eSMiklos Szeredi 	.statfs		= fuse_statfs,
489d8a5ba45SMiklos Szeredi 	.show_options	= fuse_show_options,
490d8a5ba45SMiklos Szeredi };
491d8a5ba45SMiklos Szeredi 
4929b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
4939b9a0469SMiklos Szeredi {
4949b9a0469SMiklos Szeredi 	struct fuse_init_out *arg = &req->misc.init_out;
4959b9a0469SMiklos Szeredi 
4969b9a0469SMiklos Szeredi 	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
4979b9a0469SMiklos Szeredi 		fc->conn_error = 1;
4989b9a0469SMiklos Szeredi 	else {
4999cd68455SMiklos Szeredi 		unsigned long ra_pages;
5009cd68455SMiklos Szeredi 
5019cd68455SMiklos Szeredi 		if (arg->minor >= 6) {
5029cd68455SMiklos Szeredi 			ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
5039cd68455SMiklos Szeredi 			if (arg->flags & FUSE_ASYNC_READ)
5049cd68455SMiklos Szeredi 				fc->async_read = 1;
50571421259SMiklos Szeredi 			if (!(arg->flags & FUSE_POSIX_LOCKS))
50671421259SMiklos Szeredi 				fc->no_lock = 1;
50771421259SMiklos Szeredi 		} else {
5089cd68455SMiklos Szeredi 			ra_pages = fc->max_read / PAGE_CACHE_SIZE;
50971421259SMiklos Szeredi 			fc->no_lock = 1;
51071421259SMiklos Szeredi 		}
5119cd68455SMiklos Szeredi 
5129cd68455SMiklos Szeredi 		fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
5139b9a0469SMiklos Szeredi 		fc->minor = arg->minor;
5149b9a0469SMiklos Szeredi 		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
5150ec7ca41SMiklos Szeredi 		fc->conn_init = 1;
5169b9a0469SMiklos Szeredi 	}
5179b9a0469SMiklos Szeredi 	fuse_put_request(fc, req);
51808a53cdcSMiklos Szeredi 	fc->blocked = 0;
51908a53cdcSMiklos Szeredi 	wake_up_all(&fc->blocked_waitq);
5209b9a0469SMiklos Szeredi }
5219b9a0469SMiklos Szeredi 
522ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
5239b9a0469SMiklos Szeredi {
5249b9a0469SMiklos Szeredi 	struct fuse_init_in *arg = &req->misc.init_in;
525095da6cbSMiklos Szeredi 
5269b9a0469SMiklos Szeredi 	arg->major = FUSE_KERNEL_VERSION;
5279b9a0469SMiklos Szeredi 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
5289cd68455SMiklos Szeredi 	arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
52971421259SMiklos Szeredi 	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
5309b9a0469SMiklos Szeredi 	req->in.h.opcode = FUSE_INIT;
5319b9a0469SMiklos Szeredi 	req->in.numargs = 1;
5329b9a0469SMiklos Szeredi 	req->in.args[0].size = sizeof(*arg);
5339b9a0469SMiklos Szeredi 	req->in.args[0].value = arg;
5349b9a0469SMiklos Szeredi 	req->out.numargs = 1;
5359b9a0469SMiklos Szeredi 	/* Variable length arguement used for backward compatibility
5369b9a0469SMiklos Szeredi 	   with interface version < 7.5.  Rest of init_out is zeroed
5379b9a0469SMiklos Szeredi 	   by do_get_request(), so a short reply is not a problem */
5389b9a0469SMiklos Szeredi 	req->out.argvar = 1;
5399b9a0469SMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_init_out);
5409b9a0469SMiklos Szeredi 	req->out.args[0].value = &req->misc.init_out;
5419b9a0469SMiklos Szeredi 	req->end = process_init_reply;
5429b9a0469SMiklos Szeredi 	request_send_background(fc, req);
5439b9a0469SMiklos Szeredi }
5449b9a0469SMiklos Szeredi 
545bafa9654SMiklos Szeredi static u64 conn_id(void)
546f543f253SMiklos Szeredi {
547bafa9654SMiklos Szeredi 	static u64 ctr = 1;
5480720b315SMiklos Szeredi 	return ctr++;
549f543f253SMiklos Szeredi }
550f543f253SMiklos Szeredi 
551d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent)
552d8a5ba45SMiklos Szeredi {
553d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
554d8a5ba45SMiklos Szeredi 	struct inode *root;
555d8a5ba45SMiklos Szeredi 	struct fuse_mount_data d;
556d8a5ba45SMiklos Szeredi 	struct file *file;
557f543f253SMiklos Szeredi 	struct dentry *root_dentry;
558ce1d5a49SMiklos Szeredi 	struct fuse_req *init_req;
559d8a5ba45SMiklos Szeredi 	int err;
560d8091614SMiklos Szeredi 	int is_bdev = sb->s_bdev != NULL;
561d8a5ba45SMiklos Szeredi 
56271421259SMiklos Szeredi 	if (sb->s_flags & MS_MANDLOCK)
56371421259SMiklos Szeredi 		return -EINVAL;
56471421259SMiklos Szeredi 
565d8091614SMiklos Szeredi 	if (!parse_fuse_opt((char *) data, &d, is_bdev))
566d8a5ba45SMiklos Szeredi 		return -EINVAL;
567d8a5ba45SMiklos Szeredi 
568d8091614SMiklos Szeredi 	if (is_bdev) {
569875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK
570d8091614SMiklos Szeredi 		if (!sb_set_blocksize(sb, d.blksize))
571d8091614SMiklos Szeredi 			return -EINVAL;
572875d95ecSMiklos Szeredi #endif
573d8091614SMiklos Szeredi 	} else {
574d8a5ba45SMiklos Szeredi 		sb->s_blocksize = PAGE_CACHE_SIZE;
575d8a5ba45SMiklos Szeredi 		sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
576d8091614SMiklos Szeredi 	}
577d8a5ba45SMiklos Szeredi 	sb->s_magic = FUSE_SUPER_MAGIC;
578d8a5ba45SMiklos Szeredi 	sb->s_op = &fuse_super_operations;
579d8a5ba45SMiklos Szeredi 	sb->s_maxbytes = MAX_LFS_FILESIZE;
580d8a5ba45SMiklos Szeredi 
581d8a5ba45SMiklos Szeredi 	file = fget(d.fd);
582d8a5ba45SMiklos Szeredi 	if (!file)
583d8a5ba45SMiklos Szeredi 		return -EINVAL;
584d8a5ba45SMiklos Szeredi 
5850720b315SMiklos Szeredi 	if (file->f_op != &fuse_dev_operations)
5860720b315SMiklos Szeredi 		return -EINVAL;
5870720b315SMiklos Szeredi 
5880720b315SMiklos Szeredi 	fc = new_conn();
5890720b315SMiklos Szeredi 	if (!fc)
5900720b315SMiklos Szeredi 		return -ENOMEM;
591d8a5ba45SMiklos Szeredi 
5921e9a4ed9SMiklos Szeredi 	fc->flags = d.flags;
593d8a5ba45SMiklos Szeredi 	fc->user_id = d.user_id;
59487729a55SMiklos Szeredi 	fc->group_id = d.group_id;
595db50b96cSMiklos Szeredi 	fc->max_read = d.max_read;
596d8a5ba45SMiklos Szeredi 
597f543f253SMiklos Szeredi 	/* Used by get_root_inode() */
598f543f253SMiklos Szeredi 	sb->s_fs_info = fc;
599f543f253SMiklos Szeredi 
600d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
601d8a5ba45SMiklos Szeredi 	root = get_root_inode(sb, d.rootmode);
602f543f253SMiklos Szeredi 	if (!root)
603d8a5ba45SMiklos Szeredi 		goto err;
604d8a5ba45SMiklos Szeredi 
605f543f253SMiklos Szeredi 	root_dentry = d_alloc_root(root);
606f543f253SMiklos Szeredi 	if (!root_dentry) {
607d8a5ba45SMiklos Szeredi 		iput(root);
608d8a5ba45SMiklos Szeredi 		goto err;
609d8a5ba45SMiklos Szeredi 	}
610f543f253SMiklos Szeredi 
611ce1d5a49SMiklos Szeredi 	init_req = fuse_request_alloc();
612ce1d5a49SMiklos Szeredi 	if (!init_req)
613ce1d5a49SMiklos Szeredi 		goto err_put_root;
614ce1d5a49SMiklos Szeredi 
6150ec7ca41SMiklos Szeredi 	if (is_bdev) {
6160ec7ca41SMiklos Szeredi 		fc->destroy_req = fuse_request_alloc();
6170ec7ca41SMiklos Szeredi 		if (!fc->destroy_req)
6180ec7ca41SMiklos Szeredi 			goto err_put_root;
6190ec7ca41SMiklos Szeredi 	}
6200ec7ca41SMiklos Szeredi 
621bafa9654SMiklos Szeredi 	mutex_lock(&fuse_mutex);
6228aa09a50SMiklos Szeredi 	err = -EINVAL;
6238aa09a50SMiklos Szeredi 	if (file->private_data)
624bafa9654SMiklos Szeredi 		goto err_unlock;
6258aa09a50SMiklos Szeredi 
626bafa9654SMiklos Szeredi 	fc->id = conn_id();
627bafa9654SMiklos Szeredi 	err = fuse_ctl_add_conn(fc);
628bafa9654SMiklos Szeredi 	if (err)
629bafa9654SMiklos Szeredi 		goto err_unlock;
630bafa9654SMiklos Szeredi 
631bafa9654SMiklos Szeredi 	list_add_tail(&fc->entry, &fuse_conn_list);
632f543f253SMiklos Szeredi 	sb->s_root = root_dentry;
633f543f253SMiklos Szeredi 	fc->connected = 1;
634bafa9654SMiklos Szeredi 	file->private_data = fuse_conn_get(fc);
635bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
6360720b315SMiklos Szeredi 	/*
6370720b315SMiklos Szeredi 	 * atomic_dec_and_test() in fput() provides the necessary
6380720b315SMiklos Szeredi 	 * memory barrier for file->private_data to be visible on all
6390720b315SMiklos Szeredi 	 * CPUs after this
6400720b315SMiklos Szeredi 	 */
6410720b315SMiklos Szeredi 	fput(file);
642f543f253SMiklos Szeredi 
643ce1d5a49SMiklos Szeredi 	fuse_send_init(fc, init_req);
644f543f253SMiklos Szeredi 
645d8a5ba45SMiklos Szeredi 	return 0;
646d8a5ba45SMiklos Szeredi 
647bafa9654SMiklos Szeredi  err_unlock:
648bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
649ce1d5a49SMiklos Szeredi 	fuse_request_free(init_req);
650f543f253SMiklos Szeredi  err_put_root:
651f543f253SMiklos Szeredi 	dput(root_dentry);
652d8a5ba45SMiklos Szeredi  err:
6530720b315SMiklos Szeredi 	fput(file);
654bafa9654SMiklos Szeredi 	fuse_conn_put(fc);
655d8a5ba45SMiklos Szeredi 	return err;
656d8a5ba45SMiklos Szeredi }
657d8a5ba45SMiklos Szeredi 
658454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type,
659d8a5ba45SMiklos Szeredi 		       int flags, const char *dev_name,
660454e2398SDavid Howells 		       void *raw_data, struct vfsmount *mnt)
661d8a5ba45SMiklos Szeredi {
662454e2398SDavid Howells 	return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
663d8a5ba45SMiklos Szeredi }
664d8a5ba45SMiklos Szeredi 
665875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = {
666875d95ecSMiklos Szeredi 	.owner		= THIS_MODULE,
667875d95ecSMiklos Szeredi 	.name		= "fuse",
66879c0b2dfSMiklos Szeredi 	.fs_flags	= FS_HAS_SUBTYPE,
669875d95ecSMiklos Szeredi 	.get_sb		= fuse_get_sb,
670875d95ecSMiklos Szeredi 	.kill_sb	= kill_anon_super,
671875d95ecSMiklos Szeredi };
672875d95ecSMiklos Szeredi 
673875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK
674d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type,
675d6392f87SMiklos Szeredi 			   int flags, const char *dev_name,
676d6392f87SMiklos Szeredi 			   void *raw_data, struct vfsmount *mnt)
677d6392f87SMiklos Szeredi {
678d6392f87SMiklos Szeredi 	return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super,
679d6392f87SMiklos Szeredi 			   mnt);
680d6392f87SMiklos Szeredi }
681d6392f87SMiklos Szeredi 
682d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = {
683d6392f87SMiklos Szeredi 	.owner		= THIS_MODULE,
684d6392f87SMiklos Szeredi 	.name		= "fuseblk",
685d6392f87SMiklos Szeredi 	.get_sb		= fuse_get_sb_blk,
686d6392f87SMiklos Szeredi 	.kill_sb	= kill_block_super,
687edad01e2SAlexey Dobriyan 	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
688d6392f87SMiklos Szeredi };
689d6392f87SMiklos Szeredi 
690875d95ecSMiklos Szeredi static inline int register_fuseblk(void)
691875d95ecSMiklos Szeredi {
692875d95ecSMiklos Szeredi 	return register_filesystem(&fuseblk_fs_type);
693875d95ecSMiklos Szeredi }
694875d95ecSMiklos Szeredi 
695875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void)
696875d95ecSMiklos Szeredi {
697875d95ecSMiklos Szeredi 	unregister_filesystem(&fuseblk_fs_type);
698875d95ecSMiklos Szeredi }
699875d95ecSMiklos Szeredi #else
700875d95ecSMiklos Szeredi static inline int register_fuseblk(void)
701875d95ecSMiklos Szeredi {
702875d95ecSMiklos Szeredi 	return 0;
703875d95ecSMiklos Szeredi }
704875d95ecSMiklos Szeredi 
705875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void)
706875d95ecSMiklos Szeredi {
707875d95ecSMiklos Szeredi }
708875d95ecSMiklos Szeredi #endif
709875d95ecSMiklos Szeredi 
710f543f253SMiklos Szeredi static decl_subsys(fuse, NULL, NULL);
711bafa9654SMiklos Szeredi static decl_subsys(connections, NULL, NULL);
712f543f253SMiklos Szeredi 
7134ba9b9d0SChristoph Lameter static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
714d8a5ba45SMiklos Szeredi {
715d8a5ba45SMiklos Szeredi 	struct inode * inode = foo;
716d8a5ba45SMiklos Szeredi 
717d8a5ba45SMiklos Szeredi 	inode_init_once(inode);
718d8a5ba45SMiklos Szeredi }
719d8a5ba45SMiklos Szeredi 
720d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void)
721d8a5ba45SMiklos Szeredi {
722d8a5ba45SMiklos Szeredi 	int err;
723d8a5ba45SMiklos Szeredi 
724d8a5ba45SMiklos Szeredi 	err = register_filesystem(&fuse_fs_type);
725d8a5ba45SMiklos Szeredi 	if (err)
726d6392f87SMiklos Szeredi 		goto out;
727d6392f87SMiklos Szeredi 
728875d95ecSMiklos Szeredi 	err = register_fuseblk();
729d6392f87SMiklos Szeredi 	if (err)
730d6392f87SMiklos Szeredi 		goto out_unreg;
731d6392f87SMiklos Szeredi 
732d8a5ba45SMiklos Szeredi 	fuse_inode_cachep = kmem_cache_create("fuse_inode",
733d8a5ba45SMiklos Szeredi 					      sizeof(struct fuse_inode),
734d8a5ba45SMiklos Szeredi 					      0, SLAB_HWCACHE_ALIGN,
73520c2df83SPaul Mundt 					      fuse_inode_init_once);
736d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
737d6392f87SMiklos Szeredi 	if (!fuse_inode_cachep)
738d6392f87SMiklos Szeredi 		goto out_unreg2;
739d8a5ba45SMiklos Szeredi 
740d6392f87SMiklos Szeredi 	return 0;
741d6392f87SMiklos Szeredi 
742d6392f87SMiklos Szeredi  out_unreg2:
743875d95ecSMiklos Szeredi 	unregister_fuseblk();
744d6392f87SMiklos Szeredi  out_unreg:
745d6392f87SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
746d6392f87SMiklos Szeredi  out:
747d8a5ba45SMiklos Szeredi 	return err;
748d8a5ba45SMiklos Szeredi }
749d8a5ba45SMiklos Szeredi 
750d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void)
751d8a5ba45SMiklos Szeredi {
752d8a5ba45SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
753875d95ecSMiklos Szeredi 	unregister_fuseblk();
754d8a5ba45SMiklos Szeredi 	kmem_cache_destroy(fuse_inode_cachep);
755d8a5ba45SMiklos Szeredi }
756d8a5ba45SMiklos Szeredi 
757f543f253SMiklos Szeredi static int fuse_sysfs_init(void)
758f543f253SMiklos Szeredi {
759f543f253SMiklos Szeredi 	int err;
760f543f253SMiklos Szeredi 
761823bccfcSGreg Kroah-Hartman 	kobj_set_kset_s(&fuse_subsys, fs_subsys);
762f543f253SMiklos Szeredi 	err = subsystem_register(&fuse_subsys);
763f543f253SMiklos Szeredi 	if (err)
764f543f253SMiklos Szeredi 		goto out_err;
765f543f253SMiklos Szeredi 
766823bccfcSGreg Kroah-Hartman 	kobj_set_kset_s(&connections_subsys, fuse_subsys);
767f543f253SMiklos Szeredi 	err = subsystem_register(&connections_subsys);
768f543f253SMiklos Szeredi 	if (err)
769f543f253SMiklos Szeredi 		goto out_fuse_unregister;
770f543f253SMiklos Szeredi 
771f543f253SMiklos Szeredi 	return 0;
772f543f253SMiklos Szeredi 
773f543f253SMiklos Szeredi  out_fuse_unregister:
774f543f253SMiklos Szeredi 	subsystem_unregister(&fuse_subsys);
775f543f253SMiklos Szeredi  out_err:
776f543f253SMiklos Szeredi 	return err;
777f543f253SMiklos Szeredi }
778f543f253SMiklos Szeredi 
779f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void)
780f543f253SMiklos Szeredi {
781f543f253SMiklos Szeredi 	subsystem_unregister(&connections_subsys);
782f543f253SMiklos Szeredi 	subsystem_unregister(&fuse_subsys);
783f543f253SMiklos Szeredi }
784f543f253SMiklos Szeredi 
785d8a5ba45SMiklos Szeredi static int __init fuse_init(void)
786d8a5ba45SMiklos Szeredi {
787d8a5ba45SMiklos Szeredi 	int res;
788d8a5ba45SMiklos Szeredi 
789d8a5ba45SMiklos Szeredi 	printk("fuse init (API version %i.%i)\n",
790d8a5ba45SMiklos Szeredi 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
791d8a5ba45SMiklos Szeredi 
792bafa9654SMiklos Szeredi 	INIT_LIST_HEAD(&fuse_conn_list);
793d8a5ba45SMiklos Szeredi 	res = fuse_fs_init();
794d8a5ba45SMiklos Szeredi 	if (res)
795d8a5ba45SMiklos Szeredi 		goto err;
796d8a5ba45SMiklos Szeredi 
797334f485dSMiklos Szeredi 	res = fuse_dev_init();
798334f485dSMiklos Szeredi 	if (res)
799334f485dSMiklos Szeredi 		goto err_fs_cleanup;
800334f485dSMiklos Szeredi 
801f543f253SMiklos Szeredi 	res = fuse_sysfs_init();
802f543f253SMiklos Szeredi 	if (res)
803f543f253SMiklos Szeredi 		goto err_dev_cleanup;
804f543f253SMiklos Szeredi 
805bafa9654SMiklos Szeredi 	res = fuse_ctl_init();
806bafa9654SMiklos Szeredi 	if (res)
807bafa9654SMiklos Szeredi 		goto err_sysfs_cleanup;
808bafa9654SMiklos Szeredi 
809d8a5ba45SMiklos Szeredi 	return 0;
810d8a5ba45SMiklos Szeredi 
811bafa9654SMiklos Szeredi  err_sysfs_cleanup:
812bafa9654SMiklos Szeredi 	fuse_sysfs_cleanup();
813f543f253SMiklos Szeredi  err_dev_cleanup:
814f543f253SMiklos Szeredi 	fuse_dev_cleanup();
815334f485dSMiklos Szeredi  err_fs_cleanup:
816334f485dSMiklos Szeredi 	fuse_fs_cleanup();
817d8a5ba45SMiklos Szeredi  err:
818d8a5ba45SMiklos Szeredi 	return res;
819d8a5ba45SMiklos Szeredi }
820d8a5ba45SMiklos Szeredi 
821d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void)
822d8a5ba45SMiklos Szeredi {
823d8a5ba45SMiklos Szeredi 	printk(KERN_DEBUG "fuse exit\n");
824d8a5ba45SMiklos Szeredi 
825bafa9654SMiklos Szeredi 	fuse_ctl_cleanup();
826f543f253SMiklos Szeredi 	fuse_sysfs_cleanup();
827d8a5ba45SMiklos Szeredi 	fuse_fs_cleanup();
828334f485dSMiklos Szeredi 	fuse_dev_cleanup();
829d8a5ba45SMiklos Szeredi }
830d8a5ba45SMiklos Szeredi 
831d8a5ba45SMiklos Szeredi module_init(fuse_init);
832d8a5ba45SMiklos Szeredi module_exit(fuse_exit);
833