blob: 0145045649092824fd0a5e3d7b64d4f4ab1ba061 [file] [log] [blame]
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00007*/
8
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00009#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000012#include <linux/slab.h>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000013#include <linux/file.h>
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000014#include <linux/seq_file.h>
Miklos Szeredic6ee9fd2005-01-10 09:53:04 +000015#include <linux/init.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000016#include <linux/module.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000017#ifdef KERNEL_2_6
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000018#include <linux/parser.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000019#include <linux/statfs.h>
Miklos Szeredi91762cd2006-06-29 14:38:35 +000020#include <linux/random.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000021#else
22#include "compat/parser.h"
Miklos Szeredif85ab242004-01-07 12:16:45 +000023#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000024
Miklos Szeredic6ee9fd2005-01-10 09:53:04 +000025MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
26MODULE_DESCRIPTION("Filesystem in Userspace");
27#ifdef MODULE_LICENSE
28MODULE_LICENSE("GPL");
29#endif
30
Miklos Szeredi069c9502004-07-16 16:17:02 +000031static kmem_cache_t *fuse_inode_cachep;
Miklos Szeredi91762cd2006-06-29 14:38:35 +000032struct list_head fuse_conn_list;
33DEFINE_MUTEX(fuse_mutex);
Miklos Szerediacb4d362004-07-02 16:20:45 +000034
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000035#define FUSE_SUPER_MAGIC 0x65735546
36
Miklos Szeredif85ab242004-01-07 12:16:45 +000037#ifndef KERNEL_2_6
38#define kstatfs statfs
39#endif
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000040#ifndef MAX_LFS_FILESIZE
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000041#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000042#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000043struct fuse_mount_data {
44 int fd;
Miklos Szeredi83a07442004-11-30 18:25:20 +000045 unsigned rootmode;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +000046 unsigned user_id;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +000047 unsigned group_id;
Miklos Szeredi437d8112005-07-06 09:14:20 +000048 unsigned fd_present : 1;
49 unsigned rootmode_present : 1;
50 unsigned user_id_present : 1;
51 unsigned group_id_present : 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +000052 unsigned flags;
53 unsigned max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000054};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000055
Miklos Szeredia13d9002004-11-02 17:32:03 +000056static struct inode *fuse_alloc_inode(struct super_block *sb)
Miklos Szeredi069c9502004-07-16 16:17:02 +000057{
Miklos Szeredia13d9002004-11-02 17:32:03 +000058 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000059 struct fuse_inode *fi;
60
Miklos Szeredia13d9002004-11-02 17:32:03 +000061 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
62 if (!inode)
63 return NULL;
Miklos Szeredi069c9502004-07-16 16:17:02 +000064
Miklos Szeredia13d9002004-11-02 17:32:03 +000065#ifndef KERNEL_2_6
66 inode->u.generic_ip = NULL;
67#endif
Miklos Szeredi039322d2004-12-01 18:39:12 +000068 fi = get_fuse_inode(inode);
Miklos Szeredi91762cd2006-06-29 14:38:35 +000069 fi->i_time = 0;
Miklos Szeredi81394522005-01-11 14:24:18 +000070 fi->nodeid = 0;
Miklos Szeredi38009022005-05-08 19:47:22 +000071 fi->nlookup = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +000072 fi->forget_req = fuse_request_alloc();
73 if (!fi->forget_req) {
74 kmem_cache_free(fuse_inode_cachep, inode);
75 return NULL;
76 }
Miklos Szeredia13d9002004-11-02 17:32:03 +000077
78 return inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000079}
80
Miklos Szeredia13d9002004-11-02 17:32:03 +000081static void fuse_destroy_inode(struct inode *inode)
Miklos Szeredi069c9502004-07-16 16:17:02 +000082{
Miklos Szeredi039322d2004-12-01 18:39:12 +000083 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000084 if (fi->forget_req)
85 fuse_request_free(fi->forget_req);
Miklos Szeredia13d9002004-11-02 17:32:03 +000086 kmem_cache_free(fuse_inode_cachep, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +000087}
88
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000089static void fuse_read_inode(struct inode *inode)
90{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000091 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000092}
93
Miklos Szeredia13d9002004-11-02 17:32:03 +000094void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi38009022005-05-08 19:47:22 +000095 unsigned long nodeid, u64 nlookup)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +000096{
97 struct fuse_forget_in *inarg = &req->misc.forget_in;
Miklos Szeredi38009022005-05-08 19:47:22 +000098 inarg->nlookup = nlookup;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +000099 req->in.h.opcode = FUSE_FORGET;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000100 req->in.h.nodeid = nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000101 req->in.numargs = 1;
102 req->in.args[0].size = sizeof(struct fuse_forget_in);
103 req->in.args[0].value = inarg;
104 request_send_noreply(fc, req);
105}
106
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000107static void fuse_clear_inode(struct inode *inode)
108{
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000109 if (inode->i_sb->s_flags & MS_ACTIVE) {
110 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000111 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi38009022005-05-08 19:47:22 +0000112 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000113 fi->forget_req = NULL;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000114 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000115}
116
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000117static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
118{
119 if (*flags & MS_MANDLOCK)
120 return -EINVAL;
121
122 return 0;
123}
124
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000125void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
126{
127 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
128#ifdef KERNEL_2_6
129 invalidate_inode_pages(inode->i_mapping);
130#else
131 invalidate_inode_pages(inode);
132#endif
133
134 inode->i_ino = attr->ino;
135 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
136 inode->i_nlink = attr->nlink;
137 inode->i_uid = attr->uid;
138 inode->i_gid = attr->gid;
139 i_size_write(inode, attr->size);
140 inode->i_blksize = PAGE_CACHE_SIZE;
141 inode->i_blocks = attr->blocks;
142#ifdef KERNEL_2_6
143 inode->i_atime.tv_sec = attr->atime;
144 inode->i_atime.tv_nsec = attr->atimensec;
145 inode->i_mtime.tv_sec = attr->mtime;
146 inode->i_mtime.tv_nsec = attr->mtimensec;
147 inode->i_ctime.tv_sec = attr->ctime;
148 inode->i_ctime.tv_nsec = attr->ctimensec;
149#else
150 inode->i_atime = attr->atime;
151 inode->i_mtime = attr->mtime;
152 inode->i_ctime = attr->ctime;
153#endif
154}
155
156static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
157{
158 inode->i_mode = attr->mode & S_IFMT;
159 i_size_write(inode, attr->size);
160 if (S_ISREG(inode->i_mode)) {
161 fuse_init_common(inode);
162 fuse_init_file_inode(inode);
163 } else if (S_ISDIR(inode->i_mode))
164 fuse_init_dir(inode);
165 else if (S_ISLNK(inode->i_mode))
166 fuse_init_symlink(inode);
167 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
168 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
169 fuse_init_common(inode);
170 init_special_inode(inode, inode->i_mode,
171 new_decode_dev(attr->rdev));
Miklos Szeredi64709572005-12-14 22:16:28 +0000172 } else
173 BUG();
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000174}
175
176#ifdef KERNEL_2_6
177static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
178{
179 unsigned long nodeid = *(unsigned long *) _nodeidp;
180 if (get_node_id(inode) == nodeid)
181 return 1;
182 else
183 return 0;
184}
185
186static int fuse_inode_set(struct inode *inode, void *_nodeidp)
187{
188 unsigned long nodeid = *(unsigned long *) _nodeidp;
189 get_fuse_inode(inode)->nodeid = nodeid;
190 return 0;
191}
192
193struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
Miklos Szeredi38009022005-05-08 19:47:22 +0000194 int generation, struct fuse_attr *attr)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000195{
196 struct inode *inode;
Miklos Szeredi38009022005-05-08 19:47:22 +0000197 struct fuse_inode *fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000198 struct fuse_conn *fc = get_fuse_conn_super(sb);
199 int retried = 0;
200
201 retry:
202 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
203 if (!inode)
204 return NULL;
205
206 if ((inode->i_state & I_NEW)) {
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +0000207#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000208 inode->i_flags |= S_NOATIME|S_NOCMTIME;
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +0000209#else
210 inode->i_flags |= S_NOATIME;
211#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000212 inode->i_generation = generation;
213 inode->i_data.backing_dev_info = &fc->bdi;
214 fuse_init_inode(inode, attr);
215 unlock_new_inode(inode);
216 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
217 BUG_ON(retried);
218 /* Inode has changed type, any I/O on the old should fail */
219 make_bad_inode(inode);
220 iput(inode);
221 retried = 1;
222 goto retry;
223 }
224
Miklos Szeredi38009022005-05-08 19:47:22 +0000225 fi = get_fuse_inode(inode);
226 fi->nlookup ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000227 fuse_change_attributes(inode, attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000228 return inode;
229}
230#else
231static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
232 unsigned long nodeid = *(unsigned long *) _nodeidp;
233 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
234 return 1;
235 else
236 return 0;
237}
238
239struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
Miklos Szeredi38009022005-05-08 19:47:22 +0000240 int generation, struct fuse_attr *attr)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000241{
242 struct inode *inode;
Miklos Szeredi38009022005-05-08 19:47:22 +0000243 struct fuse_inode *fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000244 int retried = 0;
245
246 retry:
247 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
248 if (!inode)
249 return NULL;
250
251 if (!inode->u.generic_ip) {
252 get_fuse_inode(inode)->nodeid = nodeid;
253 inode->u.generic_ip = inode;
254 inode->i_generation = generation;
255 fuse_init_inode(inode, attr);
256 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
257 BUG_ON(retried);
258 /* Inode has changed type, any I/O on the old should fail */
259 remove_inode_hash(inode);
260 make_bad_inode(inode);
261 iput(inode);
262 retried = 1;
263 goto retry;
264 }
265
Miklos Szeredi38009022005-05-08 19:47:22 +0000266 fi = get_fuse_inode(inode);
267 fi->nlookup ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000268 fuse_change_attributes(inode, attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000269 return inode;
270}
271#endif
272
Miklos Szerediec3f6e42006-06-29 15:13:35 +0000273#ifdef KERNEL_2_6_18_PLUS
274static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
275{
276 if (flags & MNT_FORCE)
277 fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
278}
279#else
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000280static void fuse_umount_begin(struct super_block *sb)
281{
282 fuse_abort_conn(get_fuse_conn_super(sb));
283}
Miklos Szerediec3f6e42006-06-29 15:13:35 +0000284#endif
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000285
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000286static void fuse_put_super(struct super_block *sb)
287{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000288 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000289
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000290 spin_lock(&fc->lock);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000291 fc->connected = 0;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000292 fc->blocked = 0;
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000293 spin_unlock(&fc->lock);
Miklos Szeredi96249982001-11-21 12:21:19 +0000294 /* Flush all readers on this fs */
Miklos Szeredi5d9ce362006-03-01 12:10:13 +0000295 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
Miklos Szeredi96249982001-11-21 12:21:19 +0000296 wake_up_all(&fc->waitq);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000297 wake_up_all(&fc->blocked_waitq);
298 mutex_lock(&fuse_mutex);
299 list_del(&fc->entry);
300 fuse_ctl_remove_conn(fc);
301 mutex_unlock(&fuse_mutex);
302 fuse_conn_put(fc);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000303}
304
Miklos Szeredif85ab242004-01-07 12:16:45 +0000305static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000306{
307 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000308 stbuf->f_bsize = attr->bsize;
Miklos Szeredibb4b9742005-11-29 11:29:44 +0000309#ifdef KERNEL_2_6
Miklos Szeredi2b478112005-11-28 13:27:10 +0000310 stbuf->f_frsize = attr->frsize;
Miklos Szeredibb4b9742005-11-29 11:29:44 +0000311#endif
Mark Glinesd84b39a2002-01-07 16:32:02 +0000312 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000313 stbuf->f_bfree = attr->bfree;
314 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000315 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000316 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000317 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000318 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000319}
320
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000321#ifdef KERNEL_2_6_18_PLUS
322static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000323#else
324static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
325#endif
326{
327#ifdef KERNEL_2_6_18_PLUS
328 struct super_block *sb = dentry->d_sb;
329#endif
Miklos Szeredi039322d2004-12-01 18:39:12 +0000330 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000331 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000332 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 int err;
334
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000335 req = fuse_get_req(fc);
336 if (IS_ERR(req))
337 return PTR_ERR(req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000338
Miklos Szeredi2b478112005-11-28 13:27:10 +0000339 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000340 req->in.numargs = 0;
341 req->in.h.opcode = FUSE_STATFS;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000342#ifdef KERNEL_2_6_18_PLUS
343 req->in.h.nodeid = get_node_id(dentry->d_inode);
344#endif
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000345 req->out.numargs = 1;
Miklos Szerediead7f102005-11-28 16:02:27 +0000346 req->out.args[0].size =
Miklos Szeredi2b478112005-11-28 13:27:10 +0000347 fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000348 req->out.args[0].value = &outarg;
349 request_send(fc, req);
350 err = req->out.h.error;
351 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000352 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000353 fuse_put_request(fc, req);
354 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000355}
356
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000357enum {
358 OPT_FD,
359 OPT_ROOTMODE,
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000360 OPT_USER_ID,
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000361 OPT_GROUP_ID,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000362 OPT_DEFAULT_PERMISSIONS,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000363 OPT_ALLOW_OTHER,
Miklos Szeredie56818b2004-12-12 11:45:24 +0000364#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000365 OPT_LARGE_READ,
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000366#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000367 OPT_MAX_READ,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000368 OPT_ERR
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000369};
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000370
371static match_table_t tokens = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000372 {OPT_FD, "fd=%u"},
373 {OPT_ROOTMODE, "rootmode=%o"},
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000374 {OPT_USER_ID, "user_id=%u"},
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000375 {OPT_GROUP_ID, "group_id=%u"},
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000376 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
377 {OPT_ALLOW_OTHER, "allow_other"},
Miklos Szeredie56818b2004-12-12 11:45:24 +0000378#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000379 {OPT_LARGE_READ, "large_read"},
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000380#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000381 {OPT_MAX_READ, "max_read=%u"},
382 {OPT_ERR, NULL}
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000383};
384
385static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
386{
387 char *p;
388 memset(d, 0, sizeof(struct fuse_mount_data));
Miklos Szerediad051c32004-07-02 09:22:50 +0000389 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000390
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000391 while ((p = strsep(&opt, ",")) != NULL) {
392 int token;
393 int value;
394 substring_t args[MAX_OPT_ARGS];
395 if (!*p)
396 continue;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000397
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000398 token = match_token(p, tokens, args);
399 switch (token) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000400 case OPT_FD:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000401 if (match_int(&args[0], &value))
402 return 0;
403 d->fd = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000404 d->fd_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000405 break;
406
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000407 case OPT_ROOTMODE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000408 if (match_octal(&args[0], &value))
409 return 0;
410 d->rootmode = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000411 d->rootmode_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000412 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000413
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000414 case OPT_USER_ID:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000415 if (match_int(&args[0], &value))
416 return 0;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000417 d->user_id = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000418 d->user_id_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000419 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000420
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000421 case OPT_GROUP_ID:
422 if (match_int(&args[0], &value))
423 return 0;
424 d->group_id = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000425 d->group_id_present = 1;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000426 break;
427
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000428 case OPT_DEFAULT_PERMISSIONS:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000429 d->flags |= FUSE_DEFAULT_PERMISSIONS;
430 break;
431
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000432 case OPT_ALLOW_OTHER:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000433 d->flags |= FUSE_ALLOW_OTHER;
434 break;
435
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000436#ifndef KERNEL_2_6
Miklos Szeredie56818b2004-12-12 11:45:24 +0000437 case OPT_LARGE_READ:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000438 d->flags |= FUSE_LARGE_READ;
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000439 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000440#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000441 case OPT_MAX_READ:
Miklos Szerediad051c32004-07-02 09:22:50 +0000442 if (match_int(&args[0], &value))
443 return 0;
444 d->max_read = value;
445 break;
446
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000447 default:
448 return 0;
449 }
450 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000451
Miklos Szeredi437d8112005-07-06 09:14:20 +0000452 if (!d->fd_present || !d->rootmode_present ||
453 !d->user_id_present || !d->group_id_present)
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000454 return 0;
455
456 return 1;
457}
458
459static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
460{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000461 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000462
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000463 seq_printf(m, ",user_id=%u", fc->user_id);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000464 seq_printf(m, ",group_id=%u", fc->group_id);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000465 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
466 seq_puts(m, ",default_permissions");
467 if (fc->flags & FUSE_ALLOW_OTHER)
468 seq_puts(m, ",allow_other");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000469#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000470 if (fc->flags & FUSE_LARGE_READ)
471 seq_puts(m, ",large_read");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000472#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000473 if (fc->max_read != ~0)
474 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000475 return 0;
476}
477
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000478#ifndef HAVE_KZALLOC
479static void *kzalloc(size_t size, int flags)
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000480{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000481 void *ret = kmalloc(size, flags);
482 if (ret)
483 memset(ret, 0, size);
484 return ret;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000485}
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000486#endif
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000487static struct fuse_conn *new_conn(void)
488{
489 struct fuse_conn *fc;
490
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000491 fc = kzalloc(sizeof(*fc), GFP_KERNEL);
492 if (fc) {
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000493 spin_lock_init(&fc->lock);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000494 atomic_set(&fc->count, 1);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000495 init_waitqueue_head(&fc->waitq);
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000496 init_waitqueue_head(&fc->blocked_waitq);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000497 INIT_LIST_HEAD(&fc->pending);
498 INIT_LIST_HEAD(&fc->processing);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000499 INIT_LIST_HEAD(&fc->io);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000500 INIT_LIST_HEAD(&fc->interrupts);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000501 atomic_set(&fc->num_waiting, 0);
Miklos Szeredib6220192005-01-05 16:19:10 +0000502#ifdef KERNEL_2_6_6_PLUS
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000503 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
504 fc->bdi.unplug_io_fn = default_unplug_io_fn;
505#endif
Miklos Szeredie3b83092005-07-22 17:24:30 +0000506 fc->reqctr = 0;
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000507 fc->blocked = 1;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000508 get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000509 }
510 return fc;
511}
512
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000513void fuse_conn_put(struct fuse_conn *fc)
514{
515 if (atomic_dec_and_test(&fc->count))
516 kfree(fc);
517}
518
519struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
520{
521 atomic_inc(&fc->count);
522 return fc;
523}
524
Miklos Szeredi83a07442004-11-30 18:25:20 +0000525static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000526{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000527 struct fuse_attr attr;
528 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000529
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000530 attr.mode = mode;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000531 attr.ino = FUSE_ROOT_ID;
Miklos Szeredi38009022005-05-08 19:47:22 +0000532 return fuse_iget(sb, 1, 0, &attr);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000533}
Miklos Szeredi1b188022005-07-28 11:07:29 +0000534#ifndef FUSE_MAINLINE
Miklos Szeredie815c032004-01-19 18:20:49 +0000535#ifdef KERNEL_2_6
Miklos Szeredie815c032004-01-19 18:20:49 +0000536static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
537{
538 __u32 *objp = vobjp;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000539 unsigned long nodeid = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000540 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000541 struct inode *inode;
542 struct dentry *entry;
543
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000544 if (nodeid == 0)
Miklos Szeredia5288792005-03-05 16:46:52 +0000545 return ERR_PTR(-ESTALE);
Miklos Szeredie815c032004-01-19 18:20:49 +0000546
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000547 inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredif43f0632005-02-28 11:46:56 +0000548 if (!inode)
Miklos Szeredia5288792005-03-05 16:46:52 +0000549 return ERR_PTR(-ESTALE);
550 if (inode->i_generation != generation) {
551 iput(inode);
552 return ERR_PTR(-ESTALE);
553 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000554
555 entry = d_alloc_anon(inode);
Miklos Szeredia5288792005-03-05 16:46:52 +0000556 if (!entry) {
557 iput(inode);
558 return ERR_PTR(-ENOMEM);
559 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000560
561 return entry;
562}
563
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000564static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
565 int connectable)
566{
567 struct inode *inode = dentry->d_inode;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000568 int len = *max_len;
569 int type = 1;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000570
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000571 if (len < 2 || (connectable && len < 4))
572 return 255;
573
574 len = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000575 fh[0] = get_fuse_inode(inode)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000576 fh[1] = inode->i_generation;
577 if (connectable && !S_ISDIR(inode->i_mode)) {
578 struct inode *parent;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000579
580 spin_lock(&dentry->d_lock);
581 parent = dentry->d_parent->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000582 fh[2] = get_fuse_inode(parent)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000583 fh[3] = parent->i_generation;
584 spin_unlock(&dentry->d_lock);
585 len = 4;
586 type = 2;
587 }
588 *max_len = len;
589 return type;
590}
591
Miklos Szeredie815c032004-01-19 18:20:49 +0000592static struct export_operations fuse_export_operations = {
593 .get_dentry = fuse_get_dentry,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000594 .encode_fh = fuse_encode_fh,
Miklos Szeredie815c032004-01-19 18:20:49 +0000595};
596#endif
Miklos Szeredi1b188022005-07-28 11:07:29 +0000597#endif
Miklos Szeredie815c032004-01-19 18:20:49 +0000598
599static struct super_operations fuse_super_operations = {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000600 .alloc_inode = fuse_alloc_inode,
601 .destroy_inode = fuse_destroy_inode,
Miklos Szeredie815c032004-01-19 18:20:49 +0000602 .read_inode = fuse_read_inode,
603 .clear_inode = fuse_clear_inode,
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000604 .remount_fs = fuse_remount_fs,
Miklos Szeredie815c032004-01-19 18:20:49 +0000605 .put_super = fuse_put_super,
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000606 .umount_begin = fuse_umount_begin,
Miklos Szeredie815c032004-01-19 18:20:49 +0000607 .statfs = fuse_statfs,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000608 .show_options = fuse_show_options,
Miklos Szeredie815c032004-01-19 18:20:49 +0000609};
610
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000611static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
612{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000613 struct fuse_init_out *arg = &req->misc.init_out;
614
615 if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
616 fc->conn_error = 1;
617 else {
Miklos Szeredi065f2222006-01-20 15:15:21 +0000618#ifdef KERNEL_2_6
619 unsigned long ra_pages;
620
621 if (arg->minor >= 6) {
622 ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
Miklos Szeredif8277502006-01-20 17:16:27 +0000623 if (arg->flags & FUSE_ASYNC_READ)
624 fc->async_read = 1;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000625 if (!(arg->flags & FUSE_POSIX_LOCKS))
626 fc->no_lock = 1;
627 } else {
Miklos Szeredi065f2222006-01-20 15:15:21 +0000628 ra_pages = fc->max_read / PAGE_CACHE_SIZE;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000629 fc->no_lock = 1;
630 }
Miklos Szeredi065f2222006-01-20 15:15:21 +0000631
632 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
633#endif
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000634 fc->minor = arg->minor;
635 fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
636 }
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000637 fuse_put_request(fc, req);
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000638 fc->blocked = 0;
639 wake_up_all(&fc->blocked_waitq);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000640}
641
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000642static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000643{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000644 struct fuse_init_in *arg = &req->misc.init_in;
645
646 arg->major = FUSE_KERNEL_VERSION;
647 arg->minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000648#ifdef KERNEL_2_6
649 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000650 arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000651#endif
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000652 req->in.h.opcode = FUSE_INIT;
653 req->in.numargs = 1;
654 req->in.args[0].size = sizeof(*arg);
655 req->in.args[0].value = arg;
656 req->out.numargs = 1;
657 /* Variable length arguement used for backward compatibility
658 with interface version < 7.5. Rest of init_out is zeroed
659 by do_get_request(), so a short reply is not a problem */
660 req->out.argvar = 1;
661 req->out.args[0].size = sizeof(struct fuse_init_out);
662 req->out.args[0].value = &req->misc.init_out;
663 req->end = process_init_reply;
664 request_send_background(fc, req);
665}
666
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000667static u64 conn_id(void)
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000668{
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000669 static u64 ctr = 1;
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000670 return ctr++;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000671}
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000672
Miklos Szeredi81394522005-01-11 14:24:18 +0000673static int fuse_fill_super(struct super_block *sb, void *data, int silent)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000674{
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000675 struct fuse_conn *fc;
676 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000677 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000678 struct file *file;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000679 struct dentry *root_dentry;
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000680 struct fuse_req *init_req;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000681 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000682
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000683 if (sb->s_flags & MS_MANDLOCK)
684 return -EINVAL;
685
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000686 if (!parse_fuse_opt((char *) data, &d))
687 return -EINVAL;
688
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000689 sb->s_blocksize = PAGE_CACHE_SIZE;
690 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
691 sb->s_magic = FUSE_SUPER_MAGIC;
692 sb->s_op = &fuse_super_operations;
693 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000694#ifndef FUSE_MAINLINE
Miklos Szeredie815c032004-01-19 18:20:49 +0000695#ifdef KERNEL_2_6
696 sb->s_export_op = &fuse_export_operations;
697#endif
Miklos Szeredi1b188022005-07-28 11:07:29 +0000698#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000699
Miklos Szeredied62d862004-06-20 08:57:39 +0000700 file = fget(d.fd);
701 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000702 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000703
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000704 if (file->f_op != &fuse_dev_operations)
705 return -EINVAL;
706
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000707 fc = new_conn();
708 if (!fc)
709 return -ENOMEM;
Miklos Szeredied62d862004-06-20 08:57:39 +0000710
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000711 fc->flags = d.flags;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000712 fc->user_id = d.user_id;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000713 fc->group_id = d.group_id;
Miklos Szerediad051c32004-07-02 09:22:50 +0000714 fc->max_read = d.max_read;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000715
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000716 /* Used by get_root_inode() */
717 sb->s_fs_info = fc;
718
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000719 err = -ENOMEM;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000720 root = get_root_inode(sb, d.rootmode);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000721 if (!root)
Miklos Szeredied62d862004-06-20 08:57:39 +0000722 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000723
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000724 root_dentry = d_alloc_root(root);
725 if (!root_dentry) {
Miklos Szeredied62d862004-06-20 08:57:39 +0000726 iput(root);
727 goto err;
728 }
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000729
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000730 init_req = fuse_request_alloc();
731 if (!init_req)
732 goto err_put_root;
733
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000734 mutex_lock(&fuse_mutex);
Miklos Szeredi5fe07d62006-04-21 14:09:28 +0000735 err = -EINVAL;
736 if (file->private_data)
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000737 goto err_unlock;
Miklos Szeredi5fe07d62006-04-21 14:09:28 +0000738
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000739 fc->id = conn_id();
740 err = fuse_ctl_add_conn(fc);
741 if (err)
742 goto err_unlock;
743
744 list_add_tail(&fc->entry, &fuse_conn_list);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000745 sb->s_root = root_dentry;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000746 fc->connected = 1;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000747 file->private_data = fuse_conn_get(fc);
748 mutex_unlock(&fuse_mutex);
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000749 /*
750 * atomic_dec_and_test() in fput() provides the necessary
751 * memory barrier for file->private_data to be visible on all
752 * CPUs after this
753 */
754 fput(file);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000755
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000756 fuse_send_init(fc, init_req);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000757
Miklos Szeredif85ab242004-01-07 12:16:45 +0000758 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000759
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000760 err_unlock:
761 mutex_unlock(&fuse_mutex);
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000762 fuse_request_free(init_req);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000763 err_put_root:
764 dput(root_dentry);
Miklos Szeredied62d862004-06-20 08:57:39 +0000765 err:
Miklos Szeredi67d26d42006-03-13 17:39:56 +0000766 fput(file);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000767 fuse_conn_put(fc);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000768 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000769}
770
Miklos Szeredif85ab242004-01-07 12:16:45 +0000771#ifdef KERNEL_2_6
Miklos Szerediec3f6e42006-06-29 15:13:35 +0000772#ifdef KERNEL_2_6_18_PLUS
773static int fuse_get_sb(struct file_system_type *fs_type,
774 int flags, const char *dev_name,
775 void *raw_data, struct vfsmount *mnt)
776{
777 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
778}
779#else
Miklos Szeredif85ab242004-01-07 12:16:45 +0000780static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000781 int flags, const char *dev_name,
782 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000783{
Miklos Szeredi81394522005-01-11 14:24:18 +0000784 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000785}
Miklos Szerediec3f6e42006-06-29 15:13:35 +0000786#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000787
Miklos Szeredif85ab242004-01-07 12:16:45 +0000788static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000789 .owner = THIS_MODULE,
790 .name = "fuse",
791 .get_sb = fuse_get_sb,
792 .kill_sb = kill_anon_super,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000793};
794#else
795static struct super_block *fuse_read_super_compat(struct super_block *sb,
796 void *data, int silent)
797{
Miklos Szeredi81394522005-01-11 14:24:18 +0000798 int err = fuse_fill_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000799 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000800 return NULL;
801 else
802 return sb;
803}
804
805static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
806#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000807
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000808#ifdef KERNEL_2_6
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000809#ifndef HAVE_FS_SUBSYS
810static decl_subsys(fs, NULL, NULL);
811#endif
812static decl_subsys(fuse, NULL, NULL);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000813static decl_subsys(connections, NULL, NULL);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000814#endif /* KERNEL_2_6 */
815
Miklos Szeredi81394522005-01-11 14:24:18 +0000816static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
Miklos Szeredia13d9002004-11-02 17:32:03 +0000817 unsigned long flags)
818{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000819 struct inode * inode = foo;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000820
821 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
822 SLAB_CTOR_CONSTRUCTOR)
823 inode_init_once(inode);
824}
825
Miklos Szeredi9080c792005-01-08 11:50:08 +0000826static int __init fuse_fs_init(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000827{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000828 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000829
Miklos Szeredi069c9502004-07-16 16:17:02 +0000830 err = register_filesystem(&fuse_fs_type);
831 if (err)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000832 printk("fuse: failed to register filesystem\n");
Miklos Szeredi069c9502004-07-16 16:17:02 +0000833 else {
834 fuse_inode_cachep = kmem_cache_create("fuse_inode",
Miklos Szeredi81394522005-01-11 14:24:18 +0000835 sizeof(struct fuse_inode),
Miklos Szeredia13d9002004-11-02 17:32:03 +0000836 0, SLAB_HWCACHE_ALIGN,
837 fuse_inode_init_once, NULL);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000838 if (!fuse_inode_cachep) {
839 unregister_filesystem(&fuse_fs_type);
840 err = -ENOMEM;
841 }
842 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000843
Miklos Szeredi069c9502004-07-16 16:17:02 +0000844 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000845}
846
Miklos Szeredi9080c792005-01-08 11:50:08 +0000847static void fuse_fs_cleanup(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000848{
849 unregister_filesystem(&fuse_fs_type);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000850 kmem_cache_destroy(fuse_inode_cachep);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000851}
Miklos Szeredi9080c792005-01-08 11:50:08 +0000852
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000853#ifdef KERNEL_2_6
854static int fuse_sysfs_init(void)
855{
856 int err;
857
858#ifndef HAVE_FS_SUBSYS
859 err = subsystem_register(&fs_subsys);
860 if (err)
861 return err;
862#endif
863 kset_set_kset_s(&fuse_subsys, fs_subsys);
864 err = subsystem_register(&fuse_subsys);
865 if (err)
866 goto out_err;
867
868 kset_set_kset_s(&connections_subsys, fuse_subsys);
869 err = subsystem_register(&connections_subsys);
870 if (err)
871 goto out_fuse_unregister;
872
873 return 0;
874
875 out_fuse_unregister:
876 subsystem_unregister(&fuse_subsys);
877 out_err:
878#ifndef HAVE_FS_SUBSYS
879 subsystem_unregister(&fs_subsys);
880#endif
881 return err;
882}
883
884static void fuse_sysfs_cleanup(void)
885{
886 subsystem_unregister(&connections_subsys);
887 subsystem_unregister(&fuse_subsys);
888#ifndef HAVE_FS_SUBSYS
889 subsystem_unregister(&fs_subsys);
890#endif
891}
892#else /* KERNEL_2_6 */
893static int fuse_sysfs_init(void)
894{
895 return 0;
896}
897static void fuse_sysfs_cleanup(void)
898{
899}
900#endif /* KERNEL_2_6 */
901
Miklos Szeredi81394522005-01-11 14:24:18 +0000902static int __init fuse_init(void)
Miklos Szeredi9080c792005-01-08 11:50:08 +0000903{
904 int res;
905
906 printk("fuse init (API version %i.%i)\n",
907 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
908#ifndef FUSE_MAINLINE
909 printk("fuse distribution version: %s\n", FUSE_VERSION);
910#endif
911
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000912 INIT_LIST_HEAD(&fuse_conn_list);
Miklos Szeredi9080c792005-01-08 11:50:08 +0000913 res = fuse_fs_init();
914 if (res)
915 goto err;
916
917 res = fuse_dev_init();
918 if (res)
919 goto err_fs_cleanup;
920
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000921 res = fuse_sysfs_init();
922 if (res)
923 goto err_dev_cleanup;
924
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000925 res = fuse_ctl_init();
926 if (res)
927 goto err_sysfs_cleanup;
928
Miklos Szeredi9080c792005-01-08 11:50:08 +0000929 return 0;
930
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000931 err_sysfs_cleanup:
932 fuse_sysfs_cleanup();
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000933 err_dev_cleanup:
934 fuse_dev_cleanup();
Miklos Szeredi9080c792005-01-08 11:50:08 +0000935 err_fs_cleanup:
936 fuse_fs_cleanup();
937 err:
938 return res;
939}
940
Miklos Szeredi81394522005-01-11 14:24:18 +0000941static void __exit fuse_exit(void)
Miklos Szeredi9080c792005-01-08 11:50:08 +0000942{
943 printk(KERN_DEBUG "fuse exit\n");
944
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000945 fuse_ctl_cleanup();
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000946 fuse_sysfs_cleanup();
Miklos Szeredi9080c792005-01-08 11:50:08 +0000947 fuse_fs_cleanup();
948 fuse_dev_cleanup();
949}
950
951module_init(fuse_init);
952module_exit(fuse_exit);