blob: 572951d40b5a50eef6392ce715b9337264f8036d [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 Szeredi15af1b82006-01-16 17:52:24 +000033#ifdef KERNEL_2_6
34static struct subsystem connections_subsys;
35
36struct fuse_conn_attr {
37 struct attribute attr;
38 ssize_t (*show)(struct fuse_conn *, char *);
39 ssize_t (*store)(struct fuse_conn *, const char *, size_t);
40};
41#endif
Miklos Szerediacb4d362004-07-02 16:20:45 +000042
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000043#define FUSE_SUPER_MAGIC 0x65735546
44
Miklos Szeredif85ab242004-01-07 12:16:45 +000045#ifndef KERNEL_2_6
46#define kstatfs statfs
47#endif
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000048#ifndef MAX_LFS_FILESIZE
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000049#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
Miklos Szeredib1ab8b52004-11-01 10:57:41 +000050#endif
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000051struct fuse_mount_data {
52 int fd;
Miklos Szeredi83a07442004-11-30 18:25:20 +000053 unsigned rootmode;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +000054 unsigned user_id;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +000055 unsigned group_id;
Miklos Szeredi437d8112005-07-06 09:14:20 +000056 unsigned fd_present : 1;
57 unsigned rootmode_present : 1;
58 unsigned user_id_present : 1;
59 unsigned group_id_present : 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +000060 unsigned flags;
61 unsigned max_read;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +000062};
Miklos Szeredi69cc79a2004-02-17 08:57:29 +000063
Miklos Szeredia13d9002004-11-02 17:32:03 +000064static struct inode *fuse_alloc_inode(struct super_block *sb)
Miklos Szeredi069c9502004-07-16 16:17:02 +000065{
Miklos Szeredia13d9002004-11-02 17:32:03 +000066 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000067 struct fuse_inode *fi;
68
Miklos Szeredia13d9002004-11-02 17:32:03 +000069 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
70 if (!inode)
71 return NULL;
Miklos Szeredi069c9502004-07-16 16:17:02 +000072
Miklos Szeredia13d9002004-11-02 17:32:03 +000073#ifndef KERNEL_2_6
74 inode->u.generic_ip = NULL;
75#endif
Miklos Szeredi039322d2004-12-01 18:39:12 +000076 fi = get_fuse_inode(inode);
Miklos Szeredi81394522005-01-11 14:24:18 +000077 fi->i_time = jiffies - 1;
78 fi->nodeid = 0;
Miklos Szeredi38009022005-05-08 19:47:22 +000079 fi->nlookup = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +000080 fi->forget_req = fuse_request_alloc();
81 if (!fi->forget_req) {
82 kmem_cache_free(fuse_inode_cachep, inode);
83 return NULL;
84 }
Miklos Szeredia13d9002004-11-02 17:32:03 +000085
86 return inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +000087}
88
Miklos Szeredia13d9002004-11-02 17:32:03 +000089static void fuse_destroy_inode(struct inode *inode)
Miklos Szeredi069c9502004-07-16 16:17:02 +000090{
Miklos Szeredi039322d2004-12-01 18:39:12 +000091 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000092 if (fi->forget_req)
93 fuse_request_free(fi->forget_req);
Miklos Szeredia13d9002004-11-02 17:32:03 +000094 kmem_cache_free(fuse_inode_cachep, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +000095}
96
Miklos Szeredibc22e7b2001-10-23 19:26:04 +000097static void fuse_read_inode(struct inode *inode)
98{
Miklos Szeredi90d8bef2001-10-26 14:55:42 +000099 /* No op */
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000100}
101
Miklos Szeredia13d9002004-11-02 17:32:03 +0000102void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi38009022005-05-08 19:47:22 +0000103 unsigned long nodeid, u64 nlookup)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000104{
105 struct fuse_forget_in *inarg = &req->misc.forget_in;
Miklos Szeredi38009022005-05-08 19:47:22 +0000106 inarg->nlookup = nlookup;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000107 req->in.h.opcode = FUSE_FORGET;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000108 req->in.h.nodeid = nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000109 req->in.numargs = 1;
110 req->in.args[0].size = sizeof(struct fuse_forget_in);
111 req->in.args[0].value = inarg;
112 request_send_noreply(fc, req);
113}
114
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000115static void fuse_clear_inode(struct inode *inode)
116{
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000117 if (inode->i_sb->s_flags & MS_ACTIVE) {
118 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000119 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi38009022005-05-08 19:47:22 +0000120 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000121 fi->forget_req = NULL;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000122 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000123}
124
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000125void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
126{
127 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
128#ifdef KERNEL_2_6
129 invalidate_inode_pages(inode->i_mapping);
130#else
131 invalidate_inode_pages(inode);
132#endif
133
134 inode->i_ino = attr->ino;
135 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
136 inode->i_nlink = attr->nlink;
137 inode->i_uid = attr->uid;
138 inode->i_gid = attr->gid;
139 i_size_write(inode, attr->size);
140 inode->i_blksize = PAGE_CACHE_SIZE;
141 inode->i_blocks = attr->blocks;
142#ifdef KERNEL_2_6
143 inode->i_atime.tv_sec = attr->atime;
144 inode->i_atime.tv_nsec = attr->atimensec;
145 inode->i_mtime.tv_sec = attr->mtime;
146 inode->i_mtime.tv_nsec = attr->mtimensec;
147 inode->i_ctime.tv_sec = attr->ctime;
148 inode->i_ctime.tv_nsec = attr->ctimensec;
149#else
150 inode->i_atime = attr->atime;
151 inode->i_mtime = attr->mtime;
152 inode->i_ctime = attr->ctime;
153#endif
154}
155
156static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
157{
158 inode->i_mode = attr->mode & S_IFMT;
159 i_size_write(inode, attr->size);
160 if (S_ISREG(inode->i_mode)) {
161 fuse_init_common(inode);
162 fuse_init_file_inode(inode);
163 } else if (S_ISDIR(inode->i_mode))
164 fuse_init_dir(inode);
165 else if (S_ISLNK(inode->i_mode))
166 fuse_init_symlink(inode);
167 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
168 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
169 fuse_init_common(inode);
170 init_special_inode(inode, inode->i_mode,
171 new_decode_dev(attr->rdev));
Miklos Szeredi64709572005-12-14 22:16:28 +0000172 } else
173 BUG();
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000174}
175
176#ifdef KERNEL_2_6
177static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
178{
179 unsigned long nodeid = *(unsigned long *) _nodeidp;
180 if (get_node_id(inode) == nodeid)
181 return 1;
182 else
183 return 0;
184}
185
186static int fuse_inode_set(struct inode *inode, void *_nodeidp)
187{
188 unsigned long nodeid = *(unsigned long *) _nodeidp;
189 get_fuse_inode(inode)->nodeid = nodeid;
190 return 0;
191}
192
193struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
Miklos Szeredi38009022005-05-08 19:47:22 +0000194 int generation, struct fuse_attr *attr)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000195{
196 struct inode *inode;
Miklos Szeredi38009022005-05-08 19:47:22 +0000197 struct fuse_inode *fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000198 struct fuse_conn *fc = get_fuse_conn_super(sb);
199 int retried = 0;
200
201 retry:
202 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
203 if (!inode)
204 return NULL;
205
206 if ((inode->i_state & I_NEW)) {
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +0000207#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000208 inode->i_flags |= S_NOATIME|S_NOCMTIME;
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +0000209#else
210 inode->i_flags |= S_NOATIME;
211#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000212 inode->i_generation = generation;
213 inode->i_data.backing_dev_info = &fc->bdi;
214 fuse_init_inode(inode, attr);
215 unlock_new_inode(inode);
216 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
217 BUG_ON(retried);
218 /* Inode has changed type, any I/O on the old should fail */
219 make_bad_inode(inode);
220 iput(inode);
221 retried = 1;
222 goto retry;
223 }
224
Miklos Szeredi38009022005-05-08 19:47:22 +0000225 fi = get_fuse_inode(inode);
226 fi->nlookup ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000227 fuse_change_attributes(inode, attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000228 return inode;
229}
230#else
231static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
232 unsigned long nodeid = *(unsigned long *) _nodeidp;
233 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
234 return 1;
235 else
236 return 0;
237}
238
239struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
Miklos Szeredi38009022005-05-08 19:47:22 +0000240 int generation, struct fuse_attr *attr)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000241{
242 struct inode *inode;
Miklos Szeredi38009022005-05-08 19:47:22 +0000243 struct fuse_inode *fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000244 int retried = 0;
245
246 retry:
247 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
248 if (!inode)
249 return NULL;
250
251 if (!inode->u.generic_ip) {
252 get_fuse_inode(inode)->nodeid = nodeid;
253 inode->u.generic_ip = inode;
254 inode->i_generation = generation;
255 fuse_init_inode(inode, attr);
256 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
257 BUG_ON(retried);
258 /* Inode has changed type, any I/O on the old should fail */
259 remove_inode_hash(inode);
260 make_bad_inode(inode);
261 iput(inode);
262 retried = 1;
263 goto retry;
264 }
265
Miklos Szeredi38009022005-05-08 19:47:22 +0000266 fi = get_fuse_inode(inode);
267 fi->nlookup ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000268 fuse_change_attributes(inode, attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000269 return inode;
270}
271#endif
272
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000273static void fuse_umount_begin(struct super_block *sb)
274{
275 fuse_abort_conn(get_fuse_conn_super(sb));
276}
277
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000278static void fuse_put_super(struct super_block *sb)
279{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000280 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000281
Miklos Szeredid17da462005-03-21 11:47:04 +0000282 down_write(&fc->sbput_sem);
283 while (!list_empty(&fc->background))
284 fuse_release_background(list_entry(fc->background.next,
285 struct fuse_req, bg_entry));
286
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000287 spin_lock(&fuse_lock);
Miklos Szeredi0111f9d2005-04-22 12:04:55 +0000288 fc->mounted = 0;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000289 fc->connected = 0;
290 spin_unlock(&fuse_lock);
291 up_write(&fc->sbput_sem);
Miklos Szeredi96249982001-11-21 12:21:19 +0000292 /* Flush all readers on this fs */
293 wake_up_all(&fc->waitq);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000294#ifdef KERNEL_2_6
295 kobject_del(&fc->kobj);
296#endif
297 kobject_put(&fc->kobj);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000298}
299
Miklos Szeredif85ab242004-01-07 12:16:45 +0000300static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000301{
302 stbuf->f_type = FUSE_SUPER_MAGIC;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000303 stbuf->f_bsize = attr->bsize;
Miklos Szeredibb4b9742005-11-29 11:29:44 +0000304#ifdef KERNEL_2_6
Miklos Szeredi2b478112005-11-28 13:27:10 +0000305 stbuf->f_frsize = attr->frsize;
Miklos Szeredibb4b9742005-11-29 11:29:44 +0000306#endif
Mark Glinesd84b39a2002-01-07 16:32:02 +0000307 stbuf->f_blocks = attr->blocks;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000308 stbuf->f_bfree = attr->bfree;
309 stbuf->f_bavail = attr->bavail;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000310 stbuf->f_files = attr->files;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000311 stbuf->f_ffree = attr->ffree;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000312 stbuf->f_namelen = attr->namelen;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000313 /* fsid is left zero */
Mark Glinesd84b39a2002-01-07 16:32:02 +0000314}
315
Miklos Szeredif85ab242004-01-07 12:16:45 +0000316static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
Mark Glinesd84b39a2002-01-07 16:32:02 +0000317{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000318 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000319 struct fuse_req *req;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000320 struct fuse_statfs_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000321 int err;
322
323 req = fuse_get_request(fc);
324 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000325 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000326
Miklos Szeredi2b478112005-11-28 13:27:10 +0000327 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000328 req->in.numargs = 0;
329 req->in.h.opcode = FUSE_STATFS;
330 req->out.numargs = 1;
Miklos Szerediead7f102005-11-28 16:02:27 +0000331 req->out.args[0].size =
Miklos Szeredi2b478112005-11-28 13:27:10 +0000332 fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 req->out.args[0].value = &outarg;
334 request_send(fc, req);
335 err = req->out.h.error;
336 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000337 convert_fuse_statfs(buf, &outarg.st);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000338 fuse_put_request(fc, req);
339 return err;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000340}
341
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000342enum {
343 OPT_FD,
344 OPT_ROOTMODE,
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000345 OPT_USER_ID,
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000346 OPT_GROUP_ID,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000347 OPT_DEFAULT_PERMISSIONS,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000348 OPT_ALLOW_OTHER,
Miklos Szeredie56818b2004-12-12 11:45:24 +0000349#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000350 OPT_LARGE_READ,
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000351#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000352 OPT_MAX_READ,
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000353 OPT_ERR
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000354};
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000355
356static match_table_t tokens = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000357 {OPT_FD, "fd=%u"},
358 {OPT_ROOTMODE, "rootmode=%o"},
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000359 {OPT_USER_ID, "user_id=%u"},
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000360 {OPT_GROUP_ID, "group_id=%u"},
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000361 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
362 {OPT_ALLOW_OTHER, "allow_other"},
Miklos Szeredie56818b2004-12-12 11:45:24 +0000363#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000364 {OPT_LARGE_READ, "large_read"},
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000365#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000366 {OPT_MAX_READ, "max_read=%u"},
367 {OPT_ERR, NULL}
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000368};
369
370static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
371{
372 char *p;
373 memset(d, 0, sizeof(struct fuse_mount_data));
Miklos Szerediad051c32004-07-02 09:22:50 +0000374 d->max_read = ~0;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000375
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000376 while ((p = strsep(&opt, ",")) != NULL) {
377 int token;
378 int value;
379 substring_t args[MAX_OPT_ARGS];
380 if (!*p)
381 continue;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000382
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000383 token = match_token(p, tokens, args);
384 switch (token) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000385 case OPT_FD:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000386 if (match_int(&args[0], &value))
387 return 0;
388 d->fd = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000389 d->fd_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000390 break;
391
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000392 case OPT_ROOTMODE:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000393 if (match_octal(&args[0], &value))
394 return 0;
395 d->rootmode = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000396 d->rootmode_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000397 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000398
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000399 case OPT_USER_ID:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000400 if (match_int(&args[0], &value))
401 return 0;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000402 d->user_id = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000403 d->user_id_present = 1;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000404 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000405
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000406 case OPT_GROUP_ID:
407 if (match_int(&args[0], &value))
408 return 0;
409 d->group_id = value;
Miklos Szeredi437d8112005-07-06 09:14:20 +0000410 d->group_id_present = 1;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000411 break;
412
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000413 case OPT_DEFAULT_PERMISSIONS:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000414 d->flags |= FUSE_DEFAULT_PERMISSIONS;
415 break;
416
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000417 case OPT_ALLOW_OTHER:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000418 d->flags |= FUSE_ALLOW_OTHER;
419 break;
420
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000421#ifndef KERNEL_2_6
Miklos Szeredie56818b2004-12-12 11:45:24 +0000422 case OPT_LARGE_READ:
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000423 d->flags |= FUSE_LARGE_READ;
Miklos Szeredi1bf53ee2004-09-13 11:47:59 +0000424 break;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000425#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000426 case OPT_MAX_READ:
Miklos Szerediad051c32004-07-02 09:22:50 +0000427 if (match_int(&args[0], &value))
428 return 0;
429 d->max_read = value;
430 break;
431
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000432 default:
433 return 0;
434 }
435 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000436
Miklos Szeredi437d8112005-07-06 09:14:20 +0000437 if (!d->fd_present || !d->rootmode_present ||
438 !d->user_id_present || !d->group_id_present)
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000439 return 0;
440
441 return 1;
442}
443
444static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
445{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000446 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000447
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000448 seq_printf(m, ",user_id=%u", fc->user_id);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000449 seq_printf(m, ",group_id=%u", fc->group_id);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000450 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
451 seq_puts(m, ",default_permissions");
452 if (fc->flags & FUSE_ALLOW_OTHER)
453 seq_puts(m, ",allow_other");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000454#ifndef KERNEL_2_6
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000455 if (fc->flags & FUSE_LARGE_READ)
456 seq_puts(m, ",large_read");
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000457#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000458 if (fc->max_read != ~0)
459 seq_printf(m, ",max_read=%u", fc->max_read);
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000460 return 0;
461}
462
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000463static void fuse_conn_release(struct kobject *kobj)
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000464{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000465 struct fuse_conn *fc = get_fuse_conn_kobj(kobj);
466
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000467 while (!list_empty(&fc->unused_list)) {
468 struct fuse_req *req;
469 req = list_entry(fc->unused_list.next, struct fuse_req, list);
470 list_del(&req->list);
471 fuse_request_free(req);
472 }
473 kfree(fc);
474}
475
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000476#ifndef HAVE_KZALLOC
477static void *kzalloc(size_t size, int flags)
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000478{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000479 void *ret = kmalloc(size, flags);
480 if (ret)
481 memset(ret, 0, size);
482 return ret;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000483}
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000484#endif
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000485static struct fuse_conn *new_conn(void)
486{
487 struct fuse_conn *fc;
488
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000489 fc = kzalloc(sizeof(*fc), GFP_KERNEL);
490 if (fc) {
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000491 int i;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000492 init_waitqueue_head(&fc->waitq);
493 INIT_LIST_HEAD(&fc->pending);
494 INIT_LIST_HEAD(&fc->processing);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000495 INIT_LIST_HEAD(&fc->io);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000496 INIT_LIST_HEAD(&fc->unused_list);
Miklos Szeredid17da462005-03-21 11:47:04 +0000497 INIT_LIST_HEAD(&fc->background);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000498 sema_init(&fc->outstanding_sem, 1); /* One for INIT */
Miklos Szeredid17da462005-03-21 11:47:04 +0000499 init_rwsem(&fc->sbput_sem);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000500#ifdef KERNEL_2_6
501 kobj_set_kset_s(fc, connections_subsys);
502 kobject_init(&fc->kobj);
503#else
504 atomic_set(&fc->kobj.count, 1);
505 fc->kobj.release = fuse_conn_release;
506#endif
507 atomic_set(&fc->num_waiting, 0);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000508 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
509 struct fuse_req *req = fuse_request_alloc();
510 if (!req) {
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000511 kobject_put(&fc->kobj);
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000512 return NULL;
513 }
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000514 list_add(&req->list, &fc->unused_list);
515 }
Miklos Szeredib6220192005-01-05 16:19:10 +0000516#ifdef KERNEL_2_6_6_PLUS
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000517 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
518 fc->bdi.unplug_io_fn = default_unplug_io_fn;
519#endif
Miklos Szeredie3b83092005-07-22 17:24:30 +0000520 fc->reqctr = 0;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000521 }
522 return fc;
523}
524
Miklos Szeredied62d862004-06-20 08:57:39 +0000525static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000526{
Miklos Szeredied62d862004-06-20 08:57:39 +0000527 struct fuse_conn *fc;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000528 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000529
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000530 err = -EINVAL;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000531 if (file->f_op != &fuse_dev_operations)
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000532 goto out_err;
533
534 err = -ENOMEM;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000535 fc = new_conn();
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000536 if (!fc)
537 goto out_err;
538
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000539 spin_lock(&fuse_lock);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000540 err = -EINVAL;
541 if (file->private_data)
542 goto out_unlock;
543
544 kobject_get(&fc->kobj);
545 file->private_data = fc;
Miklos Szeredi3d60e762004-11-11 14:44:04 +0000546 spin_unlock(&fuse_lock);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000547 return fc;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000548
549 out_unlock:
550 spin_unlock(&fuse_lock);
551 kobject_put(&fc->kobj);
552 out_err:
553 return ERR_PTR(err);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000554}
555
Miklos Szeredi83a07442004-11-30 18:25:20 +0000556static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000557{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000558 struct fuse_attr attr;
559 memset(&attr, 0, sizeof(attr));
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000560
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000561 attr.mode = mode;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000562 attr.ino = FUSE_ROOT_ID;
Miklos Szeredi38009022005-05-08 19:47:22 +0000563 return fuse_iget(sb, 1, 0, &attr);
Miklos Szeredi79b52f62001-10-24 14:37:13 +0000564}
Miklos Szeredi1b188022005-07-28 11:07:29 +0000565#ifndef FUSE_MAINLINE
Miklos Szeredie815c032004-01-19 18:20:49 +0000566#ifdef KERNEL_2_6
Miklos Szeredie815c032004-01-19 18:20:49 +0000567static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
568{
569 __u32 *objp = vobjp;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000570 unsigned long nodeid = objp[0];
Miklos Szeredi76f65782004-02-19 16:55:40 +0000571 __u32 generation = objp[1];
Miklos Szeredie815c032004-01-19 18:20:49 +0000572 struct inode *inode;
573 struct dentry *entry;
574
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000575 if (nodeid == 0)
Miklos Szeredia5288792005-03-05 16:46:52 +0000576 return ERR_PTR(-ESTALE);
Miklos Szeredie815c032004-01-19 18:20:49 +0000577
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000578 inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredif43f0632005-02-28 11:46:56 +0000579 if (!inode)
Miklos Szeredia5288792005-03-05 16:46:52 +0000580 return ERR_PTR(-ESTALE);
581 if (inode->i_generation != generation) {
582 iput(inode);
583 return ERR_PTR(-ESTALE);
584 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000585
586 entry = d_alloc_anon(inode);
Miklos Szeredia5288792005-03-05 16:46:52 +0000587 if (!entry) {
588 iput(inode);
589 return ERR_PTR(-ENOMEM);
590 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000591
592 return entry;
593}
594
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000595static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
596 int connectable)
597{
598 struct inode *inode = dentry->d_inode;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000599 int len = *max_len;
600 int type = 1;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000601
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000602 if (len < 2 || (connectable && len < 4))
603 return 255;
604
605 len = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000606 fh[0] = get_fuse_inode(inode)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000607 fh[1] = inode->i_generation;
608 if (connectable && !S_ISDIR(inode->i_mode)) {
609 struct inode *parent;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000610
611 spin_lock(&dentry->d_lock);
612 parent = dentry->d_parent->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000613 fh[2] = get_fuse_inode(parent)->nodeid;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000614 fh[3] = parent->i_generation;
615 spin_unlock(&dentry->d_lock);
616 len = 4;
617 type = 2;
618 }
619 *max_len = len;
620 return type;
621}
622
Miklos Szeredie815c032004-01-19 18:20:49 +0000623static struct export_operations fuse_export_operations = {
624 .get_dentry = fuse_get_dentry,
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000625 .encode_fh = fuse_encode_fh,
Miklos Szeredie815c032004-01-19 18:20:49 +0000626};
627#endif
Miklos Szeredi1b188022005-07-28 11:07:29 +0000628#endif
Miklos Szeredie815c032004-01-19 18:20:49 +0000629
630static struct super_operations fuse_super_operations = {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000631 .alloc_inode = fuse_alloc_inode,
632 .destroy_inode = fuse_destroy_inode,
Miklos Szeredie815c032004-01-19 18:20:49 +0000633 .read_inode = fuse_read_inode,
634 .clear_inode = fuse_clear_inode,
635 .put_super = fuse_put_super,
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000636 .umount_begin = fuse_umount_begin,
Miklos Szeredie815c032004-01-19 18:20:49 +0000637 .statfs = fuse_statfs,
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000638 .show_options = fuse_show_options,
Miklos Szeredie815c032004-01-19 18:20:49 +0000639};
640
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000641static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
642{
643 int i;
644 struct fuse_init_out *arg = &req->misc.init_out;
645
646 if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
647 fc->conn_error = 1;
648 else {
Miklos Szeredi065f2222006-01-20 15:15:21 +0000649#ifdef KERNEL_2_6
650 unsigned long ra_pages;
651
652 if (arg->minor >= 6) {
653 ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
Miklos Szeredif8277502006-01-20 17:16:27 +0000654 if (arg->flags & FUSE_ASYNC_READ)
655 fc->async_read = 1;
656 } else
Miklos Szeredi065f2222006-01-20 15:15:21 +0000657 ra_pages = fc->max_read / PAGE_CACHE_SIZE;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000658
659 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
660#endif
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000661 fc->minor = arg->minor;
662 fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
663 }
664
665 /* After INIT reply is received other requests can go
666 out. So do (FUSE_MAX_OUTSTANDING - 1) number of
667 up()s on outstanding_sem. The last up() is done in
668 fuse_putback_request() */
669 for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
670 up(&fc->outstanding_sem);
671
672 fuse_put_request(fc, req);
673}
674
675static void fuse_send_init(struct fuse_conn *fc)
676{
677 /* This is called from fuse_read_super() so there's guaranteed
678 to be exactly one request available */
679 struct fuse_req *req = fuse_get_request(fc);
680 struct fuse_init_in *arg = &req->misc.init_in;
681
682 arg->major = FUSE_KERNEL_VERSION;
683 arg->minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000684#ifdef KERNEL_2_6
685 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
686 arg->flags |= FUSE_ASYNC_READ;
687#endif
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000688 req->in.h.opcode = FUSE_INIT;
689 req->in.numargs = 1;
690 req->in.args[0].size = sizeof(*arg);
691 req->in.args[0].value = arg;
692 req->out.numargs = 1;
693 /* Variable length arguement used for backward compatibility
694 with interface version < 7.5. Rest of init_out is zeroed
695 by do_get_request(), so a short reply is not a problem */
696 req->out.argvar = 1;
697 req->out.args[0].size = sizeof(struct fuse_init_out);
698 req->out.args[0].value = &req->misc.init_out;
699 req->end = process_init_reply;
700 request_send_background(fc, req);
701}
702
703#ifdef KERNEL_2_6
704static unsigned long long conn_id(void)
705{
706 static unsigned long long ctr = 1;
707 unsigned long long val;
708 spin_lock(&fuse_lock);
709 val = ctr++;
710 spin_unlock(&fuse_lock);
711 return val;
712}
713#endif
714
Miklos Szeredi81394522005-01-11 14:24:18 +0000715static int fuse_fill_super(struct super_block *sb, void *data, int silent)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000716{
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000717 struct fuse_conn *fc;
718 struct inode *root;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000719 struct fuse_mount_data d;
Miklos Szeredied62d862004-06-20 08:57:39 +0000720 struct file *file;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000721 struct dentry *root_dentry;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000722 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000723
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000724 if (!parse_fuse_opt((char *) data, &d))
725 return -EINVAL;
726
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000727 sb->s_blocksize = PAGE_CACHE_SIZE;
728 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
729 sb->s_magic = FUSE_SUPER_MAGIC;
730 sb->s_op = &fuse_super_operations;
731 sb->s_maxbytes = MAX_LFS_FILESIZE;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000732#ifndef FUSE_MAINLINE
Miklos Szeredie815c032004-01-19 18:20:49 +0000733#ifdef KERNEL_2_6
734 sb->s_export_op = &fuse_export_operations;
735#endif
Miklos Szeredi1b188022005-07-28 11:07:29 +0000736#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000737
Miklos Szeredied62d862004-06-20 08:57:39 +0000738 file = fget(d.fd);
739 if (!file)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000740 return -EINVAL;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000741
Miklos Szeredied62d862004-06-20 08:57:39 +0000742 fc = get_conn(file, sb);
Miklos Szeredied62d862004-06-20 08:57:39 +0000743 fput(file);
Miklos Szerediee808382005-01-21 22:05:37 +0000744 if (IS_ERR(fc))
745 return PTR_ERR(fc);
Miklos Szeredied62d862004-06-20 08:57:39 +0000746
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000747 fc->flags = d.flags;
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000748 fc->user_id = d.user_id;
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000749 fc->group_id = d.group_id;
Miklos Szerediad051c32004-07-02 09:22:50 +0000750 fc->max_read = d.max_read;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000751
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000752 /* Used by get_root_inode() */
753 sb->s_fs_info = fc;
754
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000755 err = -ENOMEM;
Miklos Szeredi7f6bc892004-04-13 10:49:14 +0000756 root = get_root_inode(sb, d.rootmode);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000757 if (!root)
Miklos Szeredied62d862004-06-20 08:57:39 +0000758 goto err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000759
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000760 root_dentry = d_alloc_root(root);
761 if (!root_dentry) {
Miklos Szeredied62d862004-06-20 08:57:39 +0000762 iput(root);
763 goto err;
764 }
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000765
766#ifdef KERNEL_2_6
767 err = kobject_set_name(&fc->kobj, "%llu", conn_id());
768 if (err)
769 goto err_put_root;
770
771 err = kobject_add(&fc->kobj);
772 if (err)
773 goto err_put_root;
774#endif
775
776 sb->s_root = root_dentry;
777 spin_lock(&fuse_lock);
778 fc->mounted = 1;
779 fc->connected = 1;
780 spin_unlock(&fuse_lock);
781
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000782 fuse_send_init(fc);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000783
Miklos Szeredif85ab242004-01-07 12:16:45 +0000784 return 0;
Miklos Szeredied62d862004-06-20 08:57:39 +0000785
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000786#ifdef KERNEL_2_6
787 err_put_root:
788 dput(root_dentry);
789#endif
Miklos Szeredied62d862004-06-20 08:57:39 +0000790 err:
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000791 kobject_put(&fc->kobj);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000792 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000793}
794
Miklos Szeredif85ab242004-01-07 12:16:45 +0000795#ifdef KERNEL_2_6
796static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000797 int flags, const char *dev_name,
798 void *raw_data)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000799{
Miklos Szeredi81394522005-01-11 14:24:18 +0000800 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000801}
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000802
Miklos Szeredif85ab242004-01-07 12:16:45 +0000803static struct file_system_type fuse_fs_type = {
Miklos Szeredi377b2ea2004-02-06 09:48:51 +0000804 .owner = THIS_MODULE,
805 .name = "fuse",
806 .get_sb = fuse_get_sb,
807 .kill_sb = kill_anon_super,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000808};
809#else
810static struct super_block *fuse_read_super_compat(struct super_block *sb,
811 void *data, int silent)
812{
Miklos Szeredi81394522005-01-11 14:24:18 +0000813 int err = fuse_fill_super(sb, data, silent);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000814 if (err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000815 return NULL;
816 else
817 return sb;
818}
819
820static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0);
821#endif
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000822
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000823#ifdef KERNEL_2_6
824static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page)
825{
826 return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
827}
828
829static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page,
830 size_t count)
831{
832 fuse_abort_conn(fc);
833 return count;
834}
835
836#ifndef __ATTR
837#define __ATTR(_name,_mode,_show,_store) { \
838 .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
839 .show = _show, \
840 .store = _store, \
841}
842#endif
843static struct fuse_conn_attr fuse_conn_waiting =
844 __ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
845static struct fuse_conn_attr fuse_conn_abort =
846 __ATTR(abort, 0600, NULL, fuse_conn_abort_store);
847
848static struct attribute *fuse_conn_attrs[] = {
849 &fuse_conn_waiting.attr,
850 &fuse_conn_abort.attr,
851 NULL,
852};
853
854static ssize_t fuse_conn_attr_show(struct kobject *kobj,
855 struct attribute *attr,
856 char *page)
857{
858 struct fuse_conn_attr *fca =
859 container_of(attr, struct fuse_conn_attr, attr);
860
861 if (fca->show)
862 return fca->show(get_fuse_conn_kobj(kobj), page);
863 else
864 return -EACCES;
865}
866
867static ssize_t fuse_conn_attr_store(struct kobject *kobj,
868 struct attribute *attr,
869 const char *page, size_t count)
870{
871 struct fuse_conn_attr *fca =
872 container_of(attr, struct fuse_conn_attr, attr);
873
874 if (fca->store)
875 return fca->store(get_fuse_conn_kobj(kobj), page, count);
876 else
877 return -EACCES;
878}
879
880static struct sysfs_ops fuse_conn_sysfs_ops = {
881 .show = &fuse_conn_attr_show,
882 .store = &fuse_conn_attr_store,
883};
884
885static struct kobj_type ktype_fuse_conn = {
886 .release = fuse_conn_release,
887 .sysfs_ops = &fuse_conn_sysfs_ops,
888 .default_attrs = fuse_conn_attrs,
889};
890
891#ifndef HAVE_FS_SUBSYS
892static decl_subsys(fs, NULL, NULL);
893#endif
894static decl_subsys(fuse, NULL, NULL);
895static decl_subsys(connections, &ktype_fuse_conn, NULL);
896#endif /* KERNEL_2_6 */
897
Miklos Szeredi81394522005-01-11 14:24:18 +0000898static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
Miklos Szeredia13d9002004-11-02 17:32:03 +0000899 unsigned long flags)
900{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000901 struct inode * inode = foo;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000902
903 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
904 SLAB_CTOR_CONSTRUCTOR)
905 inode_init_once(inode);
906}
907
Miklos Szeredi9080c792005-01-08 11:50:08 +0000908static int __init fuse_fs_init(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000909{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000910 int err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000911
Miklos Szeredi069c9502004-07-16 16:17:02 +0000912 err = register_filesystem(&fuse_fs_type);
913 if (err)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000914 printk("fuse: failed to register filesystem\n");
Miklos Szeredi069c9502004-07-16 16:17:02 +0000915 else {
916 fuse_inode_cachep = kmem_cache_create("fuse_inode",
Miklos Szeredi81394522005-01-11 14:24:18 +0000917 sizeof(struct fuse_inode),
Miklos Szeredia13d9002004-11-02 17:32:03 +0000918 0, SLAB_HWCACHE_ALIGN,
919 fuse_inode_init_once, NULL);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000920 if (!fuse_inode_cachep) {
921 unregister_filesystem(&fuse_fs_type);
922 err = -ENOMEM;
923 }
924 }
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000925
Miklos Szeredi069c9502004-07-16 16:17:02 +0000926 return err;
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000927}
928
Miklos Szeredi9080c792005-01-08 11:50:08 +0000929static void fuse_fs_cleanup(void)
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000930{
931 unregister_filesystem(&fuse_fs_type);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000932 kmem_cache_destroy(fuse_inode_cachep);
Miklos Szeredibc22e7b2001-10-23 19:26:04 +0000933}
Miklos Szeredi9080c792005-01-08 11:50:08 +0000934
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000935#ifdef KERNEL_2_6
936static int fuse_sysfs_init(void)
937{
938 int err;
939
940#ifndef HAVE_FS_SUBSYS
941 err = subsystem_register(&fs_subsys);
942 if (err)
943 return err;
944#endif
945 kset_set_kset_s(&fuse_subsys, fs_subsys);
946 err = subsystem_register(&fuse_subsys);
947 if (err)
948 goto out_err;
949
950 kset_set_kset_s(&connections_subsys, fuse_subsys);
951 err = subsystem_register(&connections_subsys);
952 if (err)
953 goto out_fuse_unregister;
954
955 return 0;
956
957 out_fuse_unregister:
958 subsystem_unregister(&fuse_subsys);
959 out_err:
960#ifndef HAVE_FS_SUBSYS
961 subsystem_unregister(&fs_subsys);
962#endif
963 return err;
964}
965
966static void fuse_sysfs_cleanup(void)
967{
968 subsystem_unregister(&connections_subsys);
969 subsystem_unregister(&fuse_subsys);
970#ifndef HAVE_FS_SUBSYS
971 subsystem_unregister(&fs_subsys);
972#endif
973}
974#else /* KERNEL_2_6 */
975static int fuse_sysfs_init(void)
976{
977 return 0;
978}
979static void fuse_sysfs_cleanup(void)
980{
981}
982#endif /* KERNEL_2_6 */
983
Miklos Szeredi81394522005-01-11 14:24:18 +0000984static int __init fuse_init(void)
Miklos Szeredi9080c792005-01-08 11:50:08 +0000985{
986 int res;
987
988 printk("fuse init (API version %i.%i)\n",
989 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
990#ifndef FUSE_MAINLINE
991 printk("fuse distribution version: %s\n", FUSE_VERSION);
992#endif
993
994 spin_lock_init(&fuse_lock);
995 res = fuse_fs_init();
996 if (res)
997 goto err;
998
999 res = fuse_dev_init();
1000 if (res)
1001 goto err_fs_cleanup;
1002
Miklos Szeredi15af1b82006-01-16 17:52:24 +00001003 res = fuse_sysfs_init();
1004 if (res)
1005 goto err_dev_cleanup;
1006
Miklos Szeredi9080c792005-01-08 11:50:08 +00001007 return 0;
1008
Miklos Szeredi15af1b82006-01-16 17:52:24 +00001009 err_dev_cleanup:
1010 fuse_dev_cleanup();
Miklos Szeredi9080c792005-01-08 11:50:08 +00001011 err_fs_cleanup:
1012 fuse_fs_cleanup();
1013 err:
1014 return res;
1015}
1016
Miklos Szeredi81394522005-01-11 14:24:18 +00001017static void __exit fuse_exit(void)
Miklos Szeredi9080c792005-01-08 11:50:08 +00001018{
1019 printk(KERN_DEBUG "fuse exit\n");
1020
Miklos Szeredi15af1b82006-01-16 17:52:24 +00001021 fuse_sysfs_cleanup();
Miklos Szeredi9080c792005-01-08 11:50:08 +00001022 fuse_fs_cleanup();
1023 fuse_dev_cleanup();
1024}
1025
1026module_init(fuse_init);
1027module_exit(fuse_exit);