blob: d94b3b2336f79cc0ce81076cd8d997b5a1b61691 [file] [log] [blame]
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
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
25#define FUSE_SUPER_MAGIC 0x65735546
26
Miklos Szeredif85ab242004-01-07 12:16:45 +000027#ifndef KERNEL_2_6
28#define kstatfs statfs
29#endif
30
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000031#ifndef FS_SAFE
32#define FS_SAFE 0
33#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000034
35struct fuse_mount_data {
36 int fd;
37 unsigned int rootmode;
38 unsigned int uid;
39 unsigned int flags;
Miklos Szerediad051c32004-07-02 09:22:50 +000040 unsigned int max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000041};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000042
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000043static void fuse_read_inode(struct inode *inode)
44{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000045 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000046}
47
Miklos Szeredi2778f6c2004-06-21 09:45:30 +000048void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, ino_t ino,
49 int version)
50{
51 struct fuse_forget_in *inarg = &req->misc.forget_in;
52 inarg->version = version;
53 req->in.h.opcode = FUSE_FORGET;
54 req->in.h.ino = ino;
55 req->in.numargs = 1;
56 req->in.args[0].size = sizeof(struct fuse_forget_in);
57 req->in.args[0].value = inarg;
58 request_send_noreply(fc, req);
59}
60
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000061static void fuse_clear_inode(struct inode *inode)
62{
Miklos Szeredi5e183482001-10-31 14:52:35 +000063 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredid3dd2d52004-06-22 18:46:02 +000064 struct fuse_req *req = inode->u.generic_ip;
Miklos Szeredia181e612001-11-06 12:03:23 +000065
Miklos Szeredid3dd2d52004-06-22 18:46:02 +000066 if (fc == NULL) {
67 if (req)
68 fuse_request_free(req);
Miklos Szeredi43696432001-11-18 19:15:05 +000069 return;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +000070 }
71 if (req != NULL)
72 fuse_send_forget(fc, req, inode->i_ino, inode->i_version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000073}
74
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000075static void fuse_put_super(struct super_block *sb)
76{
Miklos Szeredif85ab242004-01-07 12:16:45 +000077 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000078
Miklos Szeredi79b52f62001-10-24 14:37:13 +000079 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000080 fc->sb = NULL;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +000081 fc->uid = 0;
82 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +000083 /* Flush all readers on this fs */
84 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +000085 fuse_release_conn(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +000086 SB_FC(sb) = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +000087 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000088}
89
Miklos Szeredif85ab242004-01-07 12:16:45 +000090static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +000091{
92 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +000093 stbuf->f_bsize = attr->bsize;
Mark Glinesd84b39a2002-01-07 16:32:02 +000094 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +000095 stbuf->f_bfree = attr->bfree;
96 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +000097 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +000098 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +000099 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000100 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000101}
102
Miklos Szeredif85ab242004-01-07 12:16:45 +0000103static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000104{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000105 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000106 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000107 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000108 int err;
109
110 req = fuse_get_request(fc);
111 if (!req)
112 return -ERESTARTSYS;
113
114 req->in.numargs = 0;
115 req->in.h.opcode = FUSE_STATFS;
116 req->out.numargs = 1;
117 req->out.args[0].size = sizeof(outarg);
118 req->out.args[0].value = &outarg;
119 request_send(fc, req);
120 err = req->out.h.error;
121 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000122 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000123 fuse_put_request(fc, req);
124 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000125}
126
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000127enum { opt_fd, opt_rootmode, opt_uid, opt_default_permissions,
Miklos Szerediad051c32004-07-02 09:22:50 +0000128 opt_allow_other, opt_kernel_cache, opt_large_read, opt_direct_io,
129 opt_max_read, opt_err };
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000130
131static match_table_t tokens = {
132 {opt_fd, "fd=%u"},
133 {opt_rootmode, "rootmode=%o"},
134 {opt_uid, "uid=%u"},
135 {opt_default_permissions, "default_permissions"},
136 {opt_allow_other, "allow_other"},
137 {opt_kernel_cache, "kernel_cache"},
138 {opt_large_read, "large_read"},
Miklos Szerediad051c32004-07-02 09:22:50 +0000139 {opt_direct_io, "direct_io"},
140 {opt_max_read, "max_read" },
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000141 {opt_err, NULL}
142};
143
144static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
145{
146 char *p;
147 memset(d, 0, sizeof(struct fuse_mount_data));
148 d->fd = -1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000149 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000150
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000151 while ((p = strsep(&opt, ",")) != NULL) {
152 int token;
153 int value;
154 substring_t args[MAX_OPT_ARGS];
155 if (!*p)
156 continue;
157
158 token = match_token(p, tokens, args);
159 switch (token) {
160 case opt_fd:
161 if (match_int(&args[0], &value))
162 return 0;
163 d->fd = value;
164 break;
165
166 case opt_rootmode:
167 if (match_octal(&args[0], &value))
168 return 0;
169 d->rootmode = value;
170 break;
171
172 case opt_uid:
173 if (match_int(&args[0], &value))
174 return 0;
175 d->uid = value;
176 break;
177
178 case opt_default_permissions:
179 d->flags |= FUSE_DEFAULT_PERMISSIONS;
180 break;
181
182 case opt_allow_other:
183 d->flags |= FUSE_ALLOW_OTHER;
184 break;
185
186 case opt_kernel_cache:
187 d->flags |= FUSE_KERNEL_CACHE;
188 break;
189
190 case opt_large_read:
191 d->flags |= FUSE_LARGE_READ;
192 break;
Miklos Szerediad051c32004-07-02 09:22:50 +0000193
194 case opt_direct_io:
195 d->flags |= FUSE_DIRECT_IO;
196 break;
197
198 case opt_max_read:
199 if (match_int(&args[0], &value))
200 return 0;
201 d->max_read = value;
202 break;
203
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000204 default:
205 return 0;
206 }
207 }
208 if (d->fd == -1)
209 return 0;
210
211 return 1;
212}
213
214static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
215{
216 struct fuse_conn *fc = SB_FC(mnt->mnt_sb);
217
218 seq_printf(m, ",uid=%u", fc->uid);
219 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
220 seq_puts(m, ",default_permissions");
221 if (fc->flags & FUSE_ALLOW_OTHER)
222 seq_puts(m, ",allow_other");
223 if (fc->flags & FUSE_KERNEL_CACHE)
224 seq_puts(m, ",kernel_cache");
225 if (fc->flags & FUSE_LARGE_READ)
226 seq_puts(m, ",large_read");
Miklos Szerediad051c32004-07-02 09:22:50 +0000227 if (fc->flags & FUSE_DIRECT_IO)
228 seq_puts(m, ",direct_io");
229 if (fc->max_read != ~0)
230 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000231 return 0;
232}
233
Miklos Szeredied62d862004-06-20 08:57:39 +0000234static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000235{
Miklos Szeredied62d862004-06-20 08:57:39 +0000236 struct fuse_conn *fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000237 struct inode *ino;
238
Miklos Szeredied62d862004-06-20 08:57:39 +0000239 ino = file->f_dentry->d_inode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000240 if (!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
Miklos Szeredied62d862004-06-20 08:57:39 +0000241 printk("FUSE: bad communication file descriptor\n");
242 return NULL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000243 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000244 fc = file->private_data;
Miklos Szeredied62d862004-06-20 08:57:39 +0000245 if (fc->sb != NULL) {
246 printk("fuse_read_super: connection already mounted\n");
247 return NULL;
248 }
249 fc->sb = sb;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000250 return fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000251}
252
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000253static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000254{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000255 struct fuse_attr attr;
256 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000257
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000258 attr.mode = mode;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000259 return fuse_iget(sb, 1, 0, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000260}
261
Miklos Szeredie815c032004-01-19 18:20:49 +0000262
263#ifdef KERNEL_2_6
264
265static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
266{
267 __u32 *objp = vobjp;
268 unsigned long ino = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000269 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000270 struct inode *inode;
271 struct dentry *entry;
272
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000273 if (ino == 0)
Miklos Szeredie815c032004-01-19 18:20:49 +0000274 return ERR_PTR(-ESTALE);
275
276 inode = ilookup(sb, ino);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000277 if (!inode || inode->i_generation != generation)
Miklos Szeredie815c032004-01-19 18:20:49 +0000278 return ERR_PTR(-ESTALE);
279
280 entry = d_alloc_anon(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000281 if (!entry) {
Miklos Szeredie815c032004-01-19 18:20:49 +0000282 iput(inode);
283 return ERR_PTR(-ENOMEM);
284 }
285
286 return entry;
287}
288
289static struct export_operations fuse_export_operations = {
290 .get_dentry = fuse_get_dentry,
291};
292#endif
293
294static struct super_operations fuse_super_operations = {
295 .read_inode = fuse_read_inode,
296 .clear_inode = fuse_clear_inode,
297 .put_super = fuse_put_super,
298 .statfs = fuse_statfs,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000299 .show_options = fuse_show_options,
Miklos Szeredie815c032004-01-19 18:20:49 +0000300};
301
Miklos Szeredif85ab242004-01-07 12:16:45 +0000302static int fuse_read_super(struct super_block *sb, void *data, int silent)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000303{
304 struct fuse_conn *fc;
305 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000306 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000307 struct file *file;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000308
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000309 if (!parse_fuse_opt((char *) data, &d))
310 return -EINVAL;
311
312 if ((d.flags & FUSE_ALLOW_OTHER) && !capable(CAP_SYS_ADMIN))
313 return -EPERM;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000314
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000315 sb->s_blocksize = PAGE_CACHE_SIZE;
316 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
317 sb->s_magic = FUSE_SUPER_MAGIC;
318 sb->s_op = &fuse_super_operations;
319 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredie815c032004-01-19 18:20:49 +0000320#ifdef KERNEL_2_6
321 sb->s_export_op = &fuse_export_operations;
322#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000323
Miklos Szeredied62d862004-06-20 08:57:39 +0000324 file = fget(d.fd);
325 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000326 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000327
Miklos Szeredi307242f2004-01-26 11:28:44 +0000328 spin_lock(&fuse_lock);
Miklos Szeredied62d862004-06-20 08:57:39 +0000329 fc = get_conn(file, sb);
330 spin_unlock(&fuse_lock);
331 fput(file);
332 if (fc == NULL)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000333 return -EINVAL;
Miklos Szeredied62d862004-06-20 08:57:39 +0000334
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000335 fc->flags = d.flags;
336 fc->uid = d.uid;
Miklos Szerediad051c32004-07-02 09:22:50 +0000337 fc->max_read = d.max_read;
338 fc->max_write = FUSE_MAX_IN / 2;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000339
340 /* fc is needed in fuse_init_file_inode which could be called
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000341 from get_root_inode */
Miklos Szeredi307242f2004-01-26 11:28:44 +0000342 SB_FC(sb) = fc;
343
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000344 root = get_root_inode(sb, d.rootmode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000345 if (root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000346 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredied62d862004-06-20 08:57:39 +0000347 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000348 }
349
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000350 sb->s_root = d_alloc_root(root);
Miklos Szeredied62d862004-06-20 08:57:39 +0000351 if (!sb->s_root) {
352 iput(root);
353 goto err;
354 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000355
Miklos Szeredif85ab242004-01-07 12:16:45 +0000356 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000357
358 err:
359 spin_lock(&fuse_lock);
360 fc->sb = NULL;
361 fuse_release_conn(fc);
362 spin_unlock(&fuse_lock);
363 SB_FC(sb) = NULL;
364 return -EINVAL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000365}
366
Miklos Szeredif85ab242004-01-07 12:16:45 +0000367#ifdef KERNEL_2_6
368static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000369 int flags, const char *dev_name,
370 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000371{
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000372 return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000373}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000374
Miklos Szeredif85ab242004-01-07 12:16:45 +0000375static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000376 .owner = THIS_MODULE,
377 .name = "fuse",
378 .get_sb = fuse_get_sb,
379 .kill_sb = kill_anon_super,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000380 .fs_flags = FS_SAFE,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000381};
382#else
383static struct super_block *fuse_read_super_compat(struct super_block *sb,
384 void *data, int silent)
385{
386 int err = fuse_read_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000387 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000388 return NULL;
389 else
390 return sb;
391}
392
393static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
394#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000395
396int fuse_fs_init()
397{
398 int res;
399
400 res = register_filesystem(&fuse_fs_type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000401 if (res)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000402 printk("fuse: failed to register filesystem\n");
403
404 return res;
405}
406
407void fuse_fs_cleanup()
408{
409 unregister_filesystem(&fuse_fs_type);
410}
411
412/*
413 * Local Variables:
414 * indent-tabs-mode: t
415 * c-basic-offset: 8
Miklos Szeredi63a63bc2001-12-02 20:37:53 +0000416 * End:
417 */