blob: 257b41d0f4178316f8cbda603ae0e65141cca381 [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 Szeredi60c23522002-10-24 09:19:43 +000015#include <linux/proc_fs.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000016#ifdef KERNEL_2_6
17#include <linux/statfs.h>
18#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000019
20#define FUSE_SUPER_MAGIC 0x65735546
21
Miklos Szeredif85ab242004-01-07 12:16:45 +000022#ifndef KERNEL_2_6
23#define kstatfs statfs
24#endif
25
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000026#ifndef FS_SAFE
27#define FS_SAFE 0
28#endif
29
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000030static void fuse_read_inode(struct inode *inode)
31{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000032 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000033}
34
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000035static void fuse_clear_inode(struct inode *inode)
36{
Miklos Szeredi5e183482001-10-31 14:52:35 +000037 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi43696432001-11-18 19:15:05 +000038 struct fuse_in *in = NULL;
39 struct fuse_forget_in *inarg = NULL;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000040 unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_forget_in);
Miklos Szeredia181e612001-11-06 12:03:23 +000041
Miklos Szeredi43696432001-11-18 19:15:05 +000042 if(fc == NULL)
43 return;
44
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000045 in = kmalloc(s, GFP_NOFS);
Miklos Szeredi43696432001-11-18 19:15:05 +000046 if(!in)
47 return;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000048 memset(in, 0, s);
49 inarg = (struct fuse_forget_in *) (in + 1);
Miklos Szeredi43696432001-11-18 19:15:05 +000050 inarg->version = inode->i_version;
51
52 in->h.opcode = FUSE_FORGET;
53 in->h.ino = inode->i_ino;
54 in->numargs = 1;
55 in->args[0].size = sizeof(struct fuse_forget_in);
56 in->args[0].value = inarg;
57
58 if(!request_send_noreply(fc, in))
59 return;
60
Miklos Szeredi43696432001-11-18 19:15:05 +000061 kfree(in);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000062}
63
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000064static void fuse_put_super(struct super_block *sb)
65{
Miklos Szeredif85ab242004-01-07 12:16:45 +000066 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000067
Miklos Szeredi79b52f62001-10-24 14:37:13 +000068 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000069 fc->sb = NULL;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +000070 fc->uid = 0;
71 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +000072 /* Flush all readers on this fs */
73 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +000074 fuse_release_conn(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +000075 SB_FC(sb) = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +000076 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000077}
78
Miklos Szeredif85ab242004-01-07 12:16:45 +000079static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +000080{
81 stbuf->f_type = FUSE_SUPER_MAGIC;
82 stbuf->f_bsize = attr->block_size;
83 stbuf->f_blocks = attr->blocks;
84 stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free;
85 stbuf->f_files = attr->files;
86 stbuf->f_ffree = attr->files_free;
87 /* Is this field necessary? Most filesystems ignore it...
88 stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff;
89 stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */
90 stbuf->f_namelen = attr->namelen;
91}
92
Miklos Szeredif85ab242004-01-07 12:16:45 +000093static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +000094{
Miklos Szeredif85ab242004-01-07 12:16:45 +000095 struct fuse_conn *fc = SB_FC(sb);
Mark Glinesd84b39a2002-01-07 16:32:02 +000096 struct fuse_in in = FUSE_IN_INIT;
97 struct fuse_out out = FUSE_OUT_INIT;
98 struct fuse_statfs_out outarg;
99
100 in.numargs = 0;
101 in.h.opcode = FUSE_STATFS;
102 out.numargs = 1;
103 out.args[0].size = sizeof(outarg);
104 out.args[0].value = &outarg;
105 request_send(fc, &in, &out);
106 if(!out.h.error)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000107 convert_fuse_statfs(buf, &outarg.st);
Mark Glinesd84b39a2002-01-07 16:32:02 +0000108
109 return out.h.error;
110}
111
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000112static struct fuse_conn *get_conn(struct fuse_mount_data *d)
113{
114 struct fuse_conn *fc = NULL;
115 struct file *file;
116 struct inode *ino;
117
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000118 if(d == NULL) {
119 printk("fuse_read_super: Bad mount data\n");
120 return NULL;
121 }
122
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000123 if(d->version != FUSE_KERNEL_VERSION) {
124 printk("fuse_read_super: Bad version: %i\n", d->version);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000125 return NULL;
126 }
127
128 file = fget(d->fd);
129 ino = NULL;
130 if(file)
131 ino = file->f_dentry->d_inode;
132
Miklos Szeredi60c23522002-10-24 09:19:43 +0000133 if(!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000134 printk("fuse_read_super: Bad file: %i\n", d->fd);
135 goto out;
136 }
137
138 fc = file->private_data;
139
140 out:
141 fput(file);
142 return fc;
143
144}
145
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000146static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000147{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000148 struct fuse_attr attr;
149 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000150
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000151 attr.mode = mode;
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 return fuse_iget(sb, 1, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000153}
154
Miklos Szeredie815c032004-01-19 18:20:49 +0000155
156#ifdef KERNEL_2_6
157
158static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
159{
160 __u32 *objp = vobjp;
161 unsigned long ino = objp[0];
162 /* __u32 generation = objp[1]; */
163 struct inode *inode;
164 struct dentry *entry;
165
166 if(ino == 0)
167 return ERR_PTR(-ESTALE);
168
169 inode = ilookup(sb, ino);
170 if(!inode)
171 return ERR_PTR(-ESTALE);
172
173 entry = d_alloc_anon(inode);
174 if(!entry) {
175 iput(inode);
176 return ERR_PTR(-ENOMEM);
177 }
178
179 return entry;
180}
181
182static struct export_operations fuse_export_operations = {
183 .get_dentry = fuse_get_dentry,
184};
185#endif
186
187static struct super_operations fuse_super_operations = {
188 .read_inode = fuse_read_inode,
189 .clear_inode = fuse_clear_inode,
190 .put_super = fuse_put_super,
191 .statfs = fuse_statfs,
192};
193
Miklos Szeredif85ab242004-01-07 12:16:45 +0000194static int fuse_read_super(struct super_block *sb, void *data, int silent)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000195{
196 struct fuse_conn *fc;
197 struct inode *root;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000198 struct fuse_mount_data *d = data;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000199
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000200 if(!capable(CAP_SYS_ADMIN)) {
201 if(d->flags & FUSE_ALLOW_OTHER)
202 return -EPERM;
203 }
204
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000205 sb->s_blocksize = PAGE_CACHE_SIZE;
206 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
207 sb->s_magic = FUSE_SUPER_MAGIC;
208 sb->s_op = &fuse_super_operations;
209 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredie815c032004-01-19 18:20:49 +0000210#ifdef KERNEL_2_6
211 sb->s_export_op = &fuse_export_operations;
212#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000213
Miklos Szeredi307242f2004-01-26 11:28:44 +0000214 fc = get_conn(d);
215 if(fc == NULL)
216 return -EINVAL;
217 spin_lock(&fuse_lock);
218 if(fc->sb != NULL) {
219 printk("fuse_read_super: connection already mounted\n");
220 spin_unlock(&fuse_lock);
221 return -EINVAL;
222 }
223 fc->sb = sb;
224 fc->flags = d->flags;
225 fc->uid = d->uid;
226 spin_unlock(&fuse_lock);
227
228 /* fc is needed in fuse_init_file_inode which could be called
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000229 from get_root_inode */
Miklos Szeredi307242f2004-01-26 11:28:44 +0000230 SB_FC(sb) = fc;
231
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000232 root = get_root_inode(sb, d->rootmode);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000233 if(root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000234 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredif85ab242004-01-07 12:16:45 +0000235 return -EINVAL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000236 }
237
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000238 sb->s_root = d_alloc_root(root);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000239 if(!sb->s_root)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000240 return -EINVAL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000241
Miklos Szeredif85ab242004-01-07 12:16:45 +0000242 return 0;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000243}
244
Miklos Szeredif85ab242004-01-07 12:16:45 +0000245#ifdef KERNEL_2_6
246static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000247 int flags, const char *dev_name,
248 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000249{
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000250 return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000251}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000252
Miklos Szeredif85ab242004-01-07 12:16:45 +0000253static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000254 .owner = THIS_MODULE,
255 .name = "fuse",
256 .get_sb = fuse_get_sb,
257 .kill_sb = kill_anon_super,
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000258 .fs_flags = FS_SAFE,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000259};
260#else
261static struct super_block *fuse_read_super_compat(struct super_block *sb,
262 void *data, int silent)
263{
264 int err = fuse_read_super(sb, data, silent);
265 if(err)
266 return NULL;
267 else
268 return sb;
269}
270
271static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
272#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000273
274int fuse_fs_init()
275{
276 int res;
277
278 res = register_filesystem(&fuse_fs_type);
279 if(res)
280 printk("fuse: failed to register filesystem\n");
281
282 return res;
283}
284
285void fuse_fs_cleanup()
286{
287 unregister_filesystem(&fuse_fs_type);
288}
289
290/*
291 * Local Variables:
292 * indent-tabs-mode: t
293 * c-basic-offset: 8
Miklos Szeredi63a63bc2001-12-02 20:37:53 +0000294 * End:
295 */