blob: 525a5b667ddb7252c4ed7342277210e225a9fae8 [file] [log] [blame]
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2004 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/mount.h>
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000015#include <linux/seq_file.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 Szeredi13ed4822004-11-20 11:12:21 +000018#include <linux/moduleparam.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000019#include <linux/parser.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000020#include <linux/statfs.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000021#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +000022#include <linux/proc_fs.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000023#include "compat/parser.h"
Miklos Szeredif85ab242004-01-07 12:16:45 +000024#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000025
Miklos Szeredi069c9502004-07-16 16:17:02 +000026static kmem_cache_t *fuse_inode_cachep;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000027static int mount_count;
Miklos Szerediacb4d362004-07-02 16:20:45 +000028
Miklos Szeredi13ed4822004-11-20 11:12:21 +000029static int user_allow_other;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000030static int mount_max = 1000;
Miklos Szerediacb4d362004-07-02 16:20:45 +000031#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +000032module_param(user_allow_other, int, 0644);
Miklos Szeredi0f62d722005-01-04 12:45:54 +000033module_param(mount_max, int, 0644);
Miklos Szerediacb4d362004-07-02 16:20:45 +000034#else
35MODULE_PARM(user_allow_other, "i");
Miklos Szeredi0f62d722005-01-04 12:45:54 +000036MODULE_PARM(mount_max, "i");
Miklos Szerediacb4d362004-07-02 16:20:45 +000037#endif
Miklos Szeredi180ff692004-11-01 16:01:05 +000038MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
Miklos Szeredi0f62d722005-01-04 12:45:54 +000039MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)");
Miklos Szerediacb4d362004-07-02 16:20:45 +000040
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000041#define FUSE_SUPER_MAGIC 0x65735546
42
Miklos Szeredif85ab242004-01-07 12:16:45 +000043#ifndef KERNEL_2_6
44#define kstatfs statfs
45#endif
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000046#ifndef FS_SAFE
47#define FS_SAFE 0
48#endif
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000049#ifndef MAX_LFS_FILESIZE
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000050#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000051#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000052struct fuse_mount_data {
53 int fd;
Miklos Szeredi83a07442004-11-30 18:25:20 +000054 unsigned rootmode;
55 unsigned uid;
56 unsigned flags;
57 unsigned max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000058};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000059
Miklos Szeredia13d9002004-11-02 17:32:03 +000060static struct inode *fuse_alloc_inode(struct super_block *sb)
Miklos Szeredi069c9502004-07-16 16:17:02 +000061{
Miklos Szeredia13d9002004-11-02 17:32:03 +000062 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000063 struct fuse_inode *fi;
64
Miklos Szeredia13d9002004-11-02 17:32:03 +000065 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
66 if (!inode)
67 return NULL;
Miklos Szeredi069c9502004-07-16 16:17:02 +000068
Miklos Szeredia13d9002004-11-02 17:32:03 +000069#ifndef KERNEL_2_6
70 inode->u.generic_ip = NULL;
71#endif
72
Miklos Szeredi039322d2004-12-01 18:39:12 +000073 fi = get_fuse_inode(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +000074 memset(fi, 0, sizeof(*fi));
75 fi->forget_req = fuse_request_alloc();
76 if (!fi->forget_req) {
77 kmem_cache_free(fuse_inode_cachep, inode);
78 return NULL;
79 }
Miklos Szeredia13d9002004-11-02 17:32:03 +000080
81 return inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000082}
83
Miklos Szeredia13d9002004-11-02 17:32:03 +000084static void fuse_destroy_inode(struct inode *inode)
Miklos Szeredi069c9502004-07-16 16:17:02 +000085{
Miklos Szeredi039322d2004-12-01 18:39:12 +000086 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000087 if (fi->forget_req)
88 fuse_request_free(fi->forget_req);
Miklos Szeredia13d9002004-11-02 17:32:03 +000089 kmem_cache_free(fuse_inode_cachep, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +000090}
91
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000092static void fuse_read_inode(struct inode *inode)
93{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000094 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000095}
96
Miklos Szeredia13d9002004-11-02 17:32:03 +000097void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
98 unsigned long nodeid, int version)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +000099{
100 struct fuse_forget_in *inarg = &req->misc.forget_in;
101 inarg->version = version;
102 req->in.h.opcode = FUSE_FORGET;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000103 req->in.h.nodeid = nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000104 req->in.numargs = 1;
105 req->in.args[0].size = sizeof(struct fuse_forget_in);
106 req->in.args[0].value = inarg;
107 request_send_noreply(fc, req);
108}
109
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000110static void fuse_clear_inode(struct inode *inode)
111{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000112 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000113 if (fc) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000114 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000115 fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
116 fi->forget_req = NULL;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000117 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000118}
119
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
121{
122 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
123#ifdef KERNEL_2_6
124 invalidate_inode_pages(inode->i_mapping);
125#else
126 invalidate_inode_pages(inode);
127#endif
128
129 inode->i_ino = attr->ino;
130 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
131 inode->i_nlink = attr->nlink;
132 inode->i_uid = attr->uid;
133 inode->i_gid = attr->gid;
134 i_size_write(inode, attr->size);
135 inode->i_blksize = PAGE_CACHE_SIZE;
136 inode->i_blocks = attr->blocks;
137#ifdef KERNEL_2_6
138 inode->i_atime.tv_sec = attr->atime;
139 inode->i_atime.tv_nsec = attr->atimensec;
140 inode->i_mtime.tv_sec = attr->mtime;
141 inode->i_mtime.tv_nsec = attr->mtimensec;
142 inode->i_ctime.tv_sec = attr->ctime;
143 inode->i_ctime.tv_nsec = attr->ctimensec;
144#else
145 inode->i_atime = attr->atime;
146 inode->i_mtime = attr->mtime;
147 inode->i_ctime = attr->ctime;
148#endif
149}
150
151static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
152{
153 inode->i_mode = attr->mode & S_IFMT;
154 i_size_write(inode, attr->size);
155 if (S_ISREG(inode->i_mode)) {
156 fuse_init_common(inode);
157 fuse_init_file_inode(inode);
158 } else if (S_ISDIR(inode->i_mode))
159 fuse_init_dir(inode);
160 else if (S_ISLNK(inode->i_mode))
161 fuse_init_symlink(inode);
162 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
163 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
164 fuse_init_common(inode);
165 init_special_inode(inode, inode->i_mode,
166 new_decode_dev(attr->rdev));
167 } else {
168 /* Don't let user create weird files */
169 inode->i_mode = S_IFREG;
170 fuse_init_common(inode);
171 fuse_init_file_inode(inode);
172 }
173}
174
175#ifdef KERNEL_2_6
176static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
177{
178 unsigned long nodeid = *(unsigned long *) _nodeidp;
179 if (get_node_id(inode) == nodeid)
180 return 1;
181 else
182 return 0;
183}
184
185static int fuse_inode_set(struct inode *inode, void *_nodeidp)
186{
187 unsigned long nodeid = *(unsigned long *) _nodeidp;
188 get_fuse_inode(inode)->nodeid = nodeid;
189 return 0;
190}
191
192struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
193 int generation, struct fuse_attr *attr, int version)
194{
195 struct inode *inode;
196 struct fuse_conn *fc = get_fuse_conn_super(sb);
197 int retried = 0;
198
199 retry:
200 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
201 if (!inode)
202 return NULL;
203
204 if ((inode->i_state & I_NEW)) {
205 inode->i_generation = generation;
206 inode->i_data.backing_dev_info = &fc->bdi;
207 fuse_init_inode(inode, attr);
208 unlock_new_inode(inode);
209 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
210 BUG_ON(retried);
211 /* Inode has changed type, any I/O on the old should fail */
212 make_bad_inode(inode);
213 iput(inode);
214 retried = 1;
215 goto retry;
216 }
217
218 fuse_change_attributes(inode, attr);
219 inode->i_version = version;
220 return inode;
221}
222#else
223static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
224 unsigned long nodeid = *(unsigned long *) _nodeidp;
225 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
226 return 1;
227 else
228 return 0;
229}
230
231struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
232 int generation, struct fuse_attr *attr, int version)
233{
234 struct inode *inode;
235 int retried = 0;
236
237 retry:
238 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
239 if (!inode)
240 return NULL;
241
242 if (!inode->u.generic_ip) {
243 get_fuse_inode(inode)->nodeid = nodeid;
244 inode->u.generic_ip = inode;
245 inode->i_generation = generation;
246 fuse_init_inode(inode, attr);
247 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
248 BUG_ON(retried);
249 /* Inode has changed type, any I/O on the old should fail */
250 remove_inode_hash(inode);
251 make_bad_inode(inode);
252 iput(inode);
253 retried = 1;
254 goto retry;
255 }
256
257 fuse_change_attributes(inode, attr);
258 inode->i_version = version;
259 return inode;
260}
261#endif
262
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000263static void fuse_put_super(struct super_block *sb)
264{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000265 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000266
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000267 spin_lock(&fuse_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000268 mount_count --;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000269 fc->sb = NULL;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000270 fc->uid = 0;
271 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +0000272 /* Flush all readers on this fs */
273 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +0000274 fuse_release_conn(fc);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000275 *get_fuse_conn_super_p(sb) = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000276 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000277}
278
Miklos Szeredif85ab242004-01-07 12:16:45 +0000279static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000280{
281 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000282 stbuf->f_bsize = attr->bsize;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000283 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000284 stbuf->f_bfree = attr->bfree;
285 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000286 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000287 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000288 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000289 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000290}
291
Miklos Szeredif85ab242004-01-07 12:16:45 +0000292static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000293{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000294 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000295 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000296 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000297 int err;
298
299 req = fuse_get_request(fc);
300 if (!req)
301 return -ERESTARTSYS;
302
303 req->in.numargs = 0;
304 req->in.h.opcode = FUSE_STATFS;
305 req->out.numargs = 1;
306 req->out.args[0].size = sizeof(outarg);
307 req->out.args[0].value = &outarg;
308 request_send(fc, req);
309 err = req->out.h.error;
310 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000311 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 fuse_put_request(fc, req);
313 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000314}
315
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000316enum {
317 OPT_FD,
318 OPT_ROOTMODE,
319 OPT_UID,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000320 OPT_DEFAULT_PERMISSIONS,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000321 OPT_ALLOW_OTHER,
322 OPT_ALLOW_ROOT,
323 OPT_KERNEL_CACHE,
Miklos Szeredie56818b2004-12-12 11:45:24 +0000324#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000325 OPT_LARGE_READ,
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000326#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000327 OPT_DIRECT_IO,
328 OPT_MAX_READ,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000329 OPT_ERR
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000330};
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000331
332static match_table_t tokens = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000333 {OPT_FD, "fd=%u"},
334 {OPT_ROOTMODE, "rootmode=%o"},
335 {OPT_UID, "uid=%u"},
336 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
337 {OPT_ALLOW_OTHER, "allow_other"},
338 {OPT_ALLOW_ROOT, "allow_root"},
339 {OPT_KERNEL_CACHE, "kernel_cache"},
Miklos Szeredie56818b2004-12-12 11:45:24 +0000340#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000341 {OPT_LARGE_READ, "large_read"},
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000342#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000343 {OPT_DIRECT_IO, "direct_io"},
344 {OPT_MAX_READ, "max_read=%u"},
345 {OPT_ERR, NULL}
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000346};
347
348static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
349{
350 char *p;
351 memset(d, 0, sizeof(struct fuse_mount_data));
352 d->fd = -1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000353 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000354
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000355 while ((p = strsep(&opt, ",")) != NULL) {
356 int token;
357 int value;
358 substring_t args[MAX_OPT_ARGS];
359 if (!*p)
360 continue;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000361
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000362 token = match_token(p, tokens, args);
363 switch (token) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000364 case OPT_FD:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000365 if (match_int(&args[0], &value))
366 return 0;
367 d->fd = value;
368 break;
369
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000370 case OPT_ROOTMODE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000371 if (match_octal(&args[0], &value))
372 return 0;
373 d->rootmode = value;
374 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000375
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000376 case OPT_UID:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000377 if (match_int(&args[0], &value))
378 return 0;
379 d->uid = value;
380 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000381
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000382 case OPT_DEFAULT_PERMISSIONS:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000383 d->flags |= FUSE_DEFAULT_PERMISSIONS;
384 break;
385
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000386 case OPT_ALLOW_OTHER:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000387 d->flags |= FUSE_ALLOW_OTHER;
388 break;
389
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000390 case OPT_ALLOW_ROOT:
Miklos Szeredi180ff692004-11-01 16:01:05 +0000391 d->flags |= FUSE_ALLOW_ROOT;
392 break;
393
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000394 case OPT_KERNEL_CACHE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000395 d->flags |= FUSE_KERNEL_CACHE;
396 break;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000397
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000398#ifndef KERNEL_2_6
Miklos Szeredie56818b2004-12-12 11:45:24 +0000399 case OPT_LARGE_READ:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000400 d->flags |= FUSE_LARGE_READ;
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000401 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000402#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000403 case OPT_DIRECT_IO:
Miklos Szerediad051c32004-07-02 09:22:50 +0000404 d->flags |= FUSE_DIRECT_IO;
405 break;
406
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000407 case OPT_MAX_READ:
Miklos Szerediad051c32004-07-02 09:22:50 +0000408 if (match_int(&args[0], &value))
409 return 0;
410 d->max_read = value;
411 break;
412
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000413 default:
414 return 0;
415 }
416 }
417 if (d->fd == -1)
418 return 0;
419
420 return 1;
421}
422
423static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
424{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000425 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000426
427 seq_printf(m, ",uid=%u", fc->uid);
428 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
429 seq_puts(m, ",default_permissions");
430 if (fc->flags & FUSE_ALLOW_OTHER)
431 seq_puts(m, ",allow_other");
Miklos Szeredi180ff692004-11-01 16:01:05 +0000432 if (fc->flags & FUSE_ALLOW_ROOT)
433 seq_puts(m, ",allow_root");
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000434 if (fc->flags & FUSE_KERNEL_CACHE)
435 seq_puts(m, ",kernel_cache");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000436#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000437 if (fc->flags & FUSE_LARGE_READ)
438 seq_puts(m, ",large_read");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000439#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000440 if (fc->flags & FUSE_DIRECT_IO)
441 seq_puts(m, ",direct_io");
442 if (fc->max_read != ~0)
443 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000444 return 0;
445}
446
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000447static void free_conn(struct fuse_conn *fc)
448{
449 while (!list_empty(&fc->unused_list)) {
450 struct fuse_req *req;
451 req = list_entry(fc->unused_list.next, struct fuse_req, list);
452 list_del(&req->list);
453 fuse_request_free(req);
454 }
455 kfree(fc);
456}
457
458/* Must be called with the fuse lock held */
459void fuse_release_conn(struct fuse_conn *fc)
460{
461 if (!fc->sb && !fc->file)
462 free_conn(fc);
463}
464
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000465static struct fuse_conn *new_conn(void)
466{
467 struct fuse_conn *fc;
468
469 fc = kmalloc(sizeof(*fc), GFP_KERNEL);
470 if (fc != NULL) {
471 int i;
472 memset(fc, 0, sizeof(*fc));
473 fc->sb = NULL;
474 fc->file = NULL;
475 fc->flags = 0;
476 fc->uid = 0;
477 init_waitqueue_head(&fc->waitq);
478 INIT_LIST_HEAD(&fc->pending);
479 INIT_LIST_HEAD(&fc->processing);
480 INIT_LIST_HEAD(&fc->unused_list);
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000481 sema_init(&fc->outstanding_sem, 0);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000482 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
483 struct fuse_req *req = fuse_request_alloc();
484 if (!req) {
485 free_conn(fc);
486 return NULL;
487 }
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000488 list_add(&req->list, &fc->unused_list);
489 }
Miklos Szeredib6220192005-01-05 16:19:10 +0000490#ifdef KERNEL_2_6_6_PLUS
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000491 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
492 fc->bdi.unplug_io_fn = default_unplug_io_fn;
493#endif
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000494 fc->reqctr = 1;
495 }
496 return fc;
497}
498
Miklos Szeredied62d862004-06-20 08:57:39 +0000499static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000500{
Miklos Szeredied62d862004-06-20 08:57:39 +0000501 struct fuse_conn *fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000502
Miklos Szeredie56818b2004-12-12 11:45:24 +0000503 if (file->f_op != &fuse_dev_operations)
Miklos Szeredied62d862004-06-20 08:57:39 +0000504 return NULL;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000505 fc = new_conn();
Miklos Szeredie56818b2004-12-12 11:45:24 +0000506 if (fc == NULL)
Miklos Szeredied62d862004-06-20 08:57:39 +0000507 return NULL;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000508 spin_lock(&fuse_lock);
509 if (file->private_data) {
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000510 free_conn(fc);
511 fc = NULL;
512 } else {
513 file->private_data = fc;
514 fc->sb = sb;
515 fc->file = file;
516 }
517 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000518 return fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000519}
520
Miklos Szeredi83a07442004-11-30 18:25:20 +0000521static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000522{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000523 struct fuse_attr attr;
524 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000525
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000526 attr.mode = mode;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000527 attr.ino = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000528 return fuse_iget(sb, 1, 0, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000529}
530
Miklos Szeredie815c032004-01-19 18:20:49 +0000531#ifdef KERNEL_2_6
Miklos Szeredie815c032004-01-19 18:20:49 +0000532static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
533{
534 __u32 *objp = vobjp;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000535 unsigned long nodeid = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000536 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000537 struct inode *inode;
538 struct dentry *entry;
539
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000540 if (nodeid == 0)
Miklos Szeredie815c032004-01-19 18:20:49 +0000541 return ERR_PTR(-ESTALE);
542
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000543 inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000544 if (!inode || inode->i_generation != generation)
Miklos Szeredie815c032004-01-19 18:20:49 +0000545 return ERR_PTR(-ESTALE);
546
547 entry = d_alloc_anon(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000548 if (!entry) {
Miklos Szeredie815c032004-01-19 18:20:49 +0000549 iput(inode);
550 return ERR_PTR(-ENOMEM);
551 }
552
553 return entry;
554}
555
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000556static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
557 int connectable)
558{
559 struct inode *inode = dentry->d_inode;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000560 int len = *max_len;
561 int type = 1;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000562
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000563 if (len < 2 || (connectable && len < 4))
564 return 255;
565
566 len = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000567 fh[0] = get_fuse_inode(inode)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000568 fh[1] = inode->i_generation;
569 if (connectable && !S_ISDIR(inode->i_mode)) {
570 struct inode *parent;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000571
572 spin_lock(&dentry->d_lock);
573 parent = dentry->d_parent->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000574 fh[2] = get_fuse_inode(parent)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000575 fh[3] = parent->i_generation;
576 spin_unlock(&dentry->d_lock);
577 len = 4;
578 type = 2;
579 }
580 *max_len = len;
581 return type;
582}
583
Miklos Szeredie815c032004-01-19 18:20:49 +0000584static struct export_operations fuse_export_operations = {
585 .get_dentry = fuse_get_dentry,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000586 .encode_fh = fuse_encode_fh,
Miklos Szeredie815c032004-01-19 18:20:49 +0000587};
588#endif
589
590static struct super_operations fuse_super_operations = {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000591 .alloc_inode = fuse_alloc_inode,
592 .destroy_inode = fuse_destroy_inode,
Miklos Szeredie815c032004-01-19 18:20:49 +0000593 .read_inode = fuse_read_inode,
594 .clear_inode = fuse_clear_inode,
595 .put_super = fuse_put_super,
596 .statfs = fuse_statfs,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000597 .show_options = fuse_show_options,
Miklos Szeredie815c032004-01-19 18:20:49 +0000598};
599
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000600static int inc_mount_count(void)
601{
602 int success = 0;
603 spin_lock(&fuse_lock);
604 mount_count ++;
605 if (mount_max == -1 || mount_count <= mount_max)
606 success = 1;
607 spin_unlock(&fuse_lock);
608 return success;
609}
610
Miklos Szeredif85ab242004-01-07 12:16:45 +0000611static int fuse_read_super(struct super_block *sb, void *data, int silent)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000612{
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000613 struct fuse_conn *fc;
614 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000615 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000616 struct file *file;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000617 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000618
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000619 if (!parse_fuse_opt((char *) data, &d))
620 return -EINVAL;
621
Miklos Szeredi180ff692004-11-01 16:01:05 +0000622 if (!user_allow_other &&
623 (d.flags & (FUSE_ALLOW_OTHER | FUSE_ALLOW_ROOT)) &&
Miklos Szerediacb4d362004-07-02 16:20:45 +0000624 current->uid != 0)
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000625 return -EPERM;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000626
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000627 sb->s_blocksize = PAGE_CACHE_SIZE;
628 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
629 sb->s_magic = FUSE_SUPER_MAGIC;
630 sb->s_op = &fuse_super_operations;
631 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredie815c032004-01-19 18:20:49 +0000632#ifdef KERNEL_2_6
633 sb->s_export_op = &fuse_export_operations;
634#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000635
Miklos Szeredied62d862004-06-20 08:57:39 +0000636 file = fget(d.fd);
637 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000638 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000639
Miklos Szeredied62d862004-06-20 08:57:39 +0000640 fc = get_conn(file, sb);
Miklos Szeredied62d862004-06-20 08:57:39 +0000641 fput(file);
642 if (fc == NULL)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000643 return -EINVAL;
Miklos Szeredied62d862004-06-20 08:57:39 +0000644
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000645 fc->flags = d.flags;
646 fc->uid = d.uid;
Miklos Szerediad051c32004-07-02 09:22:50 +0000647 fc->max_read = d.max_read;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000648#ifdef KERNEL_2_6
649 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
650 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
651#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000652 fc->max_write = FUSE_MAX_IN / 2;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000653
Miklos Szeredi039322d2004-12-01 18:39:12 +0000654 *get_fuse_conn_super_p(sb) = fc;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000655
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000656 err = -ENFILE;
657 if (!inc_mount_count() && current->uid != 0)
658 goto err;
659
660 err = -ENOMEM;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000661 root = get_root_inode(sb, d.rootmode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000662 if (root == NULL)
Miklos Szeredied62d862004-06-20 08:57:39 +0000663 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000664
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000665 sb->s_root = d_alloc_root(root);
Miklos Szeredied62d862004-06-20 08:57:39 +0000666 if (!sb->s_root) {
667 iput(root);
668 goto err;
669 }
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000670 fuse_send_init(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000671 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000672
673 err:
674 spin_lock(&fuse_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000675 mount_count --;
Miklos Szeredied62d862004-06-20 08:57:39 +0000676 fc->sb = NULL;
677 fuse_release_conn(fc);
678 spin_unlock(&fuse_lock);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000679 *get_fuse_conn_super_p(sb) = NULL;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000680 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000681}
682
Miklos Szeredif85ab242004-01-07 12:16:45 +0000683#ifdef KERNEL_2_6
684static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000685 int flags, const char *dev_name,
686 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000687{
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000688 return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000689}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000690
Miklos Szeredif85ab242004-01-07 12:16:45 +0000691static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000692 .owner = THIS_MODULE,
693 .name = "fuse",
694 .get_sb = fuse_get_sb,
695 .kill_sb = kill_anon_super,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000696#ifndef FUSE_MAINLINE
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000697 .fs_flags = FS_SAFE,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000698#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +0000699};
700#else
701static struct super_block *fuse_read_super_compat(struct super_block *sb,
702 void *data, int silent)
703{
704 int err = fuse_read_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000705 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000706 return NULL;
707 else
708 return sb;
709}
710
711static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
712#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000713
Miklos Szeredia13d9002004-11-02 17:32:03 +0000714static void fuse_inode_init_once(void * foo, kmem_cache_t * cachep,
715 unsigned long flags)
716{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000717 struct inode * inode = foo;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000718
719 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
720 SLAB_CTOR_CONSTRUCTOR)
721 inode_init_once(inode);
722}
723
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000724int fuse_fs_init(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000725{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000726 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000727
Miklos Szeredi069c9502004-07-16 16:17:02 +0000728 err = register_filesystem(&fuse_fs_type);
729 if (err)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000730 printk("fuse: failed to register filesystem\n");
Miklos Szeredi069c9502004-07-16 16:17:02 +0000731 else {
732 fuse_inode_cachep = kmem_cache_create("fuse_inode",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000733 sizeof(struct inode) + sizeof(struct fuse_inode) ,
734 0, SLAB_HWCACHE_ALIGN,
735 fuse_inode_init_once, NULL);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000736 if (!fuse_inode_cachep) {
737 unregister_filesystem(&fuse_fs_type);
738 err = -ENOMEM;
739 }
740 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000741
Miklos Szeredi069c9502004-07-16 16:17:02 +0000742 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000743}
744
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000745void fuse_fs_cleanup(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000746{
747 unregister_filesystem(&fuse_fs_type);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000748 kmem_cache_destroy(fuse_inode_cachep);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000749}