xref: /openbmc/linux/fs/fuse/inode.c (revision 93a8c3cd)
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;
5993a8c3cdSMiklos Szeredi 	INIT_LIST_HEAD(&fi->write_files);
60e5e5558eSMiklos Szeredi 	fi->forget_req = fuse_request_alloc();
61e5e5558eSMiklos Szeredi 	if (!fi->forget_req) {
62e5e5558eSMiklos Szeredi 		kmem_cache_free(fuse_inode_cachep, inode);
63e5e5558eSMiklos Szeredi 		return NULL;
64e5e5558eSMiklos Szeredi 	}
65d8a5ba45SMiklos Szeredi 
66d8a5ba45SMiklos Szeredi 	return inode;
67d8a5ba45SMiklos Szeredi }
68d8a5ba45SMiklos Szeredi 
69d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode)
70d8a5ba45SMiklos Szeredi {
71e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
7293a8c3cdSMiklos Szeredi 	BUG_ON(!list_empty(&fi->write_files));
73e5e5558eSMiklos Szeredi 	if (fi->forget_req)
74e5e5558eSMiklos Szeredi 		fuse_request_free(fi->forget_req);
75d8a5ba45SMiklos Szeredi 	kmem_cache_free(fuse_inode_cachep, inode);
76d8a5ba45SMiklos Szeredi }
77d8a5ba45SMiklos Szeredi 
78d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode)
79d8a5ba45SMiklos Szeredi {
80d8a5ba45SMiklos Szeredi 	/* No op */
81d8a5ba45SMiklos Szeredi }
82d8a5ba45SMiklos Szeredi 
83e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
849e6268dbSMiklos Szeredi 		      unsigned long nodeid, u64 nlookup)
85e5e5558eSMiklos Szeredi {
86e5e5558eSMiklos Szeredi 	struct fuse_forget_in *inarg = &req->misc.forget_in;
879e6268dbSMiklos Szeredi 	inarg->nlookup = nlookup;
88e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_FORGET;
89e5e5558eSMiklos Szeredi 	req->in.h.nodeid = nodeid;
90e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
91e5e5558eSMiklos Szeredi 	req->in.args[0].size = sizeof(struct fuse_forget_in);
92e5e5558eSMiklos Szeredi 	req->in.args[0].value = inarg;
93e5e5558eSMiklos Szeredi 	request_send_noreply(fc, req);
94e5e5558eSMiklos Szeredi }
95e5e5558eSMiklos Szeredi 
96d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode)
97d8a5ba45SMiklos Szeredi {
981e9a4ed9SMiklos Szeredi 	if (inode->i_sb->s_flags & MS_ACTIVE) {
99e5e5558eSMiklos Szeredi 		struct fuse_conn *fc = get_fuse_conn(inode);
100e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
1019e6268dbSMiklos Szeredi 		fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
102e5e5558eSMiklos Szeredi 		fi->forget_req = NULL;
103e5e5558eSMiklos Szeredi 	}
104d8a5ba45SMiklos Szeredi }
105d8a5ba45SMiklos Szeredi 
10671421259SMiklos Szeredi static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
10771421259SMiklos Szeredi {
10871421259SMiklos Szeredi 	if (*flags & MS_MANDLOCK)
10971421259SMiklos Szeredi 		return -EINVAL;
11071421259SMiklos Szeredi 
11171421259SMiklos Szeredi 	return 0;
11271421259SMiklos Szeredi }
11371421259SMiklos Szeredi 
114e00d2c2dSMiklos Szeredi static void fuse_truncate(struct address_space *mapping, loff_t offset)
115e00d2c2dSMiklos Szeredi {
116e00d2c2dSMiklos Szeredi 	/* See vmtruncate() */
117e00d2c2dSMiklos Szeredi 	unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
118e00d2c2dSMiklos Szeredi 	truncate_inode_pages(mapping, offset);
119e00d2c2dSMiklos Szeredi 	unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
120e00d2c2dSMiklos Szeredi }
121e00d2c2dSMiklos Szeredi 
1221fb69e78SMiklos Szeredi 
1231fb69e78SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
1241fb69e78SMiklos Szeredi 			    u64 attr_valid, u64 attr_version)
125d8a5ba45SMiklos Szeredi {
1269ffbb916SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
127ebc14c4dSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
128e00d2c2dSMiklos Szeredi 	loff_t oldsize;
129d8a5ba45SMiklos Szeredi 
1301fb69e78SMiklos Szeredi 	spin_lock(&fc->lock);
1311fb69e78SMiklos Szeredi 	if (attr_version != 0 && fi->attr_version > attr_version) {
1321fb69e78SMiklos Szeredi 		spin_unlock(&fc->lock);
1331fb69e78SMiklos Szeredi 		return;
1341fb69e78SMiklos Szeredi 	}
1351fb69e78SMiklos Szeredi 	fi->attr_version = ++fc->attr_version;
1361fb69e78SMiklos Szeredi 	fi->i_time = attr_valid;
1371fb69e78SMiklos Szeredi 
138d8a5ba45SMiklos Szeredi 	inode->i_ino     = attr->ino;
139ebc14c4dSMiklos Szeredi 	inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
140d8a5ba45SMiklos Szeredi 	inode->i_nlink   = attr->nlink;
141d8a5ba45SMiklos Szeredi 	inode->i_uid     = attr->uid;
142d8a5ba45SMiklos Szeredi 	inode->i_gid     = attr->gid;
143d8a5ba45SMiklos Szeredi 	inode->i_blocks  = attr->blocks;
144d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_sec   = attr->atime;
145d8a5ba45SMiklos Szeredi 	inode->i_atime.tv_nsec  = attr->atimensec;
146d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_sec   = attr->mtime;
147d8a5ba45SMiklos Szeredi 	inode->i_mtime.tv_nsec  = attr->mtimensec;
148d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_sec   = attr->ctime;
149d8a5ba45SMiklos Szeredi 	inode->i_ctime.tv_nsec  = attr->ctimensec;
150e00d2c2dSMiklos Szeredi 
151ebc14c4dSMiklos Szeredi 	/*
152ebc14c4dSMiklos Szeredi 	 * Don't set the sticky bit in i_mode, unless we want the VFS
153ebc14c4dSMiklos Szeredi 	 * to check permissions.  This prevents failures due to the
154ebc14c4dSMiklos Szeredi 	 * check in may_delete().
155ebc14c4dSMiklos Szeredi 	 */
156ebc14c4dSMiklos Szeredi 	fi->orig_i_mode = inode->i_mode;
157ebc14c4dSMiklos Szeredi 	if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
158ebc14c4dSMiklos Szeredi 		inode->i_mode &= ~S_ISVTX;
159ebc14c4dSMiklos Szeredi 
160e00d2c2dSMiklos Szeredi 	oldsize = inode->i_size;
161e00d2c2dSMiklos Szeredi 	i_size_write(inode, attr->size);
162e00d2c2dSMiklos Szeredi 	spin_unlock(&fc->lock);
163e00d2c2dSMiklos Szeredi 
164e00d2c2dSMiklos Szeredi 	if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
165e00d2c2dSMiklos Szeredi 		if (attr->size < oldsize)
166e00d2c2dSMiklos Szeredi 			fuse_truncate(inode->i_mapping, attr->size);
167b1009979SMiklos Szeredi 		invalidate_inode_pages2(inode->i_mapping);
168e00d2c2dSMiklos Szeredi 	}
169d8a5ba45SMiklos Szeredi }
170d8a5ba45SMiklos Szeredi 
171d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
172d8a5ba45SMiklos Szeredi {
173d8a5ba45SMiklos Szeredi 	inode->i_mode = attr->mode & S_IFMT;
1749ffbb916SMiklos Szeredi 	inode->i_size = attr->size;
175e5e5558eSMiklos Szeredi 	if (S_ISREG(inode->i_mode)) {
176e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
177b6aeadedSMiklos Szeredi 		fuse_init_file_inode(inode);
178e5e5558eSMiklos Szeredi 	} else if (S_ISDIR(inode->i_mode))
179e5e5558eSMiklos Szeredi 		fuse_init_dir(inode);
180e5e5558eSMiklos Szeredi 	else if (S_ISLNK(inode->i_mode))
181e5e5558eSMiklos Szeredi 		fuse_init_symlink(inode);
182e5e5558eSMiklos Szeredi 	else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
183e5e5558eSMiklos Szeredi 		 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
184e5e5558eSMiklos Szeredi 		fuse_init_common(inode);
185e5e5558eSMiklos Szeredi 		init_special_inode(inode, inode->i_mode,
186e5e5558eSMiklos Szeredi 				   new_decode_dev(attr->rdev));
18739ee059aSMiklos Szeredi 	} else
18839ee059aSMiklos Szeredi 		BUG();
189d8a5ba45SMiklos Szeredi }
190d8a5ba45SMiklos Szeredi 
191d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
192d8a5ba45SMiklos Szeredi {
193d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
194d8a5ba45SMiklos Szeredi 	if (get_node_id(inode) == nodeid)
195d8a5ba45SMiklos Szeredi 		return 1;
196d8a5ba45SMiklos Szeredi 	else
197d8a5ba45SMiklos Szeredi 		return 0;
198d8a5ba45SMiklos Szeredi }
199d8a5ba45SMiklos Szeredi 
200d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp)
201d8a5ba45SMiklos Szeredi {
202d8a5ba45SMiklos Szeredi 	unsigned long nodeid = *(unsigned long *) _nodeidp;
203d8a5ba45SMiklos Szeredi 	get_fuse_inode(inode)->nodeid = nodeid;
204d8a5ba45SMiklos Szeredi 	return 0;
205d8a5ba45SMiklos Szeredi }
206d8a5ba45SMiklos Szeredi 
207d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
2081fb69e78SMiklos Szeredi 			int generation, struct fuse_attr *attr,
2091fb69e78SMiklos Szeredi 			u64 attr_valid, u64 attr_version)
210d8a5ba45SMiklos Szeredi {
211d8a5ba45SMiklos Szeredi 	struct inode *inode;
2129e6268dbSMiklos Szeredi 	struct fuse_inode *fi;
213d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
214d8a5ba45SMiklos Szeredi 
215d8a5ba45SMiklos Szeredi  retry:
216d8a5ba45SMiklos Szeredi 	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
217d8a5ba45SMiklos Szeredi 	if (!inode)
218d8a5ba45SMiklos Szeredi 		return NULL;
219d8a5ba45SMiklos Szeredi 
220d8a5ba45SMiklos Szeredi 	if ((inode->i_state & I_NEW)) {
221b36c31baSMiklos Szeredi 		inode->i_flags |= S_NOATIME|S_NOCMTIME;
222d8a5ba45SMiklos Szeredi 		inode->i_generation = generation;
223d8a5ba45SMiklos Szeredi 		inode->i_data.backing_dev_info = &fc->bdi;
224d8a5ba45SMiklos Szeredi 		fuse_init_inode(inode, attr);
225d8a5ba45SMiklos Szeredi 		unlock_new_inode(inode);
226d8a5ba45SMiklos Szeredi 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
227d8a5ba45SMiklos Szeredi 		/* Inode has changed type, any I/O on the old should fail */
228d8a5ba45SMiklos Szeredi 		make_bad_inode(inode);
229d8a5ba45SMiklos Szeredi 		iput(inode);
230d8a5ba45SMiklos Szeredi 		goto retry;
231d8a5ba45SMiklos Szeredi 	}
232d8a5ba45SMiklos Szeredi 
2339e6268dbSMiklos Szeredi 	fi = get_fuse_inode(inode);
2348da5ff23SMiklos Szeredi 	spin_lock(&fc->lock);
2359e6268dbSMiklos Szeredi 	fi->nlookup ++;
2368da5ff23SMiklos Szeredi 	spin_unlock(&fc->lock);
2371fb69e78SMiklos Szeredi 	fuse_change_attributes(inode, attr, attr_valid, attr_version);
2381fb69e78SMiklos Szeredi 
239d8a5ba45SMiklos Szeredi 	return inode;
240d8a5ba45SMiklos Szeredi }
241d8a5ba45SMiklos Szeredi 
2428b512d9aSTrond Myklebust static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
24369a53bf2SMiklos Szeredi {
2448b512d9aSTrond Myklebust 	if (flags & MNT_FORCE)
2458b512d9aSTrond Myklebust 		fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
24669a53bf2SMiklos Szeredi }
24769a53bf2SMiklos Szeredi 
2480ec7ca41SMiklos Szeredi static void fuse_send_destroy(struct fuse_conn *fc)
2490ec7ca41SMiklos Szeredi {
2500ec7ca41SMiklos Szeredi 	struct fuse_req *req = fc->destroy_req;
2510ec7ca41SMiklos Szeredi 	if (req && fc->conn_init) {
2520ec7ca41SMiklos Szeredi 		fc->destroy_req = NULL;
2530ec7ca41SMiklos Szeredi 		req->in.h.opcode = FUSE_DESTROY;
2540ec7ca41SMiklos Szeredi 		req->force = 1;
2550ec7ca41SMiklos Szeredi 		request_send(fc, req);
2560ec7ca41SMiklos Szeredi 		fuse_put_request(fc, req);
2570ec7ca41SMiklos Szeredi 	}
2580ec7ca41SMiklos Szeredi }
2590ec7ca41SMiklos Szeredi 
260d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb)
261d8a5ba45SMiklos Szeredi {
262d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
263d8a5ba45SMiklos Szeredi 
2640ec7ca41SMiklos Szeredi 	fuse_send_destroy(fc);
265d7133114SMiklos Szeredi 	spin_lock(&fc->lock);
2669ba7cbbaSMiklos Szeredi 	fc->connected = 0;
26751eb01e7SMiklos Szeredi 	fc->blocked = 0;
268d7133114SMiklos Szeredi 	spin_unlock(&fc->lock);
269334f485dSMiklos Szeredi 	/* Flush all readers on this fs */
270385a17bfSJeff Dike 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
271334f485dSMiklos Szeredi 	wake_up_all(&fc->waitq);
27251eb01e7SMiklos Szeredi 	wake_up_all(&fc->blocked_waitq);
273de5e3decSMiklos Szeredi 	wake_up_all(&fc->reserved_req_waitq);
274bafa9654SMiklos Szeredi 	mutex_lock(&fuse_mutex);
275bafa9654SMiklos Szeredi 	list_del(&fc->entry);
276bafa9654SMiklos Szeredi 	fuse_ctl_remove_conn(fc);
277bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
278bafa9654SMiklos Szeredi 	fuse_conn_put(fc);
279d8a5ba45SMiklos Szeredi }
280d8a5ba45SMiklos Szeredi 
281e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
282e5e5558eSMiklos Szeredi {
283e5e5558eSMiklos Szeredi 	stbuf->f_type    = FUSE_SUPER_MAGIC;
284e5e5558eSMiklos Szeredi 	stbuf->f_bsize   = attr->bsize;
285de5f1202SMiklos Szeredi 	stbuf->f_frsize  = attr->frsize;
286e5e5558eSMiklos Szeredi 	stbuf->f_blocks  = attr->blocks;
287e5e5558eSMiklos Szeredi 	stbuf->f_bfree   = attr->bfree;
288e5e5558eSMiklos Szeredi 	stbuf->f_bavail  = attr->bavail;
289e5e5558eSMiklos Szeredi 	stbuf->f_files   = attr->files;
290e5e5558eSMiklos Szeredi 	stbuf->f_ffree   = attr->ffree;
291e5e5558eSMiklos Szeredi 	stbuf->f_namelen = attr->namelen;
292e5e5558eSMiklos Szeredi 	/* fsid is left zero */
293e5e5558eSMiklos Szeredi }
294e5e5558eSMiklos Szeredi 
295726c3342SDavid Howells static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
296e5e5558eSMiklos Szeredi {
297726c3342SDavid Howells 	struct super_block *sb = dentry->d_sb;
298e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(sb);
299e5e5558eSMiklos Szeredi 	struct fuse_req *req;
300e5e5558eSMiklos Szeredi 	struct fuse_statfs_out outarg;
301e5e5558eSMiklos Szeredi 	int err;
302e5e5558eSMiklos Szeredi 
303e57ac683SMiklos Szeredi 	if (!fuse_allow_task(fc, current)) {
304e57ac683SMiklos Szeredi 		buf->f_type = FUSE_SUPER_MAGIC;
305e57ac683SMiklos Szeredi 		return 0;
306e57ac683SMiklos Szeredi 	}
307e57ac683SMiklos Szeredi 
308ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
309ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
310ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
311e5e5558eSMiklos Szeredi 
312de5f1202SMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
313e5e5558eSMiklos Szeredi 	req->in.numargs = 0;
314e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_STATFS;
3155b35e8e5SMiklos Szeredi 	req->in.h.nodeid = get_node_id(dentry->d_inode);
316e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
317de5f1202SMiklos Szeredi 	req->out.args[0].size =
318de5f1202SMiklos Szeredi 		fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
319e5e5558eSMiklos Szeredi 	req->out.args[0].value = &outarg;
320e5e5558eSMiklos Szeredi 	request_send(fc, req);
321e5e5558eSMiklos Szeredi 	err = req->out.h.error;
322e5e5558eSMiklos Szeredi 	if (!err)
323e5e5558eSMiklos Szeredi 		convert_fuse_statfs(buf, &outarg.st);
324e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
325e5e5558eSMiklos Szeredi 	return err;
326e5e5558eSMiklos Szeredi }
327e5e5558eSMiklos Szeredi 
328d8a5ba45SMiklos Szeredi enum {
329d8a5ba45SMiklos Szeredi 	OPT_FD,
330d8a5ba45SMiklos Szeredi 	OPT_ROOTMODE,
331d8a5ba45SMiklos Szeredi 	OPT_USER_ID,
33287729a55SMiklos Szeredi 	OPT_GROUP_ID,
333d8a5ba45SMiklos Szeredi 	OPT_DEFAULT_PERMISSIONS,
334d8a5ba45SMiklos Szeredi 	OPT_ALLOW_OTHER,
335db50b96cSMiklos Szeredi 	OPT_MAX_READ,
336d8091614SMiklos Szeredi 	OPT_BLKSIZE,
337d8a5ba45SMiklos Szeredi 	OPT_ERR
338d8a5ba45SMiklos Szeredi };
339d8a5ba45SMiklos Szeredi 
340d8a5ba45SMiklos Szeredi static match_table_t tokens = {
341d8a5ba45SMiklos Szeredi 	{OPT_FD,			"fd=%u"},
342d8a5ba45SMiklos Szeredi 	{OPT_ROOTMODE,			"rootmode=%o"},
343d8a5ba45SMiklos Szeredi 	{OPT_USER_ID,			"user_id=%u"},
34487729a55SMiklos Szeredi 	{OPT_GROUP_ID,			"group_id=%u"},
345d8a5ba45SMiklos Szeredi 	{OPT_DEFAULT_PERMISSIONS,	"default_permissions"},
346d8a5ba45SMiklos Szeredi 	{OPT_ALLOW_OTHER,		"allow_other"},
347db50b96cSMiklos Szeredi 	{OPT_MAX_READ,			"max_read=%u"},
348d8091614SMiklos Szeredi 	{OPT_BLKSIZE,			"blksize=%u"},
349d8a5ba45SMiklos Szeredi 	{OPT_ERR,			NULL}
350d8a5ba45SMiklos Szeredi };
351d8a5ba45SMiklos Szeredi 
352d8091614SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
353d8a5ba45SMiklos Szeredi {
354d8a5ba45SMiklos Szeredi 	char *p;
355d8a5ba45SMiklos Szeredi 	memset(d, 0, sizeof(struct fuse_mount_data));
356db50b96cSMiklos Szeredi 	d->max_read = ~0;
357d8091614SMiklos Szeredi 	d->blksize = 512;
358d8a5ba45SMiklos Szeredi 
359d8a5ba45SMiklos Szeredi 	while ((p = strsep(&opt, ",")) != NULL) {
360d8a5ba45SMiklos Szeredi 		int token;
361d8a5ba45SMiklos Szeredi 		int value;
362d8a5ba45SMiklos Szeredi 		substring_t args[MAX_OPT_ARGS];
363d8a5ba45SMiklos Szeredi 		if (!*p)
364d8a5ba45SMiklos Szeredi 			continue;
365d8a5ba45SMiklos Szeredi 
366d8a5ba45SMiklos Szeredi 		token = match_token(p, tokens, args);
367d8a5ba45SMiklos Szeredi 		switch (token) {
368d8a5ba45SMiklos Szeredi 		case OPT_FD:
369d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
370d8a5ba45SMiklos Szeredi 				return 0;
371d8a5ba45SMiklos Szeredi 			d->fd = value;
3725a533682SMiklos Szeredi 			d->fd_present = 1;
373d8a5ba45SMiklos Szeredi 			break;
374d8a5ba45SMiklos Szeredi 
375d8a5ba45SMiklos Szeredi 		case OPT_ROOTMODE:
376d8a5ba45SMiklos Szeredi 			if (match_octal(&args[0], &value))
377d8a5ba45SMiklos Szeredi 				return 0;
378a5bfffacSTimo Savola 			if (!fuse_valid_type(value))
379a5bfffacSTimo Savola 				return 0;
380d8a5ba45SMiklos Szeredi 			d->rootmode = value;
3815a533682SMiklos Szeredi 			d->rootmode_present = 1;
382d8a5ba45SMiklos Szeredi 			break;
383d8a5ba45SMiklos Szeredi 
384d8a5ba45SMiklos Szeredi 		case OPT_USER_ID:
385d8a5ba45SMiklos Szeredi 			if (match_int(&args[0], &value))
386d8a5ba45SMiklos Szeredi 				return 0;
387d8a5ba45SMiklos Szeredi 			d->user_id = value;
3885a533682SMiklos Szeredi 			d->user_id_present = 1;
389d8a5ba45SMiklos Szeredi 			break;
390d8a5ba45SMiklos Szeredi 
39187729a55SMiklos Szeredi 		case OPT_GROUP_ID:
39287729a55SMiklos Szeredi 			if (match_int(&args[0], &value))
39387729a55SMiklos Szeredi 				return 0;
39487729a55SMiklos Szeredi 			d->group_id = value;
3955a533682SMiklos Szeredi 			d->group_id_present = 1;
39687729a55SMiklos Szeredi 			break;
39787729a55SMiklos Szeredi 
3981e9a4ed9SMiklos Szeredi 		case OPT_DEFAULT_PERMISSIONS:
3991e9a4ed9SMiklos Szeredi 			d->flags |= FUSE_DEFAULT_PERMISSIONS;
4001e9a4ed9SMiklos Szeredi 			break;
4011e9a4ed9SMiklos Szeredi 
4021e9a4ed9SMiklos Szeredi 		case OPT_ALLOW_OTHER:
4031e9a4ed9SMiklos Szeredi 			d->flags |= FUSE_ALLOW_OTHER;
4041e9a4ed9SMiklos Szeredi 			break;
4051e9a4ed9SMiklos Szeredi 
406db50b96cSMiklos Szeredi 		case OPT_MAX_READ:
407db50b96cSMiklos Szeredi 			if (match_int(&args[0], &value))
408db50b96cSMiklos Szeredi 				return 0;
409db50b96cSMiklos Szeredi 			d->max_read = value;
410db50b96cSMiklos Szeredi 			break;
411db50b96cSMiklos Szeredi 
412d8091614SMiklos Szeredi 		case OPT_BLKSIZE:
413d8091614SMiklos Szeredi 			if (!is_bdev || match_int(&args[0], &value))
414d8091614SMiklos Szeredi 				return 0;
415d8091614SMiklos Szeredi 			d->blksize = value;
416d8091614SMiklos Szeredi 			break;
417d8091614SMiklos Szeredi 
418d8a5ba45SMiklos Szeredi 		default:
419d8a5ba45SMiklos Szeredi 			return 0;
420d8a5ba45SMiklos Szeredi 		}
421d8a5ba45SMiklos Szeredi 	}
4225a533682SMiklos Szeredi 
4235a533682SMiklos Szeredi 	if (!d->fd_present || !d->rootmode_present ||
4245a533682SMiklos Szeredi 	    !d->user_id_present || !d->group_id_present)
425d8a5ba45SMiklos Szeredi 		return 0;
426d8a5ba45SMiklos Szeredi 
427d8a5ba45SMiklos Szeredi 	return 1;
428d8a5ba45SMiklos Szeredi }
429d8a5ba45SMiklos Szeredi 
430d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
431d8a5ba45SMiklos Szeredi {
432d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
433d8a5ba45SMiklos Szeredi 
434d8a5ba45SMiklos Szeredi 	seq_printf(m, ",user_id=%u", fc->user_id);
43587729a55SMiklos Szeredi 	seq_printf(m, ",group_id=%u", fc->group_id);
4361e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
4371e9a4ed9SMiklos Szeredi 		seq_puts(m, ",default_permissions");
4381e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
4391e9a4ed9SMiklos Szeredi 		seq_puts(m, ",allow_other");
440db50b96cSMiklos Szeredi 	if (fc->max_read != ~0)
441db50b96cSMiklos Szeredi 		seq_printf(m, ",max_read=%u", fc->max_read);
442d8a5ba45SMiklos Szeredi 	return 0;
443d8a5ba45SMiklos Szeredi }
444d8a5ba45SMiklos Szeredi 
445d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void)
446d8a5ba45SMiklos Szeredi {
447d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
448e0bf68ddSPeter Zijlstra 	int err;
449d8a5ba45SMiklos Szeredi 
4506383bdaaSMiklos Szeredi 	fc = kzalloc(sizeof(*fc), GFP_KERNEL);
451f543f253SMiklos Szeredi 	if (fc) {
452d7133114SMiklos Szeredi 		spin_lock_init(&fc->lock);
453d2a85164SMiklos Szeredi 		mutex_init(&fc->inst_mutex);
454bafa9654SMiklos Szeredi 		atomic_set(&fc->count, 1);
455334f485dSMiklos Szeredi 		init_waitqueue_head(&fc->waitq);
45608a53cdcSMiklos Szeredi 		init_waitqueue_head(&fc->blocked_waitq);
457de5e3decSMiklos Szeredi 		init_waitqueue_head(&fc->reserved_req_waitq);
458334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->pending);
459334f485dSMiklos Szeredi 		INIT_LIST_HEAD(&fc->processing);
460d77a1d5bSMiklos Szeredi 		INIT_LIST_HEAD(&fc->io);
461a4d27e75SMiklos Szeredi 		INIT_LIST_HEAD(&fc->interrupts);
462095da6cbSMiklos Szeredi 		atomic_set(&fc->num_waiting, 0);
463d8a5ba45SMiklos Szeredi 		fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
464d8a5ba45SMiklos Szeredi 		fc->bdi.unplug_io_fn = default_unplug_io_fn;
465e0bf68ddSPeter Zijlstra 		err = bdi_init(&fc->bdi);
466e0bf68ddSPeter Zijlstra 		if (err) {
467e0bf68ddSPeter Zijlstra 			kfree(fc);
468e0bf68ddSPeter Zijlstra 			fc = NULL;
469e0bf68ddSPeter Zijlstra 			goto out;
470e0bf68ddSPeter Zijlstra 		}
471334f485dSMiklos Szeredi 		fc->reqctr = 0;
47208a53cdcSMiklos Szeredi 		fc->blocked = 1;
4731fb69e78SMiklos Szeredi 		fc->attr_version = 1;
4749c8ef561SMiklos Szeredi 		get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
475d8a5ba45SMiklos Szeredi 	}
476e0bf68ddSPeter Zijlstra out:
477d8a5ba45SMiklos Szeredi 	return fc;
478d8a5ba45SMiklos Szeredi }
479d8a5ba45SMiklos Szeredi 
480bafa9654SMiklos Szeredi void fuse_conn_put(struct fuse_conn *fc)
481bafa9654SMiklos Szeredi {
482d2a85164SMiklos Szeredi 	if (atomic_dec_and_test(&fc->count)) {
4830ec7ca41SMiklos Szeredi 		if (fc->destroy_req)
4840ec7ca41SMiklos Szeredi 			fuse_request_free(fc->destroy_req);
485d2a85164SMiklos Szeredi 		mutex_destroy(&fc->inst_mutex);
486e0bf68ddSPeter Zijlstra 		bdi_destroy(&fc->bdi);
487bafa9654SMiklos Szeredi 		kfree(fc);
488bafa9654SMiklos Szeredi 	}
489d2a85164SMiklos Szeredi }
490bafa9654SMiklos Szeredi 
491bafa9654SMiklos Szeredi struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
492bafa9654SMiklos Szeredi {
493bafa9654SMiklos Szeredi 	atomic_inc(&fc->count);
494bafa9654SMiklos Szeredi 	return fc;
495bafa9654SMiklos Szeredi }
496bafa9654SMiklos Szeredi 
497d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
498d8a5ba45SMiklos Szeredi {
499d8a5ba45SMiklos Szeredi 	struct fuse_attr attr;
500d8a5ba45SMiklos Szeredi 	memset(&attr, 0, sizeof(attr));
501d8a5ba45SMiklos Szeredi 
502d8a5ba45SMiklos Szeredi 	attr.mode = mode;
503d8a5ba45SMiklos Szeredi 	attr.ino = FUSE_ROOT_ID;
504074406faSMiklos Szeredi 	attr.nlink = 1;
5051fb69e78SMiklos Szeredi 	return fuse_iget(sb, 1, 0, &attr, 0, 0);
506d8a5ba45SMiklos Szeredi }
507d8a5ba45SMiklos Szeredi 
508ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = {
509d8a5ba45SMiklos Szeredi 	.alloc_inode    = fuse_alloc_inode,
510d8a5ba45SMiklos Szeredi 	.destroy_inode  = fuse_destroy_inode,
511d8a5ba45SMiklos Szeredi 	.read_inode	= fuse_read_inode,
512d8a5ba45SMiklos Szeredi 	.clear_inode	= fuse_clear_inode,
513ead5f0b5SMiklos Szeredi 	.drop_inode	= generic_delete_inode,
51471421259SMiklos Szeredi 	.remount_fs	= fuse_remount_fs,
515d8a5ba45SMiklos Szeredi 	.put_super	= fuse_put_super,
51669a53bf2SMiklos Szeredi 	.umount_begin	= fuse_umount_begin,
517e5e5558eSMiklos Szeredi 	.statfs		= fuse_statfs,
518d8a5ba45SMiklos Szeredi 	.show_options	= fuse_show_options,
519d8a5ba45SMiklos Szeredi };
520d8a5ba45SMiklos Szeredi 
5219b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
5229b9a0469SMiklos Szeredi {
5239b9a0469SMiklos Szeredi 	struct fuse_init_out *arg = &req->misc.init_out;
5249b9a0469SMiklos Szeredi 
5259b9a0469SMiklos Szeredi 	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
5269b9a0469SMiklos Szeredi 		fc->conn_error = 1;
5279b9a0469SMiklos Szeredi 	else {
5289cd68455SMiklos Szeredi 		unsigned long ra_pages;
5299cd68455SMiklos Szeredi 
5309cd68455SMiklos Szeredi 		if (arg->minor >= 6) {
5319cd68455SMiklos Szeredi 			ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
5329cd68455SMiklos Szeredi 			if (arg->flags & FUSE_ASYNC_READ)
5339cd68455SMiklos Szeredi 				fc->async_read = 1;
53471421259SMiklos Szeredi 			if (!(arg->flags & FUSE_POSIX_LOCKS))
53571421259SMiklos Szeredi 				fc->no_lock = 1;
5366ff958edSMiklos Szeredi 			if (arg->flags & FUSE_ATOMIC_O_TRUNC)
5376ff958edSMiklos Szeredi 				fc->atomic_o_trunc = 1;
53871421259SMiklos Szeredi 		} else {
5399cd68455SMiklos Szeredi 			ra_pages = fc->max_read / PAGE_CACHE_SIZE;
54071421259SMiklos Szeredi 			fc->no_lock = 1;
54171421259SMiklos Szeredi 		}
5429cd68455SMiklos Szeredi 
5439cd68455SMiklos Szeredi 		fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
5449b9a0469SMiklos Szeredi 		fc->minor = arg->minor;
5459b9a0469SMiklos Szeredi 		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
5460ec7ca41SMiklos Szeredi 		fc->conn_init = 1;
5479b9a0469SMiklos Szeredi 	}
5489b9a0469SMiklos Szeredi 	fuse_put_request(fc, req);
54908a53cdcSMiklos Szeredi 	fc->blocked = 0;
55008a53cdcSMiklos Szeredi 	wake_up_all(&fc->blocked_waitq);
5519b9a0469SMiklos Szeredi }
5529b9a0469SMiklos Szeredi 
553ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
5549b9a0469SMiklos Szeredi {
5559b9a0469SMiklos Szeredi 	struct fuse_init_in *arg = &req->misc.init_in;
556095da6cbSMiklos Szeredi 
5579b9a0469SMiklos Szeredi 	arg->major = FUSE_KERNEL_VERSION;
5589b9a0469SMiklos Szeredi 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
5599cd68455SMiklos Szeredi 	arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
5606ff958edSMiklos Szeredi 	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_FILE_OPS |
5616ff958edSMiklos Szeredi 		FUSE_ATOMIC_O_TRUNC;
5629b9a0469SMiklos Szeredi 	req->in.h.opcode = FUSE_INIT;
5639b9a0469SMiklos Szeredi 	req->in.numargs = 1;
5649b9a0469SMiklos Szeredi 	req->in.args[0].size = sizeof(*arg);
5659b9a0469SMiklos Szeredi 	req->in.args[0].value = arg;
5669b9a0469SMiklos Szeredi 	req->out.numargs = 1;
5679b9a0469SMiklos Szeredi 	/* Variable length arguement used for backward compatibility
5689b9a0469SMiklos Szeredi 	   with interface version < 7.5.  Rest of init_out is zeroed
5699b9a0469SMiklos Szeredi 	   by do_get_request(), so a short reply is not a problem */
5709b9a0469SMiklos Szeredi 	req->out.argvar = 1;
5719b9a0469SMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_init_out);
5729b9a0469SMiklos Szeredi 	req->out.args[0].value = &req->misc.init_out;
5739b9a0469SMiklos Szeredi 	req->end = process_init_reply;
5749b9a0469SMiklos Szeredi 	request_send_background(fc, req);
5759b9a0469SMiklos Szeredi }
5769b9a0469SMiklos Szeredi 
577bafa9654SMiklos Szeredi static u64 conn_id(void)
578f543f253SMiklos Szeredi {
579bafa9654SMiklos Szeredi 	static u64 ctr = 1;
5800720b315SMiklos Szeredi 	return ctr++;
581f543f253SMiklos Szeredi }
582f543f253SMiklos Szeredi 
583d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent)
584d8a5ba45SMiklos Szeredi {
585d8a5ba45SMiklos Szeredi 	struct fuse_conn *fc;
586d8a5ba45SMiklos Szeredi 	struct inode *root;
587d8a5ba45SMiklos Szeredi 	struct fuse_mount_data d;
588d8a5ba45SMiklos Szeredi 	struct file *file;
589f543f253SMiklos Szeredi 	struct dentry *root_dentry;
590ce1d5a49SMiklos Szeredi 	struct fuse_req *init_req;
591d8a5ba45SMiklos Szeredi 	int err;
592d8091614SMiklos Szeredi 	int is_bdev = sb->s_bdev != NULL;
593d8a5ba45SMiklos Szeredi 
59471421259SMiklos Szeredi 	if (sb->s_flags & MS_MANDLOCK)
59571421259SMiklos Szeredi 		return -EINVAL;
59671421259SMiklos Szeredi 
597d8091614SMiklos Szeredi 	if (!parse_fuse_opt((char *) data, &d, is_bdev))
598d8a5ba45SMiklos Szeredi 		return -EINVAL;
599d8a5ba45SMiklos Szeredi 
600d8091614SMiklos Szeredi 	if (is_bdev) {
601875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK
602d8091614SMiklos Szeredi 		if (!sb_set_blocksize(sb, d.blksize))
603d8091614SMiklos Szeredi 			return -EINVAL;
604875d95ecSMiklos Szeredi #endif
605d8091614SMiklos Szeredi 	} else {
606d8a5ba45SMiklos Szeredi 		sb->s_blocksize = PAGE_CACHE_SIZE;
607d8a5ba45SMiklos Szeredi 		sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
608d8091614SMiklos Szeredi 	}
609d8a5ba45SMiklos Szeredi 	sb->s_magic = FUSE_SUPER_MAGIC;
610d8a5ba45SMiklos Szeredi 	sb->s_op = &fuse_super_operations;
611d8a5ba45SMiklos Szeredi 	sb->s_maxbytes = MAX_LFS_FILESIZE;
612d8a5ba45SMiklos Szeredi 
613d8a5ba45SMiklos Szeredi 	file = fget(d.fd);
614d8a5ba45SMiklos Szeredi 	if (!file)
615d8a5ba45SMiklos Szeredi 		return -EINVAL;
616d8a5ba45SMiklos Szeredi 
6170720b315SMiklos Szeredi 	if (file->f_op != &fuse_dev_operations)
6180720b315SMiklos Szeredi 		return -EINVAL;
6190720b315SMiklos Szeredi 
6200720b315SMiklos Szeredi 	fc = new_conn();
6210720b315SMiklos Szeredi 	if (!fc)
6220720b315SMiklos Szeredi 		return -ENOMEM;
623d8a5ba45SMiklos Szeredi 
6241e9a4ed9SMiklos Szeredi 	fc->flags = d.flags;
625d8a5ba45SMiklos Szeredi 	fc->user_id = d.user_id;
62687729a55SMiklos Szeredi 	fc->group_id = d.group_id;
627db50b96cSMiklos Szeredi 	fc->max_read = d.max_read;
628d8a5ba45SMiklos Szeredi 
629f543f253SMiklos Szeredi 	/* Used by get_root_inode() */
630f543f253SMiklos Szeredi 	sb->s_fs_info = fc;
631f543f253SMiklos Szeredi 
632d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
633d8a5ba45SMiklos Szeredi 	root = get_root_inode(sb, d.rootmode);
634f543f253SMiklos Szeredi 	if (!root)
635d8a5ba45SMiklos Szeredi 		goto err;
636d8a5ba45SMiklos Szeredi 
637f543f253SMiklos Szeredi 	root_dentry = d_alloc_root(root);
638f543f253SMiklos Szeredi 	if (!root_dentry) {
639d8a5ba45SMiklos Szeredi 		iput(root);
640d8a5ba45SMiklos Szeredi 		goto err;
641d8a5ba45SMiklos Szeredi 	}
642f543f253SMiklos Szeredi 
643ce1d5a49SMiklos Szeredi 	init_req = fuse_request_alloc();
644ce1d5a49SMiklos Szeredi 	if (!init_req)
645ce1d5a49SMiklos Szeredi 		goto err_put_root;
646ce1d5a49SMiklos Szeredi 
6470ec7ca41SMiklos Szeredi 	if (is_bdev) {
6480ec7ca41SMiklos Szeredi 		fc->destroy_req = fuse_request_alloc();
6490ec7ca41SMiklos Szeredi 		if (!fc->destroy_req)
6500ec7ca41SMiklos Szeredi 			goto err_put_root;
6510ec7ca41SMiklos Szeredi 	}
6520ec7ca41SMiklos Szeredi 
653bafa9654SMiklos Szeredi 	mutex_lock(&fuse_mutex);
6548aa09a50SMiklos Szeredi 	err = -EINVAL;
6558aa09a50SMiklos Szeredi 	if (file->private_data)
656bafa9654SMiklos Szeredi 		goto err_unlock;
6578aa09a50SMiklos Szeredi 
658bafa9654SMiklos Szeredi 	fc->id = conn_id();
659bafa9654SMiklos Szeredi 	err = fuse_ctl_add_conn(fc);
660bafa9654SMiklos Szeredi 	if (err)
661bafa9654SMiklos Szeredi 		goto err_unlock;
662bafa9654SMiklos Szeredi 
663bafa9654SMiklos Szeredi 	list_add_tail(&fc->entry, &fuse_conn_list);
664f543f253SMiklos Szeredi 	sb->s_root = root_dentry;
665f543f253SMiklos Szeredi 	fc->connected = 1;
666bafa9654SMiklos Szeredi 	file->private_data = fuse_conn_get(fc);
667bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
6680720b315SMiklos Szeredi 	/*
6690720b315SMiklos Szeredi 	 * atomic_dec_and_test() in fput() provides the necessary
6700720b315SMiklos Szeredi 	 * memory barrier for file->private_data to be visible on all
6710720b315SMiklos Szeredi 	 * CPUs after this
6720720b315SMiklos Szeredi 	 */
6730720b315SMiklos Szeredi 	fput(file);
674f543f253SMiklos Szeredi 
675ce1d5a49SMiklos Szeredi 	fuse_send_init(fc, init_req);
676f543f253SMiklos Szeredi 
677d8a5ba45SMiklos Szeredi 	return 0;
678d8a5ba45SMiklos Szeredi 
679bafa9654SMiklos Szeredi  err_unlock:
680bafa9654SMiklos Szeredi 	mutex_unlock(&fuse_mutex);
681ce1d5a49SMiklos Szeredi 	fuse_request_free(init_req);
682f543f253SMiklos Szeredi  err_put_root:
683f543f253SMiklos Szeredi 	dput(root_dentry);
684d8a5ba45SMiklos Szeredi  err:
6850720b315SMiklos Szeredi 	fput(file);
686bafa9654SMiklos Szeredi 	fuse_conn_put(fc);
687d8a5ba45SMiklos Szeredi 	return err;
688d8a5ba45SMiklos Szeredi }
689d8a5ba45SMiklos Szeredi 
690454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type,
691d8a5ba45SMiklos Szeredi 		       int flags, const char *dev_name,
692454e2398SDavid Howells 		       void *raw_data, struct vfsmount *mnt)
693d8a5ba45SMiklos Szeredi {
694454e2398SDavid Howells 	return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
695d8a5ba45SMiklos Szeredi }
696d8a5ba45SMiklos Szeredi 
697875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = {
698875d95ecSMiklos Szeredi 	.owner		= THIS_MODULE,
699875d95ecSMiklos Szeredi 	.name		= "fuse",
70079c0b2dfSMiklos Szeredi 	.fs_flags	= FS_HAS_SUBTYPE,
701875d95ecSMiklos Szeredi 	.get_sb		= fuse_get_sb,
702875d95ecSMiklos Szeredi 	.kill_sb	= kill_anon_super,
703875d95ecSMiklos Szeredi };
704875d95ecSMiklos Szeredi 
705875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK
706d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type,
707d6392f87SMiklos Szeredi 			   int flags, const char *dev_name,
708d6392f87SMiklos Szeredi 			   void *raw_data, struct vfsmount *mnt)
709d6392f87SMiklos Szeredi {
710d6392f87SMiklos Szeredi 	return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super,
711d6392f87SMiklos Szeredi 			   mnt);
712d6392f87SMiklos Szeredi }
713d6392f87SMiklos Szeredi 
714d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = {
715d6392f87SMiklos Szeredi 	.owner		= THIS_MODULE,
716d6392f87SMiklos Szeredi 	.name		= "fuseblk",
717d6392f87SMiklos Szeredi 	.get_sb		= fuse_get_sb_blk,
718d6392f87SMiklos Szeredi 	.kill_sb	= kill_block_super,
719edad01e2SAlexey Dobriyan 	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
720d6392f87SMiklos Szeredi };
721d6392f87SMiklos Szeredi 
722875d95ecSMiklos Szeredi static inline int register_fuseblk(void)
723875d95ecSMiklos Szeredi {
724875d95ecSMiklos Szeredi 	return register_filesystem(&fuseblk_fs_type);
725875d95ecSMiklos Szeredi }
726875d95ecSMiklos Szeredi 
727875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void)
728875d95ecSMiklos Szeredi {
729875d95ecSMiklos Szeredi 	unregister_filesystem(&fuseblk_fs_type);
730875d95ecSMiklos Szeredi }
731875d95ecSMiklos Szeredi #else
732875d95ecSMiklos Szeredi static inline int register_fuseblk(void)
733875d95ecSMiklos Szeredi {
734875d95ecSMiklos Szeredi 	return 0;
735875d95ecSMiklos Szeredi }
736875d95ecSMiklos Szeredi 
737875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void)
738875d95ecSMiklos Szeredi {
739875d95ecSMiklos Szeredi }
740875d95ecSMiklos Szeredi #endif
741875d95ecSMiklos Szeredi 
742f543f253SMiklos Szeredi static decl_subsys(fuse, NULL, NULL);
743bafa9654SMiklos Szeredi static decl_subsys(connections, NULL, NULL);
744f543f253SMiklos Szeredi 
7454ba9b9d0SChristoph Lameter static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
746d8a5ba45SMiklos Szeredi {
747d8a5ba45SMiklos Szeredi 	struct inode * inode = foo;
748d8a5ba45SMiklos Szeredi 
749d8a5ba45SMiklos Szeredi 	inode_init_once(inode);
750d8a5ba45SMiklos Szeredi }
751d8a5ba45SMiklos Szeredi 
752d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void)
753d8a5ba45SMiklos Szeredi {
754d8a5ba45SMiklos Szeredi 	int err;
755d8a5ba45SMiklos Szeredi 
756d8a5ba45SMiklos Szeredi 	err = register_filesystem(&fuse_fs_type);
757d8a5ba45SMiklos Szeredi 	if (err)
758d6392f87SMiklos Szeredi 		goto out;
759d6392f87SMiklos Szeredi 
760875d95ecSMiklos Szeredi 	err = register_fuseblk();
761d6392f87SMiklos Szeredi 	if (err)
762d6392f87SMiklos Szeredi 		goto out_unreg;
763d6392f87SMiklos Szeredi 
764d8a5ba45SMiklos Szeredi 	fuse_inode_cachep = kmem_cache_create("fuse_inode",
765d8a5ba45SMiklos Szeredi 					      sizeof(struct fuse_inode),
766d8a5ba45SMiklos Szeredi 					      0, SLAB_HWCACHE_ALIGN,
76720c2df83SPaul Mundt 					      fuse_inode_init_once);
768d8a5ba45SMiklos Szeredi 	err = -ENOMEM;
769d6392f87SMiklos Szeredi 	if (!fuse_inode_cachep)
770d6392f87SMiklos Szeredi 		goto out_unreg2;
771d8a5ba45SMiklos Szeredi 
772d6392f87SMiklos Szeredi 	return 0;
773d6392f87SMiklos Szeredi 
774d6392f87SMiklos Szeredi  out_unreg2:
775875d95ecSMiklos Szeredi 	unregister_fuseblk();
776d6392f87SMiklos Szeredi  out_unreg:
777d6392f87SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
778d6392f87SMiklos Szeredi  out:
779d8a5ba45SMiklos Szeredi 	return err;
780d8a5ba45SMiklos Szeredi }
781d8a5ba45SMiklos Szeredi 
782d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void)
783d8a5ba45SMiklos Szeredi {
784d8a5ba45SMiklos Szeredi 	unregister_filesystem(&fuse_fs_type);
785875d95ecSMiklos Szeredi 	unregister_fuseblk();
786d8a5ba45SMiklos Szeredi 	kmem_cache_destroy(fuse_inode_cachep);
787d8a5ba45SMiklos Szeredi }
788d8a5ba45SMiklos Szeredi 
789f543f253SMiklos Szeredi static int fuse_sysfs_init(void)
790f543f253SMiklos Szeredi {
791f543f253SMiklos Szeredi 	int err;
792f543f253SMiklos Szeredi 
793823bccfcSGreg Kroah-Hartman 	kobj_set_kset_s(&fuse_subsys, fs_subsys);
794f543f253SMiklos Szeredi 	err = subsystem_register(&fuse_subsys);
795f543f253SMiklos Szeredi 	if (err)
796f543f253SMiklos Szeredi 		goto out_err;
797f543f253SMiklos Szeredi 
798823bccfcSGreg Kroah-Hartman 	kobj_set_kset_s(&connections_subsys, fuse_subsys);
799f543f253SMiklos Szeredi 	err = subsystem_register(&connections_subsys);
800f543f253SMiklos Szeredi 	if (err)
801f543f253SMiklos Szeredi 		goto out_fuse_unregister;
802f543f253SMiklos Szeredi 
803f543f253SMiklos Szeredi 	return 0;
804f543f253SMiklos Szeredi 
805f543f253SMiklos Szeredi  out_fuse_unregister:
806f543f253SMiklos Szeredi 	subsystem_unregister(&fuse_subsys);
807f543f253SMiklos Szeredi  out_err:
808f543f253SMiklos Szeredi 	return err;
809f543f253SMiklos Szeredi }
810f543f253SMiklos Szeredi 
811f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void)
812f543f253SMiklos Szeredi {
813f543f253SMiklos Szeredi 	subsystem_unregister(&connections_subsys);
814f543f253SMiklos Szeredi 	subsystem_unregister(&fuse_subsys);
815f543f253SMiklos Szeredi }
816f543f253SMiklos Szeredi 
817d8a5ba45SMiklos Szeredi static int __init fuse_init(void)
818d8a5ba45SMiklos Szeredi {
819d8a5ba45SMiklos Szeredi 	int res;
820d8a5ba45SMiklos Szeredi 
821d8a5ba45SMiklos Szeredi 	printk("fuse init (API version %i.%i)\n",
822d8a5ba45SMiklos Szeredi 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
823d8a5ba45SMiklos Szeredi 
824bafa9654SMiklos Szeredi 	INIT_LIST_HEAD(&fuse_conn_list);
825d8a5ba45SMiklos Szeredi 	res = fuse_fs_init();
826d8a5ba45SMiklos Szeredi 	if (res)
827d8a5ba45SMiklos Szeredi 		goto err;
828d8a5ba45SMiklos Szeredi 
829334f485dSMiklos Szeredi 	res = fuse_dev_init();
830334f485dSMiklos Szeredi 	if (res)
831334f485dSMiklos Szeredi 		goto err_fs_cleanup;
832334f485dSMiklos Szeredi 
833f543f253SMiklos Szeredi 	res = fuse_sysfs_init();
834f543f253SMiklos Szeredi 	if (res)
835f543f253SMiklos Szeredi 		goto err_dev_cleanup;
836f543f253SMiklos Szeredi 
837bafa9654SMiklos Szeredi 	res = fuse_ctl_init();
838bafa9654SMiklos Szeredi 	if (res)
839bafa9654SMiklos Szeredi 		goto err_sysfs_cleanup;
840bafa9654SMiklos Szeredi 
841d8a5ba45SMiklos Szeredi 	return 0;
842d8a5ba45SMiklos Szeredi 
843bafa9654SMiklos Szeredi  err_sysfs_cleanup:
844bafa9654SMiklos Szeredi 	fuse_sysfs_cleanup();
845f543f253SMiklos Szeredi  err_dev_cleanup:
846f543f253SMiklos Szeredi 	fuse_dev_cleanup();
847334f485dSMiklos Szeredi  err_fs_cleanup:
848334f485dSMiklos Szeredi 	fuse_fs_cleanup();
849d8a5ba45SMiklos Szeredi  err:
850d8a5ba45SMiklos Szeredi 	return res;
851d8a5ba45SMiklos Szeredi }
852d8a5ba45SMiklos Szeredi 
853d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void)
854d8a5ba45SMiklos Szeredi {
855d8a5ba45SMiklos Szeredi 	printk(KERN_DEBUG "fuse exit\n");
856d8a5ba45SMiklos Szeredi 
857bafa9654SMiklos Szeredi 	fuse_ctl_cleanup();
858f543f253SMiklos Szeredi 	fuse_sysfs_cleanup();
859d8a5ba45SMiklos Szeredi 	fuse_fs_cleanup();
860334f485dSMiklos Szeredi 	fuse_dev_cleanup();
861d8a5ba45SMiklos Szeredi }
862d8a5ba45SMiklos Szeredi 
863d8a5ba45SMiklos Szeredi module_init(fuse_init);
864d8a5ba45SMiklos Szeredi module_exit(fuse_exit);
865