blob: 6c387080fab093cdeaae6160997b3dfd2241f8a8 [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>
15
16#define FUSE_SUPER_MAGIC 0x65735546
17
18static void fuse_read_inode(struct inode *inode)
19{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000020 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000021}
22
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000023static void fuse_clear_inode(struct inode *inode)
24{
Miklos Szeredi5e183482001-10-31 14:52:35 +000025 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi43696432001-11-18 19:15:05 +000026 struct fuse_in *in = NULL;
27 struct fuse_forget_in *inarg = NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000028
Miklos Szeredi43696432001-11-18 19:15:05 +000029 if(fc == NULL)
30 return;
31
32 in = kmalloc(sizeof(struct fuse_in), GFP_NOFS);
33 if(!in)
34 return;
Miklos Szeredife25def2001-12-20 15:38:05 +000035 memset(in, 0, sizeof(struct fuse_in));
Miklos Szeredi43696432001-11-18 19:15:05 +000036
37 inarg = kmalloc(sizeof(struct fuse_forget_in), GFP_NOFS);
38 if(!inarg)
39 goto out_free;
Miklos Szeredia181e612001-11-06 12:03:23 +000040
Miklos Szeredi43696432001-11-18 19:15:05 +000041 memset(inarg, 0, sizeof(struct fuse_forget_in));
42 inarg->version = inode->i_version;
43
44 in->h.opcode = FUSE_FORGET;
45 in->h.ino = inode->i_ino;
46 in->numargs = 1;
47 in->args[0].size = sizeof(struct fuse_forget_in);
48 in->args[0].value = inarg;
49
50 if(!request_send_noreply(fc, in))
51 return;
52
53 out_free:
54 kfree(inarg);
55 kfree(in);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000056}
57
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000058static void fuse_put_super(struct super_block *sb)
59{
60 struct fuse_conn *fc = sb->u.generic_sbp;
61
Miklos Szeredi79b52f62001-10-24 14:37:13 +000062 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000063 fc->sb = NULL;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +000064 fc->uid = 0;
65 fc->flags = 0;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000066 fuse_release_conn(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +000067 sb->u.generic_sbp = NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +000068 /* Flush all readers on this fs */
69 wake_up_all(&fc->waitq);
Miklos Szeredi79b52f62001-10-24 14:37:13 +000070 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000071}
72
Mark Glinesd84b39a2002-01-07 16:32:02 +000073static void convert_fuse_statfs(struct statfs *stbuf, struct fuse_statfs *attr)
74{
75 stbuf->f_type = FUSE_SUPER_MAGIC;
76 stbuf->f_bsize = attr->block_size;
77 stbuf->f_blocks = attr->blocks;
78 stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free;
79 stbuf->f_files = attr->files;
80 stbuf->f_ffree = attr->files_free;
81 /* Is this field necessary? Most filesystems ignore it...
82 stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff;
83 stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */
84 stbuf->f_namelen = attr->namelen;
85}
86
87static int fuse_statfs(struct super_block *sb, struct statfs *st)
88{
89 struct fuse_conn *fc = sb->u.generic_sbp;
90 struct fuse_in in = FUSE_IN_INIT;
91 struct fuse_out out = FUSE_OUT_INIT;
92 struct fuse_statfs_out outarg;
93
94 in.numargs = 0;
95 in.h.opcode = FUSE_STATFS;
96 out.numargs = 1;
97 out.args[0].size = sizeof(outarg);
98 out.args[0].value = &outarg;
99 request_send(fc, &in, &out);
100 if(!out.h.error)
101 convert_fuse_statfs(st,&outarg.st);
102
103 return out.h.error;
104}
105
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000106static struct super_operations fuse_super_operations = {
107 read_inode: fuse_read_inode,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000108 clear_inode: fuse_clear_inode,
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000109 put_super: fuse_put_super,
Mark Glinesd84b39a2002-01-07 16:32:02 +0000110 statfs: fuse_statfs,
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000111};
112
113
114static struct fuse_conn *get_conn(struct fuse_mount_data *d)
115{
116 struct fuse_conn *fc = NULL;
117 struct file *file;
118 struct inode *ino;
119
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000120 if(d == NULL) {
121 printk("fuse_read_super: Bad mount data\n");
122 return NULL;
123 }
124
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000125 if(d->version != FUSE_KERNEL_VERSION) {
126 printk("fuse_read_super: Bad version: %i\n", d->version);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000127 return NULL;
128 }
129
130 file = fget(d->fd);
131 ino = NULL;
132 if(file)
133 ino = file->f_dentry->d_inode;
134
135 if(!ino || ino->u.generic_ip != proc_fuse_dev) {
136 printk("fuse_read_super: Bad file: %i\n", d->fd);
137 goto out;
138 }
139
140 fc = file->private_data;
141
142 out:
143 fput(file);
144 return fc;
145
146}
147
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000148static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000149{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000150 struct fuse_attr attr;
151 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000152
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000153 attr.mode = mode;
Miklos Szeredia181e612001-11-06 12:03:23 +0000154 return fuse_iget(sb, 1, &attr, 0);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000155}
156
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000157static struct super_block *fuse_read_super(struct super_block *sb,
158 void *data, int silent)
159{
160 struct fuse_conn *fc;
161 struct inode *root;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000162 struct fuse_mount_data *d = data;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000163
Miklos Szeredi05033042001-11-13 16:11:35 +0000164 sb->s_blocksize = PAGE_CACHE_SIZE;
165 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000166 sb->s_magic = FUSE_SUPER_MAGIC;
167 sb->s_op = &fuse_super_operations;
168
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000169 root = get_root_inode(sb, d->rootmode);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000170 if(root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000171 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000172 return NULL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000173 }
174
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000175 spin_lock(&fuse_lock);
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000176 fc = get_conn(d);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000177 if(fc == NULL)
178 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000179
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000180 if(fc->sb != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000181 printk("fuse_read_super: connection already mounted\n");
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000182 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000183 }
184
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000185 sb->u.generic_sbp = fc;
186 sb->s_root = d_alloc_root(root);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000187 if(!sb->s_root)
188 goto err;
189
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000190 fc->sb = sb;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000191 fc->flags = d->flags;
192 fc->uid = d->uid;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000193 spin_unlock(&fuse_lock);
194
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000195 return sb;
196
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000197 err:
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000198 spin_unlock(&fuse_lock);
199 iput(root);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000200 return NULL;
201}
202
203
204static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super, 0);
205
206int fuse_fs_init()
207{
208 int res;
209
210 res = register_filesystem(&fuse_fs_type);
211 if(res)
212 printk("fuse: failed to register filesystem\n");
213
214 return res;
215}
216
217void fuse_fs_cleanup()
218{
219 unregister_filesystem(&fuse_fs_type);
220}
221
222/*
223 * Local Variables:
224 * indent-tabs-mode: t
225 * c-basic-offset: 8
Miklos Szeredi63a63bc2001-12-02 20:37:53 +0000226 * End:
227 */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000228