blob: ed4f760735e72b45810ebb43c4678a3de5220f5b [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
11#include <linux/module.h>
12#include <linux/kernel.h>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000013#include <linux/sched.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014#include <linux/slab.h>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000015#include <linux/file.h>
16
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 send_forget(struct fuse_conn *fc, unsigned long *forget,
25 unsigned int numforget)
26{
27 struct fuse_in in = FUSE_IN_INIT;
28
29 in.h.opcode = FUSE_FORGET;
30 in.h.ino = 0;
31 in.argsize = numforget * sizeof(unsigned long);
32 in.arg = forget;
33
34 request_send(fc, &in, NULL);
35}
36
37static int alloc_cleared(struct fuse_conn *fc)
38{
39 unsigned long *tmp;
40
41 spin_unlock(&fuse_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +000042 tmp = kmalloc(sizeof(unsigned long) * MAX_CLEARED, GFP_NOFS);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000043 spin_lock(&fuse_lock);
44
45 if(!fc->file || fc->cleared != NULL)
46 kfree(tmp);
47 else if(!tmp)
48 printk("fuse_clear_inode: Cannot allocate memory\n");
49 else
50 fc->cleared = tmp;
51
52 return fc->cleared != NULL;
53}
54
55static unsigned long *add_cleared(struct fuse_conn *fc, unsigned long ino)
56{
57 if(!fc->file || (!fc->cleared && !alloc_cleared(fc)))
58 return NULL;
59
60 fc->cleared[fc->numcleared] = ino;
61 fc->numcleared ++;
62
63 if(fc->numcleared == MAX_CLEARED) {
64 unsigned long *tmp = fc->cleared;
65 fc->cleared = NULL;
66 fc->numcleared = 0;
67 return tmp;
68 }
69
70 return NULL;
71}
72
73static void fuse_clear_inode(struct inode *inode)
74{
Miklos Szeredi5e183482001-10-31 14:52:35 +000075 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000076 unsigned long *forget;
77
78 spin_lock(&fuse_lock);
79 forget = add_cleared(fc, inode->i_ino);
80 spin_unlock(&fuse_lock);
81
82 if(forget) {
83 send_forget(fc, forget, MAX_CLEARED);
84 kfree(forget);
85 }
86}
87
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000088static void fuse_put_super(struct super_block *sb)
89{
90 struct fuse_conn *fc = sb->u.generic_sbp;
91
Miklos Szeredi79b52f62001-10-24 14:37:13 +000092 spin_lock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000093 fc->sb = NULL;
94 fuse_release_conn(fc);
Miklos Szeredi79b52f62001-10-24 14:37:13 +000095 spin_unlock(&fuse_lock);
96
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000097}
98
99static struct super_operations fuse_super_operations = {
100 read_inode: fuse_read_inode,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000101 clear_inode: fuse_clear_inode,
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000102 put_super: fuse_put_super,
103};
104
105
106static struct fuse_conn *get_conn(struct fuse_mount_data *d)
107{
108 struct fuse_conn *fc = NULL;
109 struct file *file;
110 struct inode *ino;
111
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000112 if(d == NULL) {
113 printk("fuse_read_super: Bad mount data\n");
114 return NULL;
115 }
116
117 if(d->version != FUSE_MOUNT_VERSION) {
118 printk("fuse_read_super: Bad mount version: %i\n", d->version);
119 return NULL;
120 }
121
122 file = fget(d->fd);
123 ino = NULL;
124 if(file)
125 ino = file->f_dentry->d_inode;
126
127 if(!ino || ino->u.generic_ip != proc_fuse_dev) {
128 printk("fuse_read_super: Bad file: %i\n", d->fd);
129 goto out;
130 }
131
132 fc = file->private_data;
133
134 out:
135 fput(file);
136 return fc;
137
138}
139
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000140static struct inode *get_root_inode(struct super_block *sb)
141{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000142 struct fuse_attr attr;
143 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000144
Miklos Szeredi5e183482001-10-31 14:52:35 +0000145 attr.mode = S_IFDIR;
146 return fuse_iget(sb, 1, &attr);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000147}
148
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000149static struct super_block *fuse_read_super(struct super_block *sb,
150 void *data, int silent)
151{
152 struct fuse_conn *fc;
153 struct inode *root;
154
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000155 sb->s_blocksize = 1024;
156 sb->s_blocksize_bits = 10;
157 sb->s_magic = FUSE_SUPER_MAGIC;
158 sb->s_op = &fuse_super_operations;
159
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000160 root = get_root_inode(sb);
161 if(root == NULL) {
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000162 printk("fuse_read_super: failed to get root inode\n");
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000163 return NULL;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000164 }
165
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000166 spin_lock(&fuse_lock);
167 fc = get_conn(data);
168 if(fc == NULL)
169 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000170
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000171 if(fc->sb != NULL) {
172 printk("fuse_read_super: connection %i already mounted\n",
173 fc->id);
174 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000175 }
176
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000177 sb->u.generic_sbp = fc;
178 sb->s_root = d_alloc_root(root);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000179 if(!sb->s_root)
180 goto err;
181
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000182 fc->sb = sb;
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000183 spin_unlock(&fuse_lock);
184
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000185 return sb;
186
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000187 err:
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000188 spin_unlock(&fuse_lock);
189 iput(root);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000190 return NULL;
191}
192
193
194static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super, 0);
195
196int fuse_fs_init()
197{
198 int res;
199
200 res = register_filesystem(&fuse_fs_type);
201 if(res)
202 printk("fuse: failed to register filesystem\n");
203
204 return res;
205}
206
207void fuse_fs_cleanup()
208{
209 unregister_filesystem(&fuse_fs_type);
210}
211
212/*
213 * Local Variables:
214 * indent-tabs-mode: t
215 * c-basic-offset: 8
216 * End:
217 */
218