blob: 591a4df6593c0aa035d6db6c42ce05097211d89f [file] [log] [blame]
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi2e6b6f22004-07-07 19:19:53 +00003 Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00004
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
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 Szeredibc22e7b2001-10-23 19:26:04 +000012#include <linux/sched.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000013#include <linux/slab.h>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000014#include <linux/file.h>
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000015#include <linux/mount.h>
Miklos Szeredi60c23522002-10-24 09:19:43 +000016#include <linux/proc_fs.h>
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000017#include <linux/seq_file.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000018#ifdef KERNEL_2_6
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
22#include "compat/parser.h"
Miklos Szeredif85ab242004-01-07 12:16:45 +000023#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000024
Miklos Szerediacb4d362004-07-02 16:20:45 +000025
26static int user_allow_other;
Miklos Szeredi069c9502004-07-16 16:17:02 +000027static kmem_cache_t *fuse_inode_cachep;
Miklos Szerediacb4d362004-07-02 16:20:45 +000028
29#ifdef KERNEL_2_6
30#include <linux/moduleparam.h>
31module_param(user_allow_other, int, 0);
32#else
33MODULE_PARM(user_allow_other, "i");
34#endif
35
Miklos Szeredi180ff692004-11-01 16:01:05 +000036MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
Miklos Szerediacb4d362004-07-02 16:20:45 +000037
38
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000039#define FUSE_SUPER_MAGIC 0x65735546
40
Miklos Szeredif85ab242004-01-07 12:16:45 +000041#ifndef KERNEL_2_6
42#define kstatfs statfs
43#endif
44
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000045#ifndef FS_SAFE
46#define FS_SAFE 0
47#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000048
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000049#ifndef MAX_LFS_FILESIZE
50#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
51#endif
52
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000053struct fuse_mount_data {
54 int fd;
55 unsigned int rootmode;
56 unsigned int uid;
57 unsigned int flags;
Miklos Szerediad051c32004-07-02 09:22:50 +000058 unsigned int max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000059};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000060
Miklos Szeredia13d9002004-11-02 17:32:03 +000061static struct inode *fuse_alloc_inode(struct super_block *sb)
Miklos Szeredi069c9502004-07-16 16:17:02 +000062{
Miklos Szeredia13d9002004-11-02 17:32:03 +000063 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000064 struct fuse_inode *fi;
65
Miklos Szeredia13d9002004-11-02 17:32:03 +000066 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
67 if (!inode)
68 return NULL;
Miklos Szeredi069c9502004-07-16 16:17:02 +000069
Miklos Szeredia13d9002004-11-02 17:32:03 +000070#ifndef KERNEL_2_6
71 inode->u.generic_ip = NULL;
72#endif
73
74 fi = INO_FI(inode);
75 memset(fi, 0, sizeof(*fi));
76 fi->forget_req = fuse_request_alloc();
77 if (!fi->forget_req) {
78 kmem_cache_free(fuse_inode_cachep, inode);
79 return NULL;
80 }
81 init_rwsem(&fi->write_sem);
82 INIT_LIST_HEAD(&fi->write_files);
83
84 return inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000085}
86
Miklos Szeredia13d9002004-11-02 17:32:03 +000087static void fuse_destroy_inode(struct inode *inode)
Miklos Szeredi069c9502004-07-16 16:17:02 +000088{
Miklos Szeredia13d9002004-11-02 17:32:03 +000089 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000090 BUG_ON(!list_empty(&fi->write_files));
91 if (fi->forget_req)
92 fuse_request_free(fi->forget_req);
Miklos Szeredia13d9002004-11-02 17:32:03 +000093 kmem_cache_free(fuse_inode_cachep, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +000094}
95
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000096static void fuse_read_inode(struct inode *inode)
97{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000098 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000099}
100
Miklos Szeredia13d9002004-11-02 17:32:03 +0000101void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
102 unsigned long nodeid, int version)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000103{
104 struct fuse_forget_in *inarg = &req->misc.forget_in;
105 inarg->version = version;
106 req->in.h.opcode = FUSE_FORGET;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000107 req->in.h.nodeid = nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000108 req->in.numargs = 1;
109 req->in.args[0].size = sizeof(struct fuse_forget_in);
110 req->in.args[0].value = inarg;
111 request_send_noreply(fc, req);
112}
113
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000114static void fuse_clear_inode(struct inode *inode)
115{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000116 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia181e612001-11-06 12:03:23 +0000117
Miklos Szeredia13d9002004-11-02 17:32:03 +0000118 if (fc) {
119 struct fuse_inode *fi = INO_FI(inode);
120 fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
121 fi->forget_req = NULL;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000122 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000123}
124
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000125static void fuse_put_super(struct super_block *sb)
126{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000127 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000128
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000129 down(&fc->sb_sem);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000130 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000131 fc->sb = NULL;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000132 up(&fc->sb_sem);
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000133 fc->uid = 0;
134 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +0000135 /* Flush all readers on this fs */
136 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +0000137 fuse_release_conn(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000138 SB_FC(sb) = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000139 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000140}
141
Miklos Szeredif85ab242004-01-07 12:16:45 +0000142static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000143{
144 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000145 stbuf->f_bsize = attr->bsize;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000146 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000147 stbuf->f_bfree = attr->bfree;
148 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000149 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000150 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000151 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000152 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000153}
154
Miklos Szeredif85ab242004-01-07 12:16:45 +0000155static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000156{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000157 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000158 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000159 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000160 int err;
161
162 req = fuse_get_request(fc);
163 if (!req)
164 return -ERESTARTSYS;
165
166 req->in.numargs = 0;
167 req->in.h.opcode = FUSE_STATFS;
168 req->out.numargs = 1;
169 req->out.args[0].size = sizeof(outarg);
170 req->out.args[0].value = &outarg;
171 request_send(fc, req);
172 err = req->out.h.error;
173 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000174 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000175 fuse_put_request(fc, req);
176 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000177}
178
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000179enum { opt_fd,
180 opt_rootmode,
181 opt_uid,
182 opt_default_permissions,
183 opt_allow_other,
Miklos Szeredi180ff692004-11-01 16:01:05 +0000184 opt_allow_root,
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000185 opt_kernel_cache,
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000186 opt_large_read,
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000187 opt_direct_io,
188 opt_max_read,
189 opt_err };
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000190
191static match_table_t tokens = {
192 {opt_fd, "fd=%u"},
193 {opt_rootmode, "rootmode=%o"},
194 {opt_uid, "uid=%u"},
195 {opt_default_permissions, "default_permissions"},
196 {opt_allow_other, "allow_other"},
Miklos Szeredi180ff692004-11-01 16:01:05 +0000197 {opt_allow_root, "allow_root"},
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000198 {opt_kernel_cache, "kernel_cache"},
199 {opt_large_read, "large_read"},
Miklos Szerediad051c32004-07-02 09:22:50 +0000200 {opt_direct_io, "direct_io"},
Miklos Szeredibd7661b2004-07-23 17:16:29 +0000201 {opt_max_read, "max_read=%u" },
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000202 {opt_err, NULL}
203};
204
205static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
206{
207 char *p;
208 memset(d, 0, sizeof(struct fuse_mount_data));
209 d->fd = -1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000210 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000211
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000212 while ((p = strsep(&opt, ",")) != NULL) {
213 int token;
214 int value;
215 substring_t args[MAX_OPT_ARGS];
216 if (!*p)
217 continue;
218
219 token = match_token(p, tokens, args);
220 switch (token) {
221 case opt_fd:
222 if (match_int(&args[0], &value))
223 return 0;
224 d->fd = value;
225 break;
226
227 case opt_rootmode:
228 if (match_octal(&args[0], &value))
229 return 0;
230 d->rootmode = value;
231 break;
232
233 case opt_uid:
234 if (match_int(&args[0], &value))
235 return 0;
236 d->uid = value;
237 break;
238
239 case opt_default_permissions:
240 d->flags |= FUSE_DEFAULT_PERMISSIONS;
241 break;
242
243 case opt_allow_other:
244 d->flags |= FUSE_ALLOW_OTHER;
245 break;
246
Miklos Szeredi180ff692004-11-01 16:01:05 +0000247 case opt_allow_root:
248 d->flags |= FUSE_ALLOW_ROOT;
249 break;
250
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000251 case opt_kernel_cache:
252 d->flags |= FUSE_KERNEL_CACHE;
253 break;
254
255 case opt_large_read:
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000256#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000257 d->flags |= FUSE_LARGE_READ;
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000258#else
259 {
260 static int warned = 0;
261 if (!warned) {
262 printk("fuse: large_read option is deprecated for 2.6 kernels\n");
263 warned = 1;
264 }
265 }
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000266#endif
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000267 break;
Miklos Szerediad051c32004-07-02 09:22:50 +0000268
269 case opt_direct_io:
270 d->flags |= FUSE_DIRECT_IO;
271 break;
272
273 case opt_max_read:
274 if (match_int(&args[0], &value))
275 return 0;
276 d->max_read = value;
277 break;
278
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000279 default:
280 return 0;
281 }
282 }
283 if (d->fd == -1)
284 return 0;
285
286 return 1;
287}
288
289static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
290{
291 struct fuse_conn *fc = SB_FC(mnt->mnt_sb);
292
293 seq_printf(m, ",uid=%u", fc->uid);
294 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
295 seq_puts(m, ",default_permissions");
296 if (fc->flags & FUSE_ALLOW_OTHER)
297 seq_puts(m, ",allow_other");
Miklos Szeredi180ff692004-11-01 16:01:05 +0000298 if (fc->flags & FUSE_ALLOW_ROOT)
299 seq_puts(m, ",allow_root");
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000300 if (fc->flags & FUSE_KERNEL_CACHE)
301 seq_puts(m, ",kernel_cache");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000302#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000303 if (fc->flags & FUSE_LARGE_READ)
304 seq_puts(m, ",large_read");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000305#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000306 if (fc->flags & FUSE_DIRECT_IO)
307 seq_puts(m, ",direct_io");
308 if (fc->max_read != ~0)
309 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000310 return 0;
311}
312
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000313static void free_conn(struct fuse_conn *fc)
314{
315 while (!list_empty(&fc->unused_list)) {
316 struct fuse_req *req;
317 req = list_entry(fc->unused_list.next, struct fuse_req, list);
318 list_del(&req->list);
319 fuse_request_free(req);
320 }
321 kfree(fc);
322}
323
324/* Must be called with the fuse lock held */
325void fuse_release_conn(struct fuse_conn *fc)
326{
327 if (!fc->sb && !fc->file)
328 free_conn(fc);
329}
330
331
332static struct fuse_conn *new_conn(void)
333{
334 struct fuse_conn *fc;
335
336 fc = kmalloc(sizeof(*fc), GFP_KERNEL);
337 if (fc != NULL) {
338 int i;
339 memset(fc, 0, sizeof(*fc));
340 fc->sb = NULL;
341 fc->file = NULL;
342 fc->flags = 0;
343 fc->uid = 0;
344 init_waitqueue_head(&fc->waitq);
345 INIT_LIST_HEAD(&fc->pending);
346 INIT_LIST_HEAD(&fc->processing);
347 INIT_LIST_HEAD(&fc->unused_list);
348 sema_init(&fc->unused_sem, FUSE_MAX_OUTSTANDING);
349 sema_init(&fc->sb_sem, 1);
350 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
351 struct fuse_req *req = fuse_request_alloc();
352 if (!req) {
353 free_conn(fc);
354 return NULL;
355 }
356 req->preallocated = 1;
357 list_add(&req->list, &fc->unused_list);
358 }
359 fc->reqctr = 1;
360 }
361 return fc;
362}
363
Miklos Szeredied62d862004-06-20 08:57:39 +0000364static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000365{
Miklos Szeredied62d862004-06-20 08:57:39 +0000366 struct fuse_conn *fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000367 struct inode *ino;
368
Miklos Szeredied62d862004-06-20 08:57:39 +0000369 ino = file->f_dentry->d_inode;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000370 if (!ino || !proc_fuse_dev ||
371 strcmp(ino->i_sb->s_type->name, "proc") != 0 ||
372 proc_fuse_dev->low_ino != ino->i_ino) {
Miklos Szeredied62d862004-06-20 08:57:39 +0000373 printk("FUSE: bad communication file descriptor\n");
374 return NULL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000375 }
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000376 fc = new_conn();
377 if (fc == NULL) {
378 printk("FUSE: failed to allocate connection data\n");
Miklos Szeredied62d862004-06-20 08:57:39 +0000379 return NULL;
380 }
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000381 spin_lock(&fuse_lock);
382 if (file->private_data) {
383 printk("fuse_read_super: connection already mounted\n");
384 free_conn(fc);
385 fc = NULL;
386 } else {
387 file->private_data = fc;
388 fc->sb = sb;
389 fc->file = file;
390 }
391 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000392 return fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000393}
394
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000395static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000396{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000397 struct fuse_attr attr;
398 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000399
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000400 attr.mode = mode;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000401 attr.ino = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000402 return fuse_iget(sb, 1, 0, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000403}
404
Miklos Szeredie815c032004-01-19 18:20:49 +0000405
406#ifdef KERNEL_2_6
407
408static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
409{
410 __u32 *objp = vobjp;
411 unsigned long ino = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000412 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000413 struct inode *inode;
414 struct dentry *entry;
415
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000416 if (ino == 0)
Miklos Szeredie815c032004-01-19 18:20:49 +0000417 return ERR_PTR(-ESTALE);
418
419 inode = ilookup(sb, ino);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000420 if (!inode || inode->i_generation != generation)
Miklos Szeredie815c032004-01-19 18:20:49 +0000421 return ERR_PTR(-ESTALE);
422
423 entry = d_alloc_anon(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000424 if (!entry) {
Miklos Szeredie815c032004-01-19 18:20:49 +0000425 iput(inode);
426 return ERR_PTR(-ENOMEM);
427 }
428
429 return entry;
430}
431
432static struct export_operations fuse_export_operations = {
433 .get_dentry = fuse_get_dentry,
434};
435#endif
436
437static struct super_operations fuse_super_operations = {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000438 .alloc_inode = fuse_alloc_inode,
439 .destroy_inode = fuse_destroy_inode,
Miklos Szeredie815c032004-01-19 18:20:49 +0000440 .read_inode = fuse_read_inode,
441 .clear_inode = fuse_clear_inode,
442 .put_super = fuse_put_super,
443 .statfs = fuse_statfs,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000444 .show_options = fuse_show_options,
Miklos Szeredie815c032004-01-19 18:20:49 +0000445};
446
Miklos Szeredif85ab242004-01-07 12:16:45 +0000447static int fuse_read_super(struct super_block *sb, void *data, int silent)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000448{
449 struct fuse_conn *fc;
450 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000451 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000452 struct file *file;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000453
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000454 if (!parse_fuse_opt((char *) data, &d))
455 return -EINVAL;
456
Miklos Szeredi180ff692004-11-01 16:01:05 +0000457 if (!user_allow_other &&
458 (d.flags & (FUSE_ALLOW_OTHER | FUSE_ALLOW_ROOT)) &&
Miklos Szerediacb4d362004-07-02 16:20:45 +0000459 current->uid != 0)
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000460 return -EPERM;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000461
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000462 sb->s_blocksize = PAGE_CACHE_SIZE;
463 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
464 sb->s_magic = FUSE_SUPER_MAGIC;
465 sb->s_op = &fuse_super_operations;
466 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredie815c032004-01-19 18:20:49 +0000467#ifdef KERNEL_2_6
468 sb->s_export_op = &fuse_export_operations;
469#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000470
Miklos Szeredied62d862004-06-20 08:57:39 +0000471 file = fget(d.fd);
472 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000473 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000474
Miklos Szeredied62d862004-06-20 08:57:39 +0000475 fc = get_conn(file, sb);
Miklos Szeredied62d862004-06-20 08:57:39 +0000476 fput(file);
477 if (fc == NULL)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000478 return -EINVAL;
Miklos Szeredied62d862004-06-20 08:57:39 +0000479
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000480 fc->flags = d.flags;
481 fc->uid = d.uid;
Miklos Szerediad051c32004-07-02 09:22:50 +0000482 fc->max_read = d.max_read;
483 fc->max_write = FUSE_MAX_IN / 2;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000484
485 /* fc is needed in fuse_init_file_inode which could be called
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000486 from get_root_inode */
Miklos Szeredi307242f2004-01-26 11:28:44 +0000487 SB_FC(sb) = fc;
488
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000489 root = get_root_inode(sb, d.rootmode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000490 if (root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000491 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredied62d862004-06-20 08:57:39 +0000492 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000493 }
494
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000495 sb->s_root = d_alloc_root(root);
Miklos Szeredied62d862004-06-20 08:57:39 +0000496 if (!sb->s_root) {
497 iput(root);
498 goto err;
499 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000500
Miklos Szeredif85ab242004-01-07 12:16:45 +0000501 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000502
503 err:
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000504 down(&fc->sb_sem);
Miklos Szeredied62d862004-06-20 08:57:39 +0000505 spin_lock(&fuse_lock);
506 fc->sb = NULL;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000507 up(&fc->sb_sem);
Miklos Szeredied62d862004-06-20 08:57:39 +0000508 fuse_release_conn(fc);
509 spin_unlock(&fuse_lock);
510 SB_FC(sb) = NULL;
511 return -EINVAL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000512}
513
Miklos Szeredif85ab242004-01-07 12:16:45 +0000514#ifdef KERNEL_2_6
515static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000516 int flags, const char *dev_name,
517 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000518{
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000519 return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000520}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000521
Miklos Szeredif85ab242004-01-07 12:16:45 +0000522static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000523 .owner = THIS_MODULE,
524 .name = "fuse",
525 .get_sb = fuse_get_sb,
526 .kill_sb = kill_anon_super,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000527 .fs_flags = FS_SAFE,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000528};
529#else
530static struct super_block *fuse_read_super_compat(struct super_block *sb,
531 void *data, int silent)
532{
533 int err = fuse_read_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000534 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000535 return NULL;
536 else
537 return sb;
538}
539
540static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
541#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000542
Miklos Szeredia13d9002004-11-02 17:32:03 +0000543static void fuse_inode_init_once(void * foo, kmem_cache_t * cachep,
544 unsigned long flags)
545{
546 struct inode * inode = (struct inode *) foo;
547
548 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
549 SLAB_CTOR_CONSTRUCTOR)
550 inode_init_once(inode);
551}
552
553
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000554int fuse_fs_init()
555{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000556 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000557
Miklos Szeredi069c9502004-07-16 16:17:02 +0000558 err = register_filesystem(&fuse_fs_type);
559 if (err)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000560 printk("fuse: failed to register filesystem\n");
Miklos Szeredi069c9502004-07-16 16:17:02 +0000561 else {
562 fuse_inode_cachep = kmem_cache_create("fuse_inode",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000563 sizeof(struct inode) + sizeof(struct fuse_inode) ,
564 0, SLAB_HWCACHE_ALIGN,
565 fuse_inode_init_once, NULL);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000566 if (!fuse_inode_cachep) {
567 unregister_filesystem(&fuse_fs_type);
568 err = -ENOMEM;
569 }
570 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000571
Miklos Szeredi069c9502004-07-16 16:17:02 +0000572 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000573}
574
575void fuse_fs_cleanup()
576{
577 unregister_filesystem(&fuse_fs_type);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000578 kmem_cache_destroy(fuse_inode_cachep);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000579}
580
581/*
582 * Local Variables:
583 * indent-tabs-mode: t
584 * c-basic-offset: 8
Miklos Szeredi63a63bc2001-12-02 20:37:53 +0000585 * End:
586 */