blob: 81a6fa89bda5e8e3c3d6b91b83edf42fd723f6e5 [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 Szeredibc22e7b2001-10-23 19:26:04 +000026static void fuse_read_inode(struct inode *inode)
27{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000028 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000029}
30
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000031static void fuse_clear_inode(struct inode *inode)
32{
Miklos Szeredi5e183482001-10-31 14:52:35 +000033 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi43696432001-11-18 19:15:05 +000034 struct fuse_in *in = NULL;
35 struct fuse_forget_in *inarg = NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000036
Miklos Szeredi43696432001-11-18 19:15:05 +000037 if(fc == NULL)
38 return;
39
40 in = kmalloc(sizeof(struct fuse_in), GFP_NOFS);
41 if(!in)
42 return;
Miklos Szeredife25def2001-12-20 15:38:05 +000043 memset(in, 0, sizeof(struct fuse_in));
Miklos Szeredi43696432001-11-18 19:15:05 +000044
45 inarg = kmalloc(sizeof(struct fuse_forget_in), GFP_NOFS);
46 if(!inarg)
47 goto out_free;
Miklos Szeredia181e612001-11-06 12:03:23 +000048
Miklos Szeredi43696432001-11-18 19:15:05 +000049 memset(inarg, 0, sizeof(struct fuse_forget_in));
50 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
61 out_free:
62 kfree(inarg);
63 kfree(in);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000064}
65
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000066static void fuse_put_super(struct super_block *sb)
67{
Miklos Szeredif85ab242004-01-07 12:16:45 +000068 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000069
Miklos Szeredi79b52f62001-10-24 14:37:13 +000070 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000071 fc->sb = NULL;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +000072 fc->uid = 0;
73 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +000074 /* Flush all readers on this fs */
75 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +000076 fuse_release_conn(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +000077 SB_FC(sb) = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +000078 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000079}
80
Miklos Szeredif85ab242004-01-07 12:16:45 +000081static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +000082{
83 stbuf->f_type = FUSE_SUPER_MAGIC;
84 stbuf->f_bsize = attr->block_size;
85 stbuf->f_blocks = attr->blocks;
86 stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free;
87 stbuf->f_files = attr->files;
88 stbuf->f_ffree = attr->files_free;
89 /* Is this field necessary? Most filesystems ignore it...
90 stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff;
91 stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */
92 stbuf->f_namelen = attr->namelen;
93}
94
Miklos Szeredif85ab242004-01-07 12:16:45 +000095static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +000096{
Miklos Szeredif85ab242004-01-07 12:16:45 +000097 struct fuse_conn *fc = SB_FC(sb);
Mark Glinesd84b39a2002-01-07 16:32:02 +000098 struct fuse_in in = FUSE_IN_INIT;
99 struct fuse_out out = FUSE_OUT_INIT;
100 struct fuse_statfs_out outarg;
101
102 in.numargs = 0;
103 in.h.opcode = FUSE_STATFS;
104 out.numargs = 1;
105 out.args[0].size = sizeof(outarg);
106 out.args[0].value = &outarg;
107 request_send(fc, &in, &out);
108 if(!out.h.error)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000109 convert_fuse_statfs(buf, &outarg.st);
Mark Glinesd84b39a2002-01-07 16:32:02 +0000110
111 return out.h.error;
112}
113
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000114static struct super_operations fuse_super_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000115 .read_inode = fuse_read_inode,
116 .clear_inode = fuse_clear_inode,
117 .put_super = fuse_put_super,
118 .statfs = fuse_statfs,
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000119};
120
121
122static struct fuse_conn *get_conn(struct fuse_mount_data *d)
123{
124 struct fuse_conn *fc = NULL;
125 struct file *file;
126 struct inode *ino;
127
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000128 if(d == NULL) {
129 printk("fuse_read_super: Bad mount data\n");
130 return NULL;
131 }
132
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000133 if(d->version != FUSE_KERNEL_VERSION) {
134 printk("fuse_read_super: Bad version: %i\n", d->version);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000135 return NULL;
136 }
137
138 file = fget(d->fd);
139 ino = NULL;
140 if(file)
141 ino = file->f_dentry->d_inode;
142
Miklos Szeredi60c23522002-10-24 09:19:43 +0000143 if(!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000144 printk("fuse_read_super: Bad file: %i\n", d->fd);
145 goto out;
146 }
147
148 fc = file->private_data;
149
150 out:
151 fput(file);
152 return fc;
153
154}
155
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000156static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000157{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000158 struct fuse_attr attr;
159 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000160
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000161 attr.mode = mode;
Miklos Szeredia181e612001-11-06 12:03:23 +0000162 return fuse_iget(sb, 1, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000163}
164
Miklos Szeredif85ab242004-01-07 12:16:45 +0000165static int fuse_read_super(struct super_block *sb, void *data, int silent)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000166{
167 struct fuse_conn *fc;
168 struct inode *root;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000169 struct fuse_mount_data *d = data;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000170
Miklos Szeredi05033042001-11-13 16:11:35 +0000171 sb->s_blocksize = PAGE_CACHE_SIZE;
172 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000173 sb->s_magic = FUSE_SUPER_MAGIC;
174 sb->s_op = &fuse_super_operations;
175
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000176 root = get_root_inode(sb, d->rootmode);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000177 if(root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000178 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredif85ab242004-01-07 12:16:45 +0000179 return -EINVAL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000180 }
181
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000182 spin_lock(&fuse_lock);
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000183 fc = get_conn(d);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000184 if(fc == NULL)
185 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000186
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000187 if(fc->sb != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000188 printk("fuse_read_super: connection already mounted\n");
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000189 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000190 }
191
Miklos Szeredif85ab242004-01-07 12:16:45 +0000192 SB_FC(sb) = fc;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000193 sb->s_root = d_alloc_root(root);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000194 if(!sb->s_root)
195 goto err;
196
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000197 fc->sb = sb;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000198 fc->flags = d->flags;
199 fc->uid = d->uid;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000200 spin_unlock(&fuse_lock);
201
Miklos Szeredif85ab242004-01-07 12:16:45 +0000202 return 0;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000203
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000204 err:
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000205 spin_unlock(&fuse_lock);
206 iput(root);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000207 return -EINVAL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000208}
209
Miklos Szeredif85ab242004-01-07 12:16:45 +0000210#ifdef KERNEL_2_6
211static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000212 int flags, const char *dev_name,
213 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000214{
215 return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
216}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000217
Miklos Szeredif85ab242004-01-07 12:16:45 +0000218static struct file_system_type fuse_fs_type = {
219 .owner = THIS_MODULE,
220 .name = "fuse",
221 .get_sb = fuse_get_sb,
222 .kill_sb = kill_anon_super,
223 .fs_flags = 0
224};
225#else
226static struct super_block *fuse_read_super_compat(struct super_block *sb,
227 void *data, int silent)
228{
229 int err = fuse_read_super(sb, data, silent);
230 if(err)
231 return NULL;
232 else
233 return sb;
234}
235
236static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
237#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000238
239int fuse_fs_init()
240{
241 int res;
242
243 res = register_filesystem(&fuse_fs_type);
244 if(res)
245 printk("fuse: failed to register filesystem\n");
246
247 return res;
248}
249
250void fuse_fs_cleanup()
251{
252 unregister_filesystem(&fuse_fs_type);
253}
254
255/*
256 * Local Variables:
257 * indent-tabs-mode: t
258 * c-basic-offset: 8
Miklos Szeredi63a63bc2001-12-02 20:37:53 +0000259 * End:
260 */