blob: ef99a58c88f696562f0da9a7a94ea5ca68803a27 [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 Szeredic6ee9fd2005-01-10 09:53:04 +000016#include <linux/init.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000017#include <linux/module.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000018#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +000019#include <linux/moduleparam.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000020#include <linux/parser.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000021#include <linux/statfs.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000022#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +000023#include <linux/proc_fs.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000024#include "compat/parser.h"
Miklos Szeredif85ab242004-01-07 12:16:45 +000025#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000026
Miklos Szeredic6ee9fd2005-01-10 09:53:04 +000027MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
28MODULE_DESCRIPTION("Filesystem in Userspace");
29#ifdef MODULE_LICENSE
30MODULE_LICENSE("GPL");
31#endif
32
33spinlock_t fuse_lock;
Miklos Szeredi069c9502004-07-16 16:17:02 +000034static kmem_cache_t *fuse_inode_cachep;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000035static int mount_count;
Miklos Szerediacb4d362004-07-02 16:20:45 +000036
Miklos Szeredi13ed4822004-11-20 11:12:21 +000037static int user_allow_other;
Miklos Szerediacb4d362004-07-02 16:20:45 +000038#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +000039module_param(user_allow_other, int, 0644);
Miklos Szerediacb4d362004-07-02 16:20:45 +000040#else
41MODULE_PARM(user_allow_other, "i");
42#endif
Miklos Szeredi180ff692004-11-01 16:01:05 +000043MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
Miklos Szeredi2a927272005-01-07 11:14:15 +000044
45static int mount_max = 1000;
46#ifdef KERNEL_2_6
47module_param(mount_max, int, 0644);
48#else
49MODULE_PARM(mount_max, "i");
50#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +000051MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)");
Miklos Szerediacb4d362004-07-02 16:20:45 +000052
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000053#define FUSE_SUPER_MAGIC 0x65735546
54
Miklos Szeredif85ab242004-01-07 12:16:45 +000055#ifndef KERNEL_2_6
56#define kstatfs statfs
57#endif
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000058#ifndef FS_SAFE
59#define FS_SAFE 0
60#endif
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000061#ifndef MAX_LFS_FILESIZE
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000062#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000063#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000064struct fuse_mount_data {
65 int fd;
Miklos Szeredi83a07442004-11-30 18:25:20 +000066 unsigned rootmode;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +000067 unsigned user_id;
Miklos Szeredi83a07442004-11-30 18:25:20 +000068 unsigned flags;
69 unsigned max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000070};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000071
Miklos Szeredia13d9002004-11-02 17:32:03 +000072static struct inode *fuse_alloc_inode(struct super_block *sb)
Miklos Szeredi069c9502004-07-16 16:17:02 +000073{
Miklos Szeredia13d9002004-11-02 17:32:03 +000074 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000075 struct fuse_inode *fi;
76
Miklos Szeredia13d9002004-11-02 17:32:03 +000077 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
78 if (!inode)
79 return NULL;
Miklos Szeredi069c9502004-07-16 16:17:02 +000080
Miklos Szeredia13d9002004-11-02 17:32:03 +000081#ifndef KERNEL_2_6
82 inode->u.generic_ip = NULL;
83#endif
Miklos Szeredi039322d2004-12-01 18:39:12 +000084 fi = get_fuse_inode(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +000085 memset(fi, 0, sizeof(*fi));
86 fi->forget_req = fuse_request_alloc();
87 if (!fi->forget_req) {
88 kmem_cache_free(fuse_inode_cachep, inode);
89 return NULL;
90 }
Miklos Szeredia13d9002004-11-02 17:32:03 +000091
92 return inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000093}
94
Miklos Szeredia13d9002004-11-02 17:32:03 +000095static void fuse_destroy_inode(struct inode *inode)
Miklos Szeredi069c9502004-07-16 16:17:02 +000096{
Miklos Szeredi039322d2004-12-01 18:39:12 +000097 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000098 if (fi->forget_req)
99 fuse_request_free(fi->forget_req);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000100 kmem_cache_free(fuse_inode_cachep, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000101}
102
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000103static void fuse_read_inode(struct inode *inode)
104{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +0000105 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000106}
107
Miklos Szeredia13d9002004-11-02 17:32:03 +0000108void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
109 unsigned long nodeid, int version)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000110{
111 struct fuse_forget_in *inarg = &req->misc.forget_in;
112 inarg->version = version;
113 req->in.h.opcode = FUSE_FORGET;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000114 req->in.h.nodeid = nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000115 req->in.numargs = 1;
116 req->in.args[0].size = sizeof(struct fuse_forget_in);
117 req->in.args[0].value = inarg;
118 request_send_noreply(fc, req);
119}
120
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000121static void fuse_clear_inode(struct inode *inode)
122{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000123 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000124 if (fc) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000125 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000126 fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
127 fi->forget_req = NULL;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000128 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000129}
130
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000131void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
132{
133 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
134#ifdef KERNEL_2_6
135 invalidate_inode_pages(inode->i_mapping);
136#else
137 invalidate_inode_pages(inode);
138#endif
139
140 inode->i_ino = attr->ino;
141 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
142 inode->i_nlink = attr->nlink;
143 inode->i_uid = attr->uid;
144 inode->i_gid = attr->gid;
145 i_size_write(inode, attr->size);
146 inode->i_blksize = PAGE_CACHE_SIZE;
147 inode->i_blocks = attr->blocks;
148#ifdef KERNEL_2_6
149 inode->i_atime.tv_sec = attr->atime;
150 inode->i_atime.tv_nsec = attr->atimensec;
151 inode->i_mtime.tv_sec = attr->mtime;
152 inode->i_mtime.tv_nsec = attr->mtimensec;
153 inode->i_ctime.tv_sec = attr->ctime;
154 inode->i_ctime.tv_nsec = attr->ctimensec;
155#else
156 inode->i_atime = attr->atime;
157 inode->i_mtime = attr->mtime;
158 inode->i_ctime = attr->ctime;
159#endif
160}
161
162static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
163{
164 inode->i_mode = attr->mode & S_IFMT;
165 i_size_write(inode, attr->size);
166 if (S_ISREG(inode->i_mode)) {
167 fuse_init_common(inode);
168 fuse_init_file_inode(inode);
169 } else if (S_ISDIR(inode->i_mode))
170 fuse_init_dir(inode);
171 else if (S_ISLNK(inode->i_mode))
172 fuse_init_symlink(inode);
173 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
174 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
175 fuse_init_common(inode);
176 init_special_inode(inode, inode->i_mode,
177 new_decode_dev(attr->rdev));
178 } else {
179 /* Don't let user create weird files */
180 inode->i_mode = S_IFREG;
181 fuse_init_common(inode);
182 fuse_init_file_inode(inode);
183 }
184}
185
186#ifdef KERNEL_2_6
187static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
188{
189 unsigned long nodeid = *(unsigned long *) _nodeidp;
190 if (get_node_id(inode) == nodeid)
191 return 1;
192 else
193 return 0;
194}
195
196static int fuse_inode_set(struct inode *inode, void *_nodeidp)
197{
198 unsigned long nodeid = *(unsigned long *) _nodeidp;
199 get_fuse_inode(inode)->nodeid = nodeid;
200 return 0;
201}
202
203struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
204 int generation, struct fuse_attr *attr, int version)
205{
206 struct inode *inode;
207 struct fuse_conn *fc = get_fuse_conn_super(sb);
208 int retried = 0;
209
210 retry:
211 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
212 if (!inode)
213 return NULL;
214
215 if ((inode->i_state & I_NEW)) {
216 inode->i_generation = generation;
217 inode->i_data.backing_dev_info = &fc->bdi;
218 fuse_init_inode(inode, attr);
219 unlock_new_inode(inode);
220 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
221 BUG_ON(retried);
222 /* Inode has changed type, any I/O on the old should fail */
223 make_bad_inode(inode);
224 iput(inode);
225 retried = 1;
226 goto retry;
227 }
228
229 fuse_change_attributes(inode, attr);
230 inode->i_version = version;
231 return inode;
232}
233#else
234static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
235 unsigned long nodeid = *(unsigned long *) _nodeidp;
236 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
237 return 1;
238 else
239 return 0;
240}
241
242struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
243 int generation, struct fuse_attr *attr, int version)
244{
245 struct inode *inode;
246 int retried = 0;
247
248 retry:
249 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
250 if (!inode)
251 return NULL;
252
253 if (!inode->u.generic_ip) {
254 get_fuse_inode(inode)->nodeid = nodeid;
255 inode->u.generic_ip = inode;
256 inode->i_generation = generation;
257 fuse_init_inode(inode, attr);
258 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
259 BUG_ON(retried);
260 /* Inode has changed type, any I/O on the old should fail */
261 remove_inode_hash(inode);
262 make_bad_inode(inode);
263 iput(inode);
264 retried = 1;
265 goto retry;
266 }
267
268 fuse_change_attributes(inode, attr);
269 inode->i_version = version;
270 return inode;
271}
272#endif
273
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000274static void fuse_put_super(struct super_block *sb)
275{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000276 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000277
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000278 spin_lock(&fuse_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000279 mount_count --;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000280 fc->sb = NULL;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000281 fc->user_id = 0;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000282 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +0000283 /* Flush all readers on this fs */
284 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +0000285 fuse_release_conn(fc);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000286 *get_fuse_conn_super_p(sb) = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000287 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000288}
289
Miklos Szeredif85ab242004-01-07 12:16:45 +0000290static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000291{
292 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000293 stbuf->f_bsize = attr->bsize;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000294 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000295 stbuf->f_bfree = attr->bfree;
296 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000297 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000298 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000299 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000300 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000301}
302
Miklos Szeredif85ab242004-01-07 12:16:45 +0000303static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000304{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000305 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000307 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000308 int err;
309
310 req = fuse_get_request(fc);
311 if (!req)
312 return -ERESTARTSYS;
313
314 req->in.numargs = 0;
315 req->in.h.opcode = FUSE_STATFS;
316 req->out.numargs = 1;
317 req->out.args[0].size = sizeof(outarg);
318 req->out.args[0].value = &outarg;
319 request_send(fc, req);
320 err = req->out.h.error;
321 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000322 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000323 fuse_put_request(fc, req);
324 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000325}
326
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000327enum {
328 OPT_FD,
329 OPT_ROOTMODE,
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000330 OPT_USER_ID,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000331 OPT_DEFAULT_PERMISSIONS,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000332 OPT_ALLOW_OTHER,
333 OPT_ALLOW_ROOT,
334 OPT_KERNEL_CACHE,
Miklos Szeredie56818b2004-12-12 11:45:24 +0000335#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000336 OPT_LARGE_READ,
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000337#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000338 OPT_DIRECT_IO,
339 OPT_MAX_READ,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000340 OPT_ERR
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000341};
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000342
343static match_table_t tokens = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000344 {OPT_FD, "fd=%u"},
345 {OPT_ROOTMODE, "rootmode=%o"},
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000346 {OPT_USER_ID, "user_id=%u"},
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000347 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
348 {OPT_ALLOW_OTHER, "allow_other"},
349 {OPT_ALLOW_ROOT, "allow_root"},
350 {OPT_KERNEL_CACHE, "kernel_cache"},
Miklos Szeredie56818b2004-12-12 11:45:24 +0000351#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000352 {OPT_LARGE_READ, "large_read"},
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000353#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000354 {OPT_DIRECT_IO, "direct_io"},
355 {OPT_MAX_READ, "max_read=%u"},
356 {OPT_ERR, NULL}
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000357};
358
359static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
360{
361 char *p;
362 memset(d, 0, sizeof(struct fuse_mount_data));
363 d->fd = -1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000364 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000365
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000366 while ((p = strsep(&opt, ",")) != NULL) {
367 int token;
368 int value;
369 substring_t args[MAX_OPT_ARGS];
370 if (!*p)
371 continue;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000372
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000373 token = match_token(p, tokens, args);
374 switch (token) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000375 case OPT_FD:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000376 if (match_int(&args[0], &value))
377 return 0;
378 d->fd = value;
379 break;
380
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000381 case OPT_ROOTMODE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000382 if (match_octal(&args[0], &value))
383 return 0;
384 d->rootmode = value;
385 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000386
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000387 case OPT_USER_ID:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000388 if (match_int(&args[0], &value))
389 return 0;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000390 d->user_id = value;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000391 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000392
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000393 case OPT_DEFAULT_PERMISSIONS:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000394 d->flags |= FUSE_DEFAULT_PERMISSIONS;
395 break;
396
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000397 case OPT_ALLOW_OTHER:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000398 d->flags |= FUSE_ALLOW_OTHER;
399 break;
400
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000401 case OPT_ALLOW_ROOT:
Miklos Szeredi180ff692004-11-01 16:01:05 +0000402 d->flags |= FUSE_ALLOW_ROOT;
403 break;
404
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000405 case OPT_KERNEL_CACHE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000406 d->flags |= FUSE_KERNEL_CACHE;
407 break;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000408
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000409#ifndef KERNEL_2_6
Miklos Szeredie56818b2004-12-12 11:45:24 +0000410 case OPT_LARGE_READ:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000411 d->flags |= FUSE_LARGE_READ;
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000412 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000413#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000414 case OPT_DIRECT_IO:
Miklos Szerediad051c32004-07-02 09:22:50 +0000415 d->flags |= FUSE_DIRECT_IO;
416 break;
417
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000418 case OPT_MAX_READ:
Miklos Szerediad051c32004-07-02 09:22:50 +0000419 if (match_int(&args[0], &value))
420 return 0;
421 d->max_read = value;
422 break;
423
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000424 default:
425 return 0;
426 }
427 }
428 if (d->fd == -1)
429 return 0;
430
431 return 1;
432}
433
434static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
435{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000436 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000437
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000438 seq_printf(m, ",user_id=%u", fc->user_id);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000439 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
440 seq_puts(m, ",default_permissions");
441 if (fc->flags & FUSE_ALLOW_OTHER)
442 seq_puts(m, ",allow_other");
Miklos Szeredi180ff692004-11-01 16:01:05 +0000443 if (fc->flags & FUSE_ALLOW_ROOT)
444 seq_puts(m, ",allow_root");
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000445 if (fc->flags & FUSE_KERNEL_CACHE)
446 seq_puts(m, ",kernel_cache");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000447#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000448 if (fc->flags & FUSE_LARGE_READ)
449 seq_puts(m, ",large_read");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000450#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000451 if (fc->flags & FUSE_DIRECT_IO)
452 seq_puts(m, ",direct_io");
453 if (fc->max_read != ~0)
454 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000455 return 0;
456}
457
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000458static void free_conn(struct fuse_conn *fc)
459{
460 while (!list_empty(&fc->unused_list)) {
461 struct fuse_req *req;
462 req = list_entry(fc->unused_list.next, struct fuse_req, list);
463 list_del(&req->list);
464 fuse_request_free(req);
465 }
466 kfree(fc);
467}
468
469/* Must be called with the fuse lock held */
470void fuse_release_conn(struct fuse_conn *fc)
471{
472 if (!fc->sb && !fc->file)
473 free_conn(fc);
474}
475
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000476static struct fuse_conn *new_conn(void)
477{
478 struct fuse_conn *fc;
479
480 fc = kmalloc(sizeof(*fc), GFP_KERNEL);
481 if (fc != NULL) {
482 int i;
483 memset(fc, 0, sizeof(*fc));
484 fc->sb = NULL;
485 fc->file = NULL;
486 fc->flags = 0;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000487 fc->user_id = 0;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000488 init_waitqueue_head(&fc->waitq);
489 INIT_LIST_HEAD(&fc->pending);
490 INIT_LIST_HEAD(&fc->processing);
491 INIT_LIST_HEAD(&fc->unused_list);
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000492 sema_init(&fc->outstanding_sem, 0);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000493 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
494 struct fuse_req *req = fuse_request_alloc();
495 if (!req) {
496 free_conn(fc);
497 return NULL;
498 }
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000499 list_add(&req->list, &fc->unused_list);
500 }
Miklos Szeredib6220192005-01-05 16:19:10 +0000501#ifdef KERNEL_2_6_6_PLUS
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000502 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
503 fc->bdi.unplug_io_fn = default_unplug_io_fn;
504#endif
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000505 fc->reqctr = 1;
506 }
507 return fc;
508}
509
Miklos Szeredied62d862004-06-20 08:57:39 +0000510static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000511{
Miklos Szeredied62d862004-06-20 08:57:39 +0000512 struct fuse_conn *fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000513
Miklos Szeredie56818b2004-12-12 11:45:24 +0000514 if (file->f_op != &fuse_dev_operations)
Miklos Szeredied62d862004-06-20 08:57:39 +0000515 return NULL;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000516 fc = new_conn();
Miklos Szeredie56818b2004-12-12 11:45:24 +0000517 if (fc == NULL)
Miklos Szeredied62d862004-06-20 08:57:39 +0000518 return NULL;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000519 spin_lock(&fuse_lock);
520 if (file->private_data) {
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000521 free_conn(fc);
522 fc = NULL;
523 } else {
524 file->private_data = fc;
525 fc->sb = sb;
526 fc->file = file;
527 }
528 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000529 return fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000530}
531
Miklos Szeredi83a07442004-11-30 18:25:20 +0000532static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000533{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000534 struct fuse_attr attr;
535 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000536
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000537 attr.mode = mode;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000538 attr.ino = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000539 return fuse_iget(sb, 1, 0, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000540}
541
Miklos Szeredie815c032004-01-19 18:20:49 +0000542#ifdef KERNEL_2_6
Miklos Szeredie815c032004-01-19 18:20:49 +0000543static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
544{
545 __u32 *objp = vobjp;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000546 unsigned long nodeid = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000547 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000548 struct inode *inode;
549 struct dentry *entry;
550
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000551 if (nodeid == 0)
Miklos Szeredie815c032004-01-19 18:20:49 +0000552 return ERR_PTR(-ESTALE);
553
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000554 inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000555 if (!inode || inode->i_generation != generation)
Miklos Szeredie815c032004-01-19 18:20:49 +0000556 return ERR_PTR(-ESTALE);
557
558 entry = d_alloc_anon(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000559 if (!entry) {
Miklos Szeredie815c032004-01-19 18:20:49 +0000560 iput(inode);
561 return ERR_PTR(-ENOMEM);
562 }
563
564 return entry;
565}
566
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000567static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
568 int connectable)
569{
570 struct inode *inode = dentry->d_inode;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000571 int len = *max_len;
572 int type = 1;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000573
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000574 if (len < 2 || (connectable && len < 4))
575 return 255;
576
577 len = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000578 fh[0] = get_fuse_inode(inode)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000579 fh[1] = inode->i_generation;
580 if (connectable && !S_ISDIR(inode->i_mode)) {
581 struct inode *parent;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000582
583 spin_lock(&dentry->d_lock);
584 parent = dentry->d_parent->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000585 fh[2] = get_fuse_inode(parent)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000586 fh[3] = parent->i_generation;
587 spin_unlock(&dentry->d_lock);
588 len = 4;
589 type = 2;
590 }
591 *max_len = len;
592 return type;
593}
594
Miklos Szeredie815c032004-01-19 18:20:49 +0000595static struct export_operations fuse_export_operations = {
596 .get_dentry = fuse_get_dentry,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000597 .encode_fh = fuse_encode_fh,
Miklos Szeredie815c032004-01-19 18:20:49 +0000598};
599#endif
600
601static struct super_operations fuse_super_operations = {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000602 .alloc_inode = fuse_alloc_inode,
603 .destroy_inode = fuse_destroy_inode,
Miklos Szeredie815c032004-01-19 18:20:49 +0000604 .read_inode = fuse_read_inode,
605 .clear_inode = fuse_clear_inode,
606 .put_super = fuse_put_super,
607 .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 Szeredi0f62d722005-01-04 12:45:54 +0000611static int inc_mount_count(void)
612{
613 int success = 0;
614 spin_lock(&fuse_lock);
615 mount_count ++;
616 if (mount_max == -1 || mount_count <= mount_max)
617 success = 1;
618 spin_unlock(&fuse_lock);
619 return success;
620}
621
Miklos Szeredif85ab242004-01-07 12:16:45 +0000622static int fuse_read_super(struct super_block *sb, void *data, int silent)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000623{
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000624 struct fuse_conn *fc;
625 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000626 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000627 struct file *file;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000628 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000629
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000630 if (!parse_fuse_opt((char *) data, &d))
631 return -EINVAL;
632
Miklos Szeredi180ff692004-11-01 16:01:05 +0000633 if (!user_allow_other &&
634 (d.flags & (FUSE_ALLOW_OTHER | FUSE_ALLOW_ROOT)) &&
Miklos Szerediacb4d362004-07-02 16:20:45 +0000635 current->uid != 0)
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000636 return -EPERM;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000637
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000638 sb->s_blocksize = PAGE_CACHE_SIZE;
639 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
640 sb->s_magic = FUSE_SUPER_MAGIC;
641 sb->s_op = &fuse_super_operations;
642 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredie815c032004-01-19 18:20:49 +0000643#ifdef KERNEL_2_6
644 sb->s_export_op = &fuse_export_operations;
645#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000646
Miklos Szeredied62d862004-06-20 08:57:39 +0000647 file = fget(d.fd);
648 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000649 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000650
Miklos Szeredied62d862004-06-20 08:57:39 +0000651 fc = get_conn(file, sb);
Miklos Szeredied62d862004-06-20 08:57:39 +0000652 fput(file);
653 if (fc == NULL)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000654 return -EINVAL;
Miklos Szeredied62d862004-06-20 08:57:39 +0000655
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000656 fc->flags = d.flags;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000657 fc->user_id = d.user_id;
Miklos Szerediad051c32004-07-02 09:22:50 +0000658 fc->max_read = d.max_read;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000659#ifdef KERNEL_2_6
660 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
661 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
662#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000663 fc->max_write = FUSE_MAX_IN / 2;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000664
Miklos Szeredi039322d2004-12-01 18:39:12 +0000665 *get_fuse_conn_super_p(sb) = fc;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000666
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000667 err = -ENFILE;
668 if (!inc_mount_count() && current->uid != 0)
669 goto err;
670
671 err = -ENOMEM;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000672 root = get_root_inode(sb, d.rootmode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000673 if (root == NULL)
Miklos Szeredied62d862004-06-20 08:57:39 +0000674 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000675
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000676 sb->s_root = d_alloc_root(root);
Miklos Szeredied62d862004-06-20 08:57:39 +0000677 if (!sb->s_root) {
678 iput(root);
679 goto err;
680 }
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000681 fuse_send_init(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000682 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000683
684 err:
685 spin_lock(&fuse_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000686 mount_count --;
Miklos Szeredied62d862004-06-20 08:57:39 +0000687 fc->sb = NULL;
688 fuse_release_conn(fc);
689 spin_unlock(&fuse_lock);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000690 *get_fuse_conn_super_p(sb) = NULL;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000691 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000692}
693
Miklos Szeredif85ab242004-01-07 12:16:45 +0000694#ifdef KERNEL_2_6
695static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000696 int flags, const char *dev_name,
697 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000698{
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000699 return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000700}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000701
Miklos Szeredif85ab242004-01-07 12:16:45 +0000702static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000703 .owner = THIS_MODULE,
704 .name = "fuse",
705 .get_sb = fuse_get_sb,
706 .kill_sb = kill_anon_super,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000707#ifndef FUSE_MAINLINE
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000708 .fs_flags = FS_SAFE,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000709#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +0000710};
711#else
712static struct super_block *fuse_read_super_compat(struct super_block *sb,
713 void *data, int silent)
714{
715 int err = fuse_read_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000716 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000717 return NULL;
718 else
719 return sb;
720}
721
722static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
723#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000724
Miklos Szeredia13d9002004-11-02 17:32:03 +0000725static void fuse_inode_init_once(void * foo, kmem_cache_t * cachep,
726 unsigned long flags)
727{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000728 struct inode * inode = foo;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000729
730 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
731 SLAB_CTOR_CONSTRUCTOR)
732 inode_init_once(inode);
733}
734
Miklos Szeredi9080c792005-01-08 11:50:08 +0000735static int __init fuse_fs_init(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000736{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000737 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000738
Miklos Szeredi069c9502004-07-16 16:17:02 +0000739 err = register_filesystem(&fuse_fs_type);
740 if (err)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000741 printk("fuse: failed to register filesystem\n");
Miklos Szeredi069c9502004-07-16 16:17:02 +0000742 else {
743 fuse_inode_cachep = kmem_cache_create("fuse_inode",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000744 sizeof(struct inode) + sizeof(struct fuse_inode) ,
745 0, SLAB_HWCACHE_ALIGN,
746 fuse_inode_init_once, NULL);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000747 if (!fuse_inode_cachep) {
748 unregister_filesystem(&fuse_fs_type);
749 err = -ENOMEM;
750 }
751 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000752
Miklos Szeredi069c9502004-07-16 16:17:02 +0000753 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000754}
755
Miklos Szeredi9080c792005-01-08 11:50:08 +0000756static void fuse_fs_cleanup(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000757{
758 unregister_filesystem(&fuse_fs_type);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000759 kmem_cache_destroy(fuse_inode_cachep);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000760}
Miklos Szeredi9080c792005-01-08 11:50:08 +0000761
762int __init fuse_init(void)
763{
764 int res;
765
766 printk("fuse init (API version %i.%i)\n",
767 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
768#ifndef FUSE_MAINLINE
769 printk("fuse distribution version: %s\n", FUSE_VERSION);
770#endif
771
772 spin_lock_init(&fuse_lock);
773 res = fuse_fs_init();
774 if (res)
775 goto err;
776
777 res = fuse_dev_init();
778 if (res)
779 goto err_fs_cleanup;
780
781 return 0;
782
783 err_fs_cleanup:
784 fuse_fs_cleanup();
785 err:
786 return res;
787}
788
789void __exit fuse_exit(void)
790{
791 printk(KERN_DEBUG "fuse exit\n");
792
793 fuse_fs_cleanup();
794 fuse_dev_cleanup();
795}
796
797module_init(fuse_init);
798module_exit(fuse_exit);