blob: af374c8edc2412706822bee7f540b34488e01492 [file] [log] [blame]
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredibc22e7b2001-10-23 19:26:04 +00007*/
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 Szeredi85c74fc2001-10-28 19:44:14 +000012#include <linux/slab.h>
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000013#include <linux/file.h>
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000014#include <linux/mount.h>
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000015#include <linux/seq_file.h>
Miklos Szeredic6ee9fd2005-01-10 09:53:04 +000016#include <linux/init.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000017#include <linux/module.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000018#ifdef KERNEL_2_6
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000019#include <linux/parser.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000020#include <linux/statfs.h>
Miklos Szeredi8ec48ec2004-04-19 10:24:41 +000021#else
22#include "compat/parser.h"
Miklos Szeredif85ab242004-01-07 12:16:45 +000023#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000024
Miklos Szeredic6ee9fd2005-01-10 09:53:04 +000025MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
26MODULE_DESCRIPTION("Filesystem in Userspace");
27#ifdef MODULE_LICENSE
28MODULE_LICENSE("GPL");
29#endif
30
31spinlock_t fuse_lock;
Miklos Szeredi069c9502004-07-16 16:17:02 +000032static kmem_cache_t *fuse_inode_cachep;
Miklos Szerediacb4d362004-07-02 16:20:45 +000033
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000034#define FUSE_SUPER_MAGIC 0x65735546
35
Miklos Szeredif85ab242004-01-07 12:16:45 +000036#ifndef KERNEL_2_6
37#define kstatfs statfs
38#endif
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000039#ifndef MAX_LFS_FILESIZE
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000040#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000041#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000042struct fuse_mount_data {
43 int fd;
Miklos Szeredi83a07442004-11-30 18:25:20 +000044 unsigned rootmode;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +000045 unsigned user_id;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +000046 unsigned group_id;
Miklos Szeredi437d8112005-07-06 09:14:20 +000047 unsigned fd_present : 1;
48 unsigned rootmode_present : 1;
49 unsigned user_id_present : 1;
50 unsigned group_id_present : 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +000051 unsigned flags;
52 unsigned max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000053};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000054
Miklos Szeredia13d9002004-11-02 17:32:03 +000055static struct inode *fuse_alloc_inode(struct super_block *sb)
Miklos Szeredi069c9502004-07-16 16:17:02 +000056{
Miklos Szeredia13d9002004-11-02 17:32:03 +000057 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000058 struct fuse_inode *fi;
59
Miklos Szeredia13d9002004-11-02 17:32:03 +000060 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
61 if (!inode)
62 return NULL;
Miklos Szeredi069c9502004-07-16 16:17:02 +000063
Miklos Szeredia13d9002004-11-02 17:32:03 +000064#ifndef KERNEL_2_6
65 inode->u.generic_ip = NULL;
66#endif
Miklos Szeredi039322d2004-12-01 18:39:12 +000067 fi = get_fuse_inode(inode);
Miklos Szeredi81394522005-01-11 14:24:18 +000068 fi->i_time = jiffies - 1;
69 fi->nodeid = 0;
Miklos Szeredi38009022005-05-08 19:47:22 +000070 fi->nlookup = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +000071 fi->forget_req = fuse_request_alloc();
72 if (!fi->forget_req) {
73 kmem_cache_free(fuse_inode_cachep, inode);
74 return NULL;
75 }
Miklos Szeredia13d9002004-11-02 17:32:03 +000076
77 return inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000078}
79
Miklos Szeredia13d9002004-11-02 17:32:03 +000080static void fuse_destroy_inode(struct inode *inode)
Miklos Szeredi069c9502004-07-16 16:17:02 +000081{
Miklos Szeredi039322d2004-12-01 18:39:12 +000082 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000083 if (fi->forget_req)
84 fuse_request_free(fi->forget_req);
Miklos Szeredia13d9002004-11-02 17:32:03 +000085 kmem_cache_free(fuse_inode_cachep, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +000086}
87
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000088static void fuse_read_inode(struct inode *inode)
89{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000090 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000091}
92
Miklos Szeredia13d9002004-11-02 17:32:03 +000093void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi38009022005-05-08 19:47:22 +000094 unsigned long nodeid, u64 nlookup)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +000095{
96 struct fuse_forget_in *inarg = &req->misc.forget_in;
Miklos Szeredi38009022005-05-08 19:47:22 +000097 inarg->nlookup = nlookup;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +000098 req->in.h.opcode = FUSE_FORGET;
Miklos Szeredia13d9002004-11-02 17:32:03 +000099 req->in.h.nodeid = nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000100 req->in.numargs = 1;
101 req->in.args[0].size = sizeof(struct fuse_forget_in);
102 req->in.args[0].value = inarg;
103 request_send_noreply(fc, req);
104}
105
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000106static void fuse_clear_inode(struct inode *inode)
107{
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000108 if (inode->i_sb->s_flags & MS_ACTIVE) {
109 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000110 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi38009022005-05-08 19:47:22 +0000111 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000112 fi->forget_req = NULL;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000113 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000114}
115
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000116void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
117{
118 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
119#ifdef KERNEL_2_6
120 invalidate_inode_pages(inode->i_mapping);
121#else
122 invalidate_inode_pages(inode);
123#endif
124
125 inode->i_ino = attr->ino;
126 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
127 inode->i_nlink = attr->nlink;
128 inode->i_uid = attr->uid;
129 inode->i_gid = attr->gid;
130 i_size_write(inode, attr->size);
131 inode->i_blksize = PAGE_CACHE_SIZE;
132 inode->i_blocks = attr->blocks;
133#ifdef KERNEL_2_6
134 inode->i_atime.tv_sec = attr->atime;
135 inode->i_atime.tv_nsec = attr->atimensec;
136 inode->i_mtime.tv_sec = attr->mtime;
137 inode->i_mtime.tv_nsec = attr->mtimensec;
138 inode->i_ctime.tv_sec = attr->ctime;
139 inode->i_ctime.tv_nsec = attr->ctimensec;
140#else
141 inode->i_atime = attr->atime;
142 inode->i_mtime = attr->mtime;
143 inode->i_ctime = attr->ctime;
144#endif
145}
146
147static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
148{
149 inode->i_mode = attr->mode & S_IFMT;
150 i_size_write(inode, attr->size);
151 if (S_ISREG(inode->i_mode)) {
152 fuse_init_common(inode);
153 fuse_init_file_inode(inode);
154 } else if (S_ISDIR(inode->i_mode))
155 fuse_init_dir(inode);
156 else if (S_ISLNK(inode->i_mode))
157 fuse_init_symlink(inode);
158 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
159 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
160 fuse_init_common(inode);
161 init_special_inode(inode, inode->i_mode,
162 new_decode_dev(attr->rdev));
Miklos Szeredi64709572005-12-14 22:16:28 +0000163 } else
164 BUG();
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000165}
166
167#ifdef KERNEL_2_6
168static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
169{
170 unsigned long nodeid = *(unsigned long *) _nodeidp;
171 if (get_node_id(inode) == nodeid)
172 return 1;
173 else
174 return 0;
175}
176
177static int fuse_inode_set(struct inode *inode, void *_nodeidp)
178{
179 unsigned long nodeid = *(unsigned long *) _nodeidp;
180 get_fuse_inode(inode)->nodeid = nodeid;
181 return 0;
182}
183
184struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
Miklos Szeredi38009022005-05-08 19:47:22 +0000185 int generation, struct fuse_attr *attr)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000186{
187 struct inode *inode;
Miklos Szeredi38009022005-05-08 19:47:22 +0000188 struct fuse_inode *fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000189 struct fuse_conn *fc = get_fuse_conn_super(sb);
190 int retried = 0;
191
192 retry:
193 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
194 if (!inode)
195 return NULL;
196
197 if ((inode->i_state & I_NEW)) {
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +0000198#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000199 inode->i_flags |= S_NOATIME|S_NOCMTIME;
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +0000200#else
201 inode->i_flags |= S_NOATIME;
202#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000203 inode->i_generation = generation;
204 inode->i_data.backing_dev_info = &fc->bdi;
205 fuse_init_inode(inode, attr);
206 unlock_new_inode(inode);
207 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
208 BUG_ON(retried);
209 /* Inode has changed type, any I/O on the old should fail */
210 make_bad_inode(inode);
211 iput(inode);
212 retried = 1;
213 goto retry;
214 }
215
Miklos Szeredi38009022005-05-08 19:47:22 +0000216 fi = get_fuse_inode(inode);
217 fi->nlookup ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000218 fuse_change_attributes(inode, attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000219 return inode;
220}
221#else
222static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
223 unsigned long nodeid = *(unsigned long *) _nodeidp;
224 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
225 return 1;
226 else
227 return 0;
228}
229
230struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
Miklos Szeredi38009022005-05-08 19:47:22 +0000231 int generation, struct fuse_attr *attr)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000232{
233 struct inode *inode;
Miklos Szeredi38009022005-05-08 19:47:22 +0000234 struct fuse_inode *fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000235 int retried = 0;
236
237 retry:
238 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
239 if (!inode)
240 return NULL;
241
242 if (!inode->u.generic_ip) {
243 get_fuse_inode(inode)->nodeid = nodeid;
244 inode->u.generic_ip = inode;
245 inode->i_generation = generation;
246 fuse_init_inode(inode, attr);
247 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
248 BUG_ON(retried);
249 /* Inode has changed type, any I/O on the old should fail */
250 remove_inode_hash(inode);
251 make_bad_inode(inode);
252 iput(inode);
253 retried = 1;
254 goto retry;
255 }
256
Miklos Szeredi38009022005-05-08 19:47:22 +0000257 fi = get_fuse_inode(inode);
258 fi->nlookup ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000259 fuse_change_attributes(inode, attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000260 return inode;
261}
262#endif
263
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000264static void fuse_put_super(struct super_block *sb)
265{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000266 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000267
Miklos Szeredid17da462005-03-21 11:47:04 +0000268 down_write(&fc->sbput_sem);
269 while (!list_empty(&fc->background))
270 fuse_release_background(list_entry(fc->background.next,
271 struct fuse_req, bg_entry));
272
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000273 spin_lock(&fuse_lock);
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000274 fc->mounted = 0;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000275 fc->user_id = 0;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000276 fc->group_id = 0;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000277 fc->flags = 0;
Miklos Szeredi96249982001-11-21 12:21:19 +0000278 /* Flush all readers on this fs */
279 wake_up_all(&fc->waitq);
Miklos Szeredid17da462005-03-21 11:47:04 +0000280 up_write(&fc->sbput_sem);
Miklos Szeredi79b461a2003-03-10 09:35:34 +0000281 fuse_release_conn(fc);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000282 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000283}
284
Miklos Szeredif85ab242004-01-07 12:16:45 +0000285static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000286{
287 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000288 stbuf->f_bsize = attr->bsize;
Miklos Szeredibb4b9742005-11-29 11:29:44 +0000289#ifdef KERNEL_2_6
Miklos Szeredi2b478112005-11-28 13:27:10 +0000290 stbuf->f_frsize = attr->frsize;
Miklos Szeredibb4b9742005-11-29 11:29:44 +0000291#endif
Mark Glinesd84b39a2002-01-07 16:32:02 +0000292 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000293 stbuf->f_bfree = attr->bfree;
294 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000295 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000296 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000297 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000298 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000299}
300
Miklos Szeredif85ab242004-01-07 12:16:45 +0000301static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000302{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000303 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000304 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000305 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 int err;
307
308 req = fuse_get_request(fc);
309 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000310 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000311
Miklos Szeredi2b478112005-11-28 13:27:10 +0000312 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 req->in.numargs = 0;
314 req->in.h.opcode = FUSE_STATFS;
315 req->out.numargs = 1;
Miklos Szerediead7f102005-11-28 16:02:27 +0000316 req->out.args[0].size =
Miklos Szeredi2b478112005-11-28 13:27:10 +0000317 fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000318 req->out.args[0].value = &outarg;
319 request_send(fc, req);
320 err = req->out.h.error;
321 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000322 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000323 fuse_put_request(fc, req);
324 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000325}
326
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000327enum {
328 OPT_FD,
329 OPT_ROOTMODE,
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000330 OPT_USER_ID,
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000331 OPT_GROUP_ID,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000332 OPT_DEFAULT_PERMISSIONS,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000333 OPT_ALLOW_OTHER,
Miklos Szeredie56818b2004-12-12 11:45:24 +0000334#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000335 OPT_LARGE_READ,
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000336#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000337 OPT_MAX_READ,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000338 OPT_ERR
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000339};
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000340
341static match_table_t tokens = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000342 {OPT_FD, "fd=%u"},
343 {OPT_ROOTMODE, "rootmode=%o"},
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000344 {OPT_USER_ID, "user_id=%u"},
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000345 {OPT_GROUP_ID, "group_id=%u"},
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000346 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
347 {OPT_ALLOW_OTHER, "allow_other"},
Miklos Szeredie56818b2004-12-12 11:45:24 +0000348#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000349 {OPT_LARGE_READ, "large_read"},
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000350#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000351 {OPT_MAX_READ, "max_read=%u"},
352 {OPT_ERR, NULL}
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000353};
354
355static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
356{
357 char *p;
358 memset(d, 0, sizeof(struct fuse_mount_data));
Miklos Szerediad051c32004-07-02 09:22:50 +0000359 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000360
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000361 while ((p = strsep(&opt, ",")) != NULL) {
362 int token;
363 int value;
364 substring_t args[MAX_OPT_ARGS];
365 if (!*p)
366 continue;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000367
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000368 token = match_token(p, tokens, args);
369 switch (token) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000370 case OPT_FD:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000371 if (match_int(&args[0], &value))
372 return 0;
373 d->fd = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000374 d->fd_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000375 break;
376
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000377 case OPT_ROOTMODE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000378 if (match_octal(&args[0], &value))
379 return 0;
380 d->rootmode = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000381 d->rootmode_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000382 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000383
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000384 case OPT_USER_ID:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000385 if (match_int(&args[0], &value))
386 return 0;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000387 d->user_id = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000388 d->user_id_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000389 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000390
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000391 case OPT_GROUP_ID:
392 if (match_int(&args[0], &value))
393 return 0;
394 d->group_id = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000395 d->group_id_present = 1;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000396 break;
397
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000398 case OPT_DEFAULT_PERMISSIONS:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000399 d->flags |= FUSE_DEFAULT_PERMISSIONS;
400 break;
401
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000402 case OPT_ALLOW_OTHER:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000403 d->flags |= FUSE_ALLOW_OTHER;
404 break;
405
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000406#ifndef KERNEL_2_6
Miklos Szeredie56818b2004-12-12 11:45:24 +0000407 case OPT_LARGE_READ:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000408 d->flags |= FUSE_LARGE_READ;
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000409 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000410#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000411 case OPT_MAX_READ:
Miklos Szerediad051c32004-07-02 09:22:50 +0000412 if (match_int(&args[0], &value))
413 return 0;
414 d->max_read = value;
415 break;
416
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000417 default:
418 return 0;
419 }
420 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000421
Miklos Szeredi437d8112005-07-06 09:14:20 +0000422 if (!d->fd_present || !d->rootmode_present ||
423 !d->user_id_present || !d->group_id_present)
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000424 return 0;
425
426 return 1;
427}
428
429static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
430{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000431 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000432
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000433 seq_printf(m, ",user_id=%u", fc->user_id);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000434 seq_printf(m, ",group_id=%u", fc->group_id);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000435 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
436 seq_puts(m, ",default_permissions");
437 if (fc->flags & FUSE_ALLOW_OTHER)
438 seq_puts(m, ",allow_other");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000439#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000440 if (fc->flags & FUSE_LARGE_READ)
441 seq_puts(m, ",large_read");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000442#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000443 if (fc->max_read != ~0)
444 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000445 return 0;
446}
447
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000448static void free_conn(struct fuse_conn *fc)
449{
450 while (!list_empty(&fc->unused_list)) {
451 struct fuse_req *req;
452 req = list_entry(fc->unused_list.next, struct fuse_req, list);
453 list_del(&req->list);
454 fuse_request_free(req);
455 }
456 kfree(fc);
457}
458
459/* Must be called with the fuse lock held */
460void fuse_release_conn(struct fuse_conn *fc)
461{
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000462 fc->count--;
463 if (!fc->count)
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000464 free_conn(fc);
465}
466
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000467static struct fuse_conn *new_conn(void)
468{
469 struct fuse_conn *fc;
470
471 fc = kmalloc(sizeof(*fc), GFP_KERNEL);
472 if (fc != NULL) {
473 int i;
474 memset(fc, 0, sizeof(*fc));
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000475 init_waitqueue_head(&fc->waitq);
476 INIT_LIST_HEAD(&fc->pending);
477 INIT_LIST_HEAD(&fc->processing);
478 INIT_LIST_HEAD(&fc->unused_list);
Miklos Szeredid17da462005-03-21 11:47:04 +0000479 INIT_LIST_HEAD(&fc->background);
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000480 sema_init(&fc->outstanding_sem, 0);
Miklos Szeredid17da462005-03-21 11:47:04 +0000481 init_rwsem(&fc->sbput_sem);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000482 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
483 struct fuse_req *req = fuse_request_alloc();
484 if (!req) {
485 free_conn(fc);
486 return NULL;
487 }
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000488 list_add(&req->list, &fc->unused_list);
489 }
Miklos Szeredib6220192005-01-05 16:19:10 +0000490#ifdef KERNEL_2_6_6_PLUS
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000491 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
492 fc->bdi.unplug_io_fn = default_unplug_io_fn;
493#endif
Miklos Szeredie3b83092005-07-22 17:24:30 +0000494 fc->reqctr = 0;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000495 }
496 return fc;
497}
498
Miklos Szeredied62d862004-06-20 08:57:39 +0000499static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000500{
Miklos Szeredied62d862004-06-20 08:57:39 +0000501 struct fuse_conn *fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000502
Miklos Szeredie56818b2004-12-12 11:45:24 +0000503 if (file->f_op != &fuse_dev_operations)
Miklos Szerediee808382005-01-21 22:05:37 +0000504 return ERR_PTR(-EINVAL);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000505 fc = new_conn();
Miklos Szeredie56818b2004-12-12 11:45:24 +0000506 if (fc == NULL)
Miklos Szerediee808382005-01-21 22:05:37 +0000507 return ERR_PTR(-ENOMEM);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000508 spin_lock(&fuse_lock);
509 if (file->private_data) {
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000510 free_conn(fc);
Miklos Szerediee808382005-01-21 22:05:37 +0000511 fc = ERR_PTR(-EINVAL);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000512 } else {
513 file->private_data = fc;
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000514 *get_fuse_conn_super_p(sb) = fc;
515 fc->mounted = 1;
516 fc->connected = 1;
517 fc->count = 2;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000518 }
519 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000520 return fc;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000521}
522
Miklos Szeredi83a07442004-11-30 18:25:20 +0000523static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000524{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000525 struct fuse_attr attr;
526 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000527
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000528 attr.mode = mode;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000529 attr.ino = FUSE_ROOT_ID;
Miklos Szeredi38009022005-05-08 19:47:22 +0000530 return fuse_iget(sb, 1, 0, &attr);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000531}
Miklos Szeredi1b188022005-07-28 11:07:29 +0000532#ifndef FUSE_MAINLINE
Miklos Szeredie815c032004-01-19 18:20:49 +0000533#ifdef KERNEL_2_6
Miklos Szeredie815c032004-01-19 18:20:49 +0000534static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
535{
536 __u32 *objp = vobjp;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000537 unsigned long nodeid = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000538 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000539 struct inode *inode;
540 struct dentry *entry;
541
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000542 if (nodeid == 0)
Miklos Szeredia5288792005-03-05 16:46:52 +0000543 return ERR_PTR(-ESTALE);
Miklos Szeredie815c032004-01-19 18:20:49 +0000544
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000545 inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredif43f0632005-02-28 11:46:56 +0000546 if (!inode)
Miklos Szeredia5288792005-03-05 16:46:52 +0000547 return ERR_PTR(-ESTALE);
548 if (inode->i_generation != generation) {
549 iput(inode);
550 return ERR_PTR(-ESTALE);
551 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000552
553 entry = d_alloc_anon(inode);
Miklos Szeredia5288792005-03-05 16:46:52 +0000554 if (!entry) {
555 iput(inode);
556 return ERR_PTR(-ENOMEM);
557 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000558
559 return entry;
560}
561
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000562static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
563 int connectable)
564{
565 struct inode *inode = dentry->d_inode;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000566 int len = *max_len;
567 int type = 1;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000568
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000569 if (len < 2 || (connectable && len < 4))
570 return 255;
571
572 len = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000573 fh[0] = get_fuse_inode(inode)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000574 fh[1] = inode->i_generation;
575 if (connectable && !S_ISDIR(inode->i_mode)) {
576 struct inode *parent;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000577
578 spin_lock(&dentry->d_lock);
579 parent = dentry->d_parent->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000580 fh[2] = get_fuse_inode(parent)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000581 fh[3] = parent->i_generation;
582 spin_unlock(&dentry->d_lock);
583 len = 4;
584 type = 2;
585 }
586 *max_len = len;
587 return type;
588}
589
Miklos Szeredie815c032004-01-19 18:20:49 +0000590static struct export_operations fuse_export_operations = {
591 .get_dentry = fuse_get_dentry,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000592 .encode_fh = fuse_encode_fh,
Miklos Szeredie815c032004-01-19 18:20:49 +0000593};
594#endif
Miklos Szeredi1b188022005-07-28 11:07:29 +0000595#endif
Miklos Szeredie815c032004-01-19 18:20:49 +0000596
597static struct super_operations fuse_super_operations = {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000598 .alloc_inode = fuse_alloc_inode,
599 .destroy_inode = fuse_destroy_inode,
Miklos Szeredie815c032004-01-19 18:20:49 +0000600 .read_inode = fuse_read_inode,
601 .clear_inode = fuse_clear_inode,
602 .put_super = fuse_put_super,
603 .statfs = fuse_statfs,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000604 .show_options = fuse_show_options,
Miklos Szeredie815c032004-01-19 18:20:49 +0000605};
606
Miklos Szeredi81394522005-01-11 14:24:18 +0000607static int fuse_fill_super(struct super_block *sb, void *data, int silent)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000608{
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000609 struct fuse_conn *fc;
610 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000611 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000612 struct file *file;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000613 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000614
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000615 if (!parse_fuse_opt((char *) data, &d))
616 return -EINVAL;
617
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000618 sb->s_blocksize = PAGE_CACHE_SIZE;
619 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
620 sb->s_magic = FUSE_SUPER_MAGIC;
621 sb->s_op = &fuse_super_operations;
622 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000623#ifndef FUSE_MAINLINE
Miklos Szeredie815c032004-01-19 18:20:49 +0000624#ifdef KERNEL_2_6
625 sb->s_export_op = &fuse_export_operations;
626#endif
Miklos Szeredi1b188022005-07-28 11:07:29 +0000627#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000628
Miklos Szeredied62d862004-06-20 08:57:39 +0000629 file = fget(d.fd);
630 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000631 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000632
Miklos Szeredied62d862004-06-20 08:57:39 +0000633 fc = get_conn(file, sb);
Miklos Szeredied62d862004-06-20 08:57:39 +0000634 fput(file);
Miklos Szerediee808382005-01-21 22:05:37 +0000635 if (IS_ERR(fc))
636 return PTR_ERR(fc);
Miklos Szeredied62d862004-06-20 08:57:39 +0000637
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000638 fc->flags = d.flags;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000639 fc->user_id = d.user_id;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000640 fc->group_id = d.group_id;
Miklos Szerediad051c32004-07-02 09:22:50 +0000641 fc->max_read = d.max_read;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000642#ifdef KERNEL_2_6
643 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
644 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
645#endif
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000646
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000647 err = -ENOMEM;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000648 root = get_root_inode(sb, d.rootmode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000649 if (root == NULL)
Miklos Szeredied62d862004-06-20 08:57:39 +0000650 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000651
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000652 sb->s_root = d_alloc_root(root);
Miklos Szeredied62d862004-06-20 08:57:39 +0000653 if (!sb->s_root) {
654 iput(root);
655 goto err;
656 }
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000657 fuse_send_init(fc);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000658 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000659
660 err:
661 spin_lock(&fuse_lock);
Miklos Szeredied62d862004-06-20 08:57:39 +0000662 fuse_release_conn(fc);
663 spin_unlock(&fuse_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000664 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000665}
666
Miklos Szeredif85ab242004-01-07 12:16:45 +0000667#ifdef KERNEL_2_6
668static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000669 int flags, const char *dev_name,
670 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000671{
Miklos Szeredi81394522005-01-11 14:24:18 +0000672 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000673}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000674
Miklos Szeredif85ab242004-01-07 12:16:45 +0000675static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000676 .owner = THIS_MODULE,
677 .name = "fuse",
678 .get_sb = fuse_get_sb,
679 .kill_sb = kill_anon_super,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000680};
681#else
682static struct super_block *fuse_read_super_compat(struct super_block *sb,
683 void *data, int silent)
684{
Miklos Szeredi81394522005-01-11 14:24:18 +0000685 int err = fuse_fill_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000686 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000687 return NULL;
688 else
689 return sb;
690}
691
692static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
693#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000694
Miklos Szeredi81394522005-01-11 14:24:18 +0000695static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
Miklos Szeredia13d9002004-11-02 17:32:03 +0000696 unsigned long flags)
697{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000698 struct inode * inode = foo;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000699
700 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
701 SLAB_CTOR_CONSTRUCTOR)
702 inode_init_once(inode);
703}
704
Miklos Szeredi9080c792005-01-08 11:50:08 +0000705static int __init fuse_fs_init(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000706{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000707 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000708
Miklos Szeredi069c9502004-07-16 16:17:02 +0000709 err = register_filesystem(&fuse_fs_type);
710 if (err)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000711 printk("fuse: failed to register filesystem\n");
Miklos Szeredi069c9502004-07-16 16:17:02 +0000712 else {
713 fuse_inode_cachep = kmem_cache_create("fuse_inode",
Miklos Szeredi81394522005-01-11 14:24:18 +0000714 sizeof(struct fuse_inode),
Miklos Szeredia13d9002004-11-02 17:32:03 +0000715 0, SLAB_HWCACHE_ALIGN,
716 fuse_inode_init_once, NULL);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000717 if (!fuse_inode_cachep) {
718 unregister_filesystem(&fuse_fs_type);
719 err = -ENOMEM;
720 }
721 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000722
Miklos Szeredi069c9502004-07-16 16:17:02 +0000723 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000724}
725
Miklos Szeredi9080c792005-01-08 11:50:08 +0000726static void fuse_fs_cleanup(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000727{
728 unregister_filesystem(&fuse_fs_type);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000729 kmem_cache_destroy(fuse_inode_cachep);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000730}
Miklos Szeredi9080c792005-01-08 11:50:08 +0000731
Miklos Szeredi81394522005-01-11 14:24:18 +0000732static int __init fuse_init(void)
Miklos Szeredi9080c792005-01-08 11:50:08 +0000733{
734 int res;
735
736 printk("fuse init (API version %i.%i)\n",
737 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
738#ifndef FUSE_MAINLINE
739 printk("fuse distribution version: %s\n", FUSE_VERSION);
740#endif
741
742 spin_lock_init(&fuse_lock);
743 res = fuse_fs_init();
744 if (res)
745 goto err;
746
747 res = fuse_dev_init();
748 if (res)
749 goto err_fs_cleanup;
750
751 return 0;
752
753 err_fs_cleanup:
754 fuse_fs_cleanup();
755 err:
756 return res;
757}
758
Miklos Szeredi81394522005-01-11 14:24:18 +0000759static void __exit fuse_exit(void)
Miklos Szeredi9080c792005-01-08 11:50:08 +0000760{
761 printk(KERN_DEBUG "fuse exit\n");
762
763 fuse_fs_cleanup();
764 fuse_dev_cleanup();
765}
766
767module_init(fuse_init);
768module_exit(fuse_exit);