blob: 0cb8b653bd6e6bd7bc5386214d3c57f925b2a9fc [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 Szeredibc22e7b2001-10-23 19:26:04 +000016
17#define FUSE_SUPER_MAGIC 0x65735546
18
19static void fuse_read_inode(struct inode *inode)
20{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000021 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000022}
23
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000024static void fuse_clear_inode(struct inode *inode)
25{
Miklos Szeredi5e183482001-10-31 14:52:35 +000026 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi43696432001-11-18 19:15:05 +000027 struct fuse_in *in = NULL;
28 struct fuse_forget_in *inarg = NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000029
Miklos Szeredi43696432001-11-18 19:15:05 +000030 if(fc == NULL)
31 return;
32
33 in = kmalloc(sizeof(struct fuse_in), GFP_NOFS);
34 if(!in)
35 return;
Miklos Szeredife25def2001-12-20 15:38:05 +000036 memset(in, 0, sizeof(struct fuse_in));
Miklos Szeredi43696432001-11-18 19:15:05 +000037
38 inarg = kmalloc(sizeof(struct fuse_forget_in), GFP_NOFS);
39 if(!inarg)
40 goto out_free;
Miklos Szeredia181e612001-11-06 12:03:23 +000041
Miklos Szeredi43696432001-11-18 19:15:05 +000042 memset(inarg, 0, sizeof(struct fuse_forget_in));
43 inarg->version = inode->i_version;
44
45 in->h.opcode = FUSE_FORGET;
46 in->h.ino = inode->i_ino;
47 in->numargs = 1;
48 in->args[0].size = sizeof(struct fuse_forget_in);
49 in->args[0].value = inarg;
50
51 if(!request_send_noreply(fc, in))
52 return;
53
54 out_free:
55 kfree(inarg);
56 kfree(in);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000057}
58
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000059static void fuse_put_super(struct super_block *sb)
60{
61 struct fuse_conn *fc = sb->u.generic_sbp;
62
Miklos Szeredi79b52f62001-10-24 14:37:13 +000063 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000064 fc->sb = NULL;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +000065 fc->uid = 0;
66 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +000067 /* Flush all readers on this fs */
68 wake_up_all(&fc->waitq);
Miklos Szeredi79b461a2003-03-10 09:35:34 +000069 fuse_release_conn(fc);
70 sb->u.generic_sbp = NULL;
Miklos Szeredi79b52f62001-10-24 14:37:13 +000071 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000072}
73
Miklos Szeredi24ed9452002-10-07 10:24:26 +000074static void convert_fuse_statfs(struct statfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +000075{
76 stbuf->f_type = FUSE_SUPER_MAGIC;
77 stbuf->f_bsize = attr->block_size;
78 stbuf->f_blocks = attr->blocks;
79 stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free;
80 stbuf->f_files = attr->files;
81 stbuf->f_ffree = attr->files_free;
82 /* Is this field necessary? Most filesystems ignore it...
83 stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff;
84 stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */
85 stbuf->f_namelen = attr->namelen;
86}
87
88static int fuse_statfs(struct super_block *sb, struct statfs *st)
89{
90 struct fuse_conn *fc = sb->u.generic_sbp;
91 struct fuse_in in = FUSE_IN_INIT;
92 struct fuse_out out = FUSE_OUT_INIT;
93 struct fuse_statfs_out outarg;
94
95 in.numargs = 0;
96 in.h.opcode = FUSE_STATFS;
97 out.numargs = 1;
98 out.args[0].size = sizeof(outarg);
99 out.args[0].value = &outarg;
100 request_send(fc, &in, &out);
101 if(!out.h.error)
102 convert_fuse_statfs(st,&outarg.st);
103
104 return out.h.error;
105}
106
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000107static struct super_operations fuse_super_operations = {
108 read_inode: fuse_read_inode,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109 clear_inode: fuse_clear_inode,
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000110 put_super: fuse_put_super,
Mark Glinesd84b39a2002-01-07 16:32:02 +0000111 statfs: fuse_statfs,
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000112};
113
114
115static struct fuse_conn *get_conn(struct fuse_mount_data *d)
116{
117 struct fuse_conn *fc = NULL;
118 struct file *file;
119 struct inode *ino;
120
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000121 if(d == NULL) {
122 printk("fuse_read_super: Bad mount data\n");
123 return NULL;
124 }
125
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000126 if(d->version != FUSE_KERNEL_VERSION) {
127 printk("fuse_read_super: Bad version: %i\n", d->version);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000128 return NULL;
129 }
130
131 file = fget(d->fd);
132 ino = NULL;
133 if(file)
134 ino = file->f_dentry->d_inode;
135
Miklos Szeredi60c23522002-10-24 09:19:43 +0000136 if(!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000137 printk("fuse_read_super: Bad file: %i\n", d->fd);
138 goto out;
139 }
140
141 fc = file->private_data;
142
143 out:
144 fput(file);
145 return fc;
146
147}
148
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000149static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000150{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000151 struct fuse_attr attr;
152 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000153
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000154 attr.mode = mode;
Miklos Szeredia181e612001-11-06 12:03:23 +0000155 return fuse_iget(sb, 1, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000156}
157
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000158static struct super_block *fuse_read_super(struct super_block *sb,
159 void *data, int silent)
160{
161 struct fuse_conn *fc;
162 struct inode *root;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000163 struct fuse_mount_data *d = data;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000164
Miklos Szeredi05033042001-11-13 16:11:35 +0000165 sb->s_blocksize = PAGE_CACHE_SIZE;
166 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000167 sb->s_magic = FUSE_SUPER_MAGIC;
168 sb->s_op = &fuse_super_operations;
169
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000170 root = get_root_inode(sb, d->rootmode);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000171 if(root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000172 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000173 return NULL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000174 }
175
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000176 spin_lock(&fuse_lock);
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000177 fc = get_conn(d);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000178 if(fc == NULL)
179 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000180
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000181 if(fc->sb != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000182 printk("fuse_read_super: connection already mounted\n");
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000183 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000184 }
185
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000186 sb->u.generic_sbp = fc;
187 sb->s_root = d_alloc_root(root);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000188 if(!sb->s_root)
189 goto err;
190
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000191 fc->sb = sb;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000192 fc->flags = d->flags;
193 fc->uid = d->uid;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000194 spin_unlock(&fuse_lock);
195
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000196 return sb;
197
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000198 err:
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000199 spin_unlock(&fuse_lock);
200 iput(root);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000201 return NULL;
202}
203
204
205static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super, 0);
206
207int fuse_fs_init()
208{
209 int res;
210
211 res = register_filesystem(&fuse_fs_type);
212 if(res)
213 printk("fuse: failed to register filesystem\n");
214
215 return res;
216}
217
218void fuse_fs_cleanup()
219{
220 unregister_filesystem(&fuse_fs_type);
221}
222
223/*
224 * Local Variables:
225 * indent-tabs-mode: t
226 * c-basic-offset: 8
Miklos Szeredi63a63bc2001-12-02 20:37:53 +0000227 * End:
228 */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000229