1d8a5ba45SMiklos Szeredi /* 2d8a5ba45SMiklos Szeredi FUSE: Filesystem in Userspace 3d8a5ba45SMiklos Szeredi Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> 4d8a5ba45SMiklos Szeredi 5d8a5ba45SMiklos Szeredi This program can be distributed under the terms of the GNU GPL. 6d8a5ba45SMiklos Szeredi See the file COPYING. 7d8a5ba45SMiklos Szeredi */ 8d8a5ba45SMiklos Szeredi 9d8a5ba45SMiklos Szeredi #include "fuse_i.h" 10d8a5ba45SMiklos Szeredi 11d8a5ba45SMiklos Szeredi #include <linux/pagemap.h> 12d8a5ba45SMiklos Szeredi #include <linux/slab.h> 13d8a5ba45SMiklos Szeredi #include <linux/file.h> 14d8a5ba45SMiklos Szeredi #include <linux/mount.h> 15d8a5ba45SMiklos Szeredi #include <linux/seq_file.h> 16d8a5ba45SMiklos Szeredi #include <linux/init.h> 17d8a5ba45SMiklos Szeredi #include <linux/module.h> 18d8a5ba45SMiklos Szeredi #include <linux/moduleparam.h> 19d8a5ba45SMiklos Szeredi #include <linux/parser.h> 20d8a5ba45SMiklos Szeredi #include <linux/statfs.h> 21d8a5ba45SMiklos Szeredi 22d8a5ba45SMiklos Szeredi MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); 23d8a5ba45SMiklos Szeredi MODULE_DESCRIPTION("Filesystem in Userspace"); 24d8a5ba45SMiklos Szeredi MODULE_LICENSE("GPL"); 25d8a5ba45SMiklos Szeredi 26d8a5ba45SMiklos Szeredi spinlock_t fuse_lock; 27d8a5ba45SMiklos Szeredi static kmem_cache_t *fuse_inode_cachep; 28d8a5ba45SMiklos Szeredi static int mount_count; 29d8a5ba45SMiklos Szeredi 30d8a5ba45SMiklos Szeredi static int mount_max = 1000; 31d8a5ba45SMiklos Szeredi module_param(mount_max, int, 0644); 32d8a5ba45SMiklos Szeredi MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)"); 33d8a5ba45SMiklos Szeredi 34d8a5ba45SMiklos Szeredi #define FUSE_SUPER_MAGIC 0x65735546 35d8a5ba45SMiklos Szeredi 36d8a5ba45SMiklos Szeredi struct fuse_mount_data { 37d8a5ba45SMiklos Szeredi int fd; 38d8a5ba45SMiklos Szeredi unsigned rootmode; 39d8a5ba45SMiklos Szeredi unsigned user_id; 40d8a5ba45SMiklos Szeredi }; 41d8a5ba45SMiklos Szeredi 42d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb) 43d8a5ba45SMiklos Szeredi { 44d8a5ba45SMiklos Szeredi struct inode *inode; 45d8a5ba45SMiklos Szeredi struct fuse_inode *fi; 46d8a5ba45SMiklos Szeredi 47d8a5ba45SMiklos Szeredi inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); 48d8a5ba45SMiklos Szeredi if (!inode) 49d8a5ba45SMiklos Szeredi return NULL; 50d8a5ba45SMiklos Szeredi 51d8a5ba45SMiklos Szeredi fi = get_fuse_inode(inode); 52d8a5ba45SMiklos Szeredi fi->i_time = jiffies - 1; 53d8a5ba45SMiklos Szeredi fi->nodeid = 0; 54e5e5558eSMiklos Szeredi fi->forget_req = fuse_request_alloc(); 55e5e5558eSMiklos Szeredi if (!fi->forget_req) { 56e5e5558eSMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 57e5e5558eSMiklos Szeredi return NULL; 58e5e5558eSMiklos Szeredi } 59d8a5ba45SMiklos Szeredi 60d8a5ba45SMiklos Szeredi return inode; 61d8a5ba45SMiklos Szeredi } 62d8a5ba45SMiklos Szeredi 63d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode) 64d8a5ba45SMiklos Szeredi { 65e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 66e5e5558eSMiklos Szeredi if (fi->forget_req) 67e5e5558eSMiklos Szeredi fuse_request_free(fi->forget_req); 68d8a5ba45SMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 69d8a5ba45SMiklos Szeredi } 70d8a5ba45SMiklos Szeredi 71d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode) 72d8a5ba45SMiklos Szeredi { 73d8a5ba45SMiklos Szeredi /* No op */ 74d8a5ba45SMiklos Szeredi } 75d8a5ba45SMiklos Szeredi 76e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, 77e5e5558eSMiklos Szeredi unsigned long nodeid, int version) 78e5e5558eSMiklos Szeredi { 79e5e5558eSMiklos Szeredi struct fuse_forget_in *inarg = &req->misc.forget_in; 80e5e5558eSMiklos Szeredi inarg->version = version; 81e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_FORGET; 82e5e5558eSMiklos Szeredi req->in.h.nodeid = nodeid; 83e5e5558eSMiklos Szeredi req->in.numargs = 1; 84e5e5558eSMiklos Szeredi req->in.args[0].size = sizeof(struct fuse_forget_in); 85e5e5558eSMiklos Szeredi req->in.args[0].value = inarg; 86e5e5558eSMiklos Szeredi request_send_noreply(fc, req); 87e5e5558eSMiklos Szeredi } 88e5e5558eSMiklos Szeredi 89d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode) 90d8a5ba45SMiklos Szeredi { 91e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 92e5e5558eSMiklos Szeredi if (fc) { 93e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 94e5e5558eSMiklos Szeredi fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version); 95e5e5558eSMiklos Szeredi fi->forget_req = NULL; 96e5e5558eSMiklos Szeredi } 97d8a5ba45SMiklos Szeredi } 98d8a5ba45SMiklos Szeredi 99d8a5ba45SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) 100d8a5ba45SMiklos Szeredi { 101d8a5ba45SMiklos Szeredi if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) 102d8a5ba45SMiklos Szeredi invalidate_inode_pages(inode->i_mapping); 103d8a5ba45SMiklos Szeredi 104d8a5ba45SMiklos Szeredi inode->i_ino = attr->ino; 105d8a5ba45SMiklos Szeredi inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); 106d8a5ba45SMiklos Szeredi inode->i_nlink = attr->nlink; 107d8a5ba45SMiklos Szeredi inode->i_uid = attr->uid; 108d8a5ba45SMiklos Szeredi inode->i_gid = attr->gid; 109d8a5ba45SMiklos Szeredi i_size_write(inode, attr->size); 110d8a5ba45SMiklos Szeredi inode->i_blksize = PAGE_CACHE_SIZE; 111d8a5ba45SMiklos Szeredi inode->i_blocks = attr->blocks; 112d8a5ba45SMiklos Szeredi inode->i_atime.tv_sec = attr->atime; 113d8a5ba45SMiklos Szeredi inode->i_atime.tv_nsec = attr->atimensec; 114d8a5ba45SMiklos Szeredi inode->i_mtime.tv_sec = attr->mtime; 115d8a5ba45SMiklos Szeredi inode->i_mtime.tv_nsec = attr->mtimensec; 116d8a5ba45SMiklos Szeredi inode->i_ctime.tv_sec = attr->ctime; 117d8a5ba45SMiklos Szeredi inode->i_ctime.tv_nsec = attr->ctimensec; 118d8a5ba45SMiklos Szeredi } 119d8a5ba45SMiklos Szeredi 120d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) 121d8a5ba45SMiklos Szeredi { 122d8a5ba45SMiklos Szeredi inode->i_mode = attr->mode & S_IFMT; 123d8a5ba45SMiklos Szeredi i_size_write(inode, attr->size); 124e5e5558eSMiklos Szeredi if (S_ISREG(inode->i_mode)) { 125e5e5558eSMiklos Szeredi fuse_init_common(inode); 126e5e5558eSMiklos Szeredi } else if (S_ISDIR(inode->i_mode)) 127e5e5558eSMiklos Szeredi fuse_init_dir(inode); 128e5e5558eSMiklos Szeredi else if (S_ISLNK(inode->i_mode)) 129e5e5558eSMiklos Szeredi fuse_init_symlink(inode); 130e5e5558eSMiklos Szeredi else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || 131e5e5558eSMiklos Szeredi S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { 132e5e5558eSMiklos Szeredi fuse_init_common(inode); 133e5e5558eSMiklos Szeredi init_special_inode(inode, inode->i_mode, 134e5e5558eSMiklos Szeredi new_decode_dev(attr->rdev)); 135e5e5558eSMiklos Szeredi } else { 136e5e5558eSMiklos Szeredi /* Don't let user create weird files */ 137e5e5558eSMiklos Szeredi inode->i_mode = S_IFREG; 138e5e5558eSMiklos Szeredi fuse_init_common(inode); 139e5e5558eSMiklos Szeredi } 140d8a5ba45SMiklos Szeredi } 141d8a5ba45SMiklos Szeredi 142d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp) 143d8a5ba45SMiklos Szeredi { 144d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 145d8a5ba45SMiklos Szeredi if (get_node_id(inode) == nodeid) 146d8a5ba45SMiklos Szeredi return 1; 147d8a5ba45SMiklos Szeredi else 148d8a5ba45SMiklos Szeredi return 0; 149d8a5ba45SMiklos Szeredi } 150d8a5ba45SMiklos Szeredi 151d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp) 152d8a5ba45SMiklos Szeredi { 153d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 154d8a5ba45SMiklos Szeredi get_fuse_inode(inode)->nodeid = nodeid; 155d8a5ba45SMiklos Szeredi return 0; 156d8a5ba45SMiklos Szeredi } 157d8a5ba45SMiklos Szeredi 158d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 159d8a5ba45SMiklos Szeredi int generation, struct fuse_attr *attr, int version) 160d8a5ba45SMiklos Szeredi { 161d8a5ba45SMiklos Szeredi struct inode *inode; 162d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 163d8a5ba45SMiklos Szeredi int retried = 0; 164d8a5ba45SMiklos Szeredi 165d8a5ba45SMiklos Szeredi retry: 166d8a5ba45SMiklos Szeredi inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); 167d8a5ba45SMiklos Szeredi if (!inode) 168d8a5ba45SMiklos Szeredi return NULL; 169d8a5ba45SMiklos Szeredi 170d8a5ba45SMiklos Szeredi if ((inode->i_state & I_NEW)) { 171d8a5ba45SMiklos Szeredi inode->i_generation = generation; 172d8a5ba45SMiklos Szeredi inode->i_data.backing_dev_info = &fc->bdi; 173d8a5ba45SMiklos Szeredi fuse_init_inode(inode, attr); 174d8a5ba45SMiklos Szeredi unlock_new_inode(inode); 175d8a5ba45SMiklos Szeredi } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { 176d8a5ba45SMiklos Szeredi BUG_ON(retried); 177d8a5ba45SMiklos Szeredi /* Inode has changed type, any I/O on the old should fail */ 178d8a5ba45SMiklos Szeredi make_bad_inode(inode); 179d8a5ba45SMiklos Szeredi iput(inode); 180d8a5ba45SMiklos Szeredi retried = 1; 181d8a5ba45SMiklos Szeredi goto retry; 182d8a5ba45SMiklos Szeredi } 183d8a5ba45SMiklos Szeredi 184d8a5ba45SMiklos Szeredi fuse_change_attributes(inode, attr); 185d8a5ba45SMiklos Szeredi inode->i_version = version; 186d8a5ba45SMiklos Szeredi return inode; 187d8a5ba45SMiklos Szeredi } 188d8a5ba45SMiklos Szeredi 189d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb) 190d8a5ba45SMiklos Szeredi { 191d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 192d8a5ba45SMiklos Szeredi 193d8a5ba45SMiklos Szeredi spin_lock(&fuse_lock); 194d8a5ba45SMiklos Szeredi mount_count --; 195d8a5ba45SMiklos Szeredi fc->sb = NULL; 196d8a5ba45SMiklos Szeredi fc->user_id = 0; 197334f485dSMiklos Szeredi /* Flush all readers on this fs */ 198334f485dSMiklos Szeredi wake_up_all(&fc->waitq); 199d8a5ba45SMiklos Szeredi fuse_release_conn(fc); 200d8a5ba45SMiklos Szeredi *get_fuse_conn_super_p(sb) = NULL; 201d8a5ba45SMiklos Szeredi spin_unlock(&fuse_lock); 202d8a5ba45SMiklos Szeredi } 203d8a5ba45SMiklos Szeredi 204e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) 205e5e5558eSMiklos Szeredi { 206e5e5558eSMiklos Szeredi stbuf->f_type = FUSE_SUPER_MAGIC; 207e5e5558eSMiklos Szeredi stbuf->f_bsize = attr->bsize; 208e5e5558eSMiklos Szeredi stbuf->f_blocks = attr->blocks; 209e5e5558eSMiklos Szeredi stbuf->f_bfree = attr->bfree; 210e5e5558eSMiklos Szeredi stbuf->f_bavail = attr->bavail; 211e5e5558eSMiklos Szeredi stbuf->f_files = attr->files; 212e5e5558eSMiklos Szeredi stbuf->f_ffree = attr->ffree; 213e5e5558eSMiklos Szeredi stbuf->f_namelen = attr->namelen; 214e5e5558eSMiklos Szeredi /* fsid is left zero */ 215e5e5558eSMiklos Szeredi } 216e5e5558eSMiklos Szeredi 217e5e5558eSMiklos Szeredi static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) 218e5e5558eSMiklos Szeredi { 219e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 220e5e5558eSMiklos Szeredi struct fuse_req *req; 221e5e5558eSMiklos Szeredi struct fuse_statfs_out outarg; 222e5e5558eSMiklos Szeredi int err; 223e5e5558eSMiklos Szeredi 224e5e5558eSMiklos Szeredi req = fuse_get_request(fc); 225e5e5558eSMiklos Szeredi if (!req) 226e5e5558eSMiklos Szeredi return -ERESTARTSYS; 227e5e5558eSMiklos Szeredi 228e5e5558eSMiklos Szeredi req->in.numargs = 0; 229e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_STATFS; 230e5e5558eSMiklos Szeredi req->out.numargs = 1; 231e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 232e5e5558eSMiklos Szeredi req->out.args[0].value = &outarg; 233e5e5558eSMiklos Szeredi request_send(fc, req); 234e5e5558eSMiklos Szeredi err = req->out.h.error; 235e5e5558eSMiklos Szeredi if (!err) 236e5e5558eSMiklos Szeredi convert_fuse_statfs(buf, &outarg.st); 237e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 238e5e5558eSMiklos Szeredi return err; 239e5e5558eSMiklos Szeredi } 240e5e5558eSMiklos Szeredi 241d8a5ba45SMiklos Szeredi enum { 242d8a5ba45SMiklos Szeredi OPT_FD, 243d8a5ba45SMiklos Szeredi OPT_ROOTMODE, 244d8a5ba45SMiklos Szeredi OPT_USER_ID, 245d8a5ba45SMiklos Szeredi OPT_DEFAULT_PERMISSIONS, 246d8a5ba45SMiklos Szeredi OPT_ALLOW_OTHER, 247d8a5ba45SMiklos Szeredi OPT_ALLOW_ROOT, 248d8a5ba45SMiklos Szeredi OPT_KERNEL_CACHE, 249d8a5ba45SMiklos Szeredi OPT_ERR 250d8a5ba45SMiklos Szeredi }; 251d8a5ba45SMiklos Szeredi 252d8a5ba45SMiklos Szeredi static match_table_t tokens = { 253d8a5ba45SMiklos Szeredi {OPT_FD, "fd=%u"}, 254d8a5ba45SMiklos Szeredi {OPT_ROOTMODE, "rootmode=%o"}, 255d8a5ba45SMiklos Szeredi {OPT_USER_ID, "user_id=%u"}, 256d8a5ba45SMiklos Szeredi {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 257d8a5ba45SMiklos Szeredi {OPT_ALLOW_OTHER, "allow_other"}, 258d8a5ba45SMiklos Szeredi {OPT_ALLOW_ROOT, "allow_root"}, 259d8a5ba45SMiklos Szeredi {OPT_KERNEL_CACHE, "kernel_cache"}, 260d8a5ba45SMiklos Szeredi {OPT_ERR, NULL} 261d8a5ba45SMiklos Szeredi }; 262d8a5ba45SMiklos Szeredi 263d8a5ba45SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) 264d8a5ba45SMiklos Szeredi { 265d8a5ba45SMiklos Szeredi char *p; 266d8a5ba45SMiklos Szeredi memset(d, 0, sizeof(struct fuse_mount_data)); 267d8a5ba45SMiklos Szeredi d->fd = -1; 268d8a5ba45SMiklos Szeredi 269d8a5ba45SMiklos Szeredi while ((p = strsep(&opt, ",")) != NULL) { 270d8a5ba45SMiklos Szeredi int token; 271d8a5ba45SMiklos Szeredi int value; 272d8a5ba45SMiklos Szeredi substring_t args[MAX_OPT_ARGS]; 273d8a5ba45SMiklos Szeredi if (!*p) 274d8a5ba45SMiklos Szeredi continue; 275d8a5ba45SMiklos Szeredi 276d8a5ba45SMiklos Szeredi token = match_token(p, tokens, args); 277d8a5ba45SMiklos Szeredi switch (token) { 278d8a5ba45SMiklos Szeredi case OPT_FD: 279d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 280d8a5ba45SMiklos Szeredi return 0; 281d8a5ba45SMiklos Szeredi d->fd = value; 282d8a5ba45SMiklos Szeredi break; 283d8a5ba45SMiklos Szeredi 284d8a5ba45SMiklos Szeredi case OPT_ROOTMODE: 285d8a5ba45SMiklos Szeredi if (match_octal(&args[0], &value)) 286d8a5ba45SMiklos Szeredi return 0; 287d8a5ba45SMiklos Szeredi d->rootmode = value; 288d8a5ba45SMiklos Szeredi break; 289d8a5ba45SMiklos Szeredi 290d8a5ba45SMiklos Szeredi case OPT_USER_ID: 291d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 292d8a5ba45SMiklos Szeredi return 0; 293d8a5ba45SMiklos Szeredi d->user_id = value; 294d8a5ba45SMiklos Szeredi break; 295d8a5ba45SMiklos Szeredi 296d8a5ba45SMiklos Szeredi default: 297d8a5ba45SMiklos Szeredi return 0; 298d8a5ba45SMiklos Szeredi } 299d8a5ba45SMiklos Szeredi } 300d8a5ba45SMiklos Szeredi if (d->fd == -1) 301d8a5ba45SMiklos Szeredi return 0; 302d8a5ba45SMiklos Szeredi 303d8a5ba45SMiklos Szeredi return 1; 304d8a5ba45SMiklos Szeredi } 305d8a5ba45SMiklos Szeredi 306d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) 307d8a5ba45SMiklos Szeredi { 308d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 309d8a5ba45SMiklos Szeredi 310d8a5ba45SMiklos Szeredi seq_printf(m, ",user_id=%u", fc->user_id); 311d8a5ba45SMiklos Szeredi return 0; 312d8a5ba45SMiklos Szeredi } 313d8a5ba45SMiklos Szeredi 314334f485dSMiklos Szeredi static void free_conn(struct fuse_conn *fc) 315334f485dSMiklos Szeredi { 316334f485dSMiklos Szeredi while (!list_empty(&fc->unused_list)) { 317334f485dSMiklos Szeredi struct fuse_req *req; 318334f485dSMiklos Szeredi req = list_entry(fc->unused_list.next, struct fuse_req, list); 319334f485dSMiklos Szeredi list_del(&req->list); 320334f485dSMiklos Szeredi fuse_request_free(req); 321334f485dSMiklos Szeredi } 322334f485dSMiklos Szeredi kfree(fc); 323334f485dSMiklos Szeredi } 324334f485dSMiklos Szeredi 325334f485dSMiklos Szeredi /* Must be called with the fuse lock held */ 326d8a5ba45SMiklos Szeredi void fuse_release_conn(struct fuse_conn *fc) 327d8a5ba45SMiklos Szeredi { 328334f485dSMiklos Szeredi if (!fc->sb && !fc->file) 329334f485dSMiklos Szeredi free_conn(fc); 330d8a5ba45SMiklos Szeredi } 331d8a5ba45SMiklos Szeredi 332d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void) 333d8a5ba45SMiklos Szeredi { 334d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 335d8a5ba45SMiklos Szeredi 336d8a5ba45SMiklos Szeredi fc = kmalloc(sizeof(*fc), GFP_KERNEL); 337d8a5ba45SMiklos Szeredi if (fc != NULL) { 338334f485dSMiklos Szeredi int i; 339d8a5ba45SMiklos Szeredi memset(fc, 0, sizeof(*fc)); 340d8a5ba45SMiklos Szeredi fc->sb = NULL; 341334f485dSMiklos Szeredi fc->file = NULL; 342d8a5ba45SMiklos Szeredi fc->user_id = 0; 343334f485dSMiklos Szeredi init_waitqueue_head(&fc->waitq); 344334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->pending); 345334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->processing); 346334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->unused_list); 347334f485dSMiklos Szeredi sema_init(&fc->outstanding_sem, 0); 348334f485dSMiklos Szeredi for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { 349334f485dSMiklos Szeredi struct fuse_req *req = fuse_request_alloc(); 350334f485dSMiklos Szeredi if (!req) { 351334f485dSMiklos Szeredi free_conn(fc); 352334f485dSMiklos Szeredi return NULL; 353334f485dSMiklos Szeredi } 354334f485dSMiklos Szeredi list_add(&req->list, &fc->unused_list); 355334f485dSMiklos Szeredi } 356d8a5ba45SMiklos Szeredi fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 357d8a5ba45SMiklos Szeredi fc->bdi.unplug_io_fn = default_unplug_io_fn; 358334f485dSMiklos Szeredi fc->reqctr = 0; 359d8a5ba45SMiklos Szeredi } 360d8a5ba45SMiklos Szeredi return fc; 361d8a5ba45SMiklos Szeredi } 362d8a5ba45SMiklos Szeredi 363d8a5ba45SMiklos Szeredi static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) 364d8a5ba45SMiklos Szeredi { 365d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 366d8a5ba45SMiklos Szeredi 367334f485dSMiklos Szeredi if (file->f_op != &fuse_dev_operations) 368334f485dSMiklos Szeredi return ERR_PTR(-EINVAL); 369d8a5ba45SMiklos Szeredi fc = new_conn(); 370d8a5ba45SMiklos Szeredi if (fc == NULL) 371334f485dSMiklos Szeredi return ERR_PTR(-ENOMEM); 372d8a5ba45SMiklos Szeredi spin_lock(&fuse_lock); 373334f485dSMiklos Szeredi if (file->private_data) { 374334f485dSMiklos Szeredi free_conn(fc); 375334f485dSMiklos Szeredi fc = ERR_PTR(-EINVAL); 376334f485dSMiklos Szeredi } else { 377334f485dSMiklos Szeredi file->private_data = fc; 378d8a5ba45SMiklos Szeredi fc->sb = sb; 379334f485dSMiklos Szeredi fc->file = file; 380334f485dSMiklos Szeredi } 381d8a5ba45SMiklos Szeredi spin_unlock(&fuse_lock); 382d8a5ba45SMiklos Szeredi return fc; 383d8a5ba45SMiklos Szeredi } 384d8a5ba45SMiklos Szeredi 385d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode) 386d8a5ba45SMiklos Szeredi { 387d8a5ba45SMiklos Szeredi struct fuse_attr attr; 388d8a5ba45SMiklos Szeredi memset(&attr, 0, sizeof(attr)); 389d8a5ba45SMiklos Szeredi 390d8a5ba45SMiklos Szeredi attr.mode = mode; 391d8a5ba45SMiklos Szeredi attr.ino = FUSE_ROOT_ID; 392d8a5ba45SMiklos Szeredi return fuse_iget(sb, 1, 0, &attr, 0); 393d8a5ba45SMiklos Szeredi } 394d8a5ba45SMiklos Szeredi 395d8a5ba45SMiklos Szeredi static struct super_operations fuse_super_operations = { 396d8a5ba45SMiklos Szeredi .alloc_inode = fuse_alloc_inode, 397d8a5ba45SMiklos Szeredi .destroy_inode = fuse_destroy_inode, 398d8a5ba45SMiklos Szeredi .read_inode = fuse_read_inode, 399d8a5ba45SMiklos Szeredi .clear_inode = fuse_clear_inode, 400d8a5ba45SMiklos Szeredi .put_super = fuse_put_super, 401e5e5558eSMiklos Szeredi .statfs = fuse_statfs, 402d8a5ba45SMiklos Szeredi .show_options = fuse_show_options, 403d8a5ba45SMiklos Szeredi }; 404d8a5ba45SMiklos Szeredi 405d8a5ba45SMiklos Szeredi static int inc_mount_count(void) 406d8a5ba45SMiklos Szeredi { 407d8a5ba45SMiklos Szeredi int success = 0; 408d8a5ba45SMiklos Szeredi spin_lock(&fuse_lock); 409d8a5ba45SMiklos Szeredi mount_count ++; 410d8a5ba45SMiklos Szeredi if (mount_max == -1 || mount_count <= mount_max) 411d8a5ba45SMiklos Szeredi success = 1; 412d8a5ba45SMiklos Szeredi spin_unlock(&fuse_lock); 413d8a5ba45SMiklos Szeredi return success; 414d8a5ba45SMiklos Szeredi } 415d8a5ba45SMiklos Szeredi 416d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent) 417d8a5ba45SMiklos Szeredi { 418d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 419d8a5ba45SMiklos Szeredi struct inode *root; 420d8a5ba45SMiklos Szeredi struct fuse_mount_data d; 421d8a5ba45SMiklos Szeredi struct file *file; 422d8a5ba45SMiklos Szeredi int err; 423d8a5ba45SMiklos Szeredi 424d8a5ba45SMiklos Szeredi if (!parse_fuse_opt((char *) data, &d)) 425d8a5ba45SMiklos Szeredi return -EINVAL; 426d8a5ba45SMiklos Szeredi 427d8a5ba45SMiklos Szeredi sb->s_blocksize = PAGE_CACHE_SIZE; 428d8a5ba45SMiklos Szeredi sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 429d8a5ba45SMiklos Szeredi sb->s_magic = FUSE_SUPER_MAGIC; 430d8a5ba45SMiklos Szeredi sb->s_op = &fuse_super_operations; 431d8a5ba45SMiklos Szeredi sb->s_maxbytes = MAX_LFS_FILESIZE; 432d8a5ba45SMiklos Szeredi 433d8a5ba45SMiklos Szeredi file = fget(d.fd); 434d8a5ba45SMiklos Szeredi if (!file) 435d8a5ba45SMiklos Szeredi return -EINVAL; 436d8a5ba45SMiklos Szeredi 437d8a5ba45SMiklos Szeredi fc = get_conn(file, sb); 438d8a5ba45SMiklos Szeredi fput(file); 439334f485dSMiklos Szeredi if (IS_ERR(fc)) 440334f485dSMiklos Szeredi return PTR_ERR(fc); 441d8a5ba45SMiklos Szeredi 442d8a5ba45SMiklos Szeredi fc->user_id = d.user_id; 443d8a5ba45SMiklos Szeredi 444d8a5ba45SMiklos Szeredi *get_fuse_conn_super_p(sb) = fc; 445d8a5ba45SMiklos Szeredi 446d8a5ba45SMiklos Szeredi err = -ENFILE; 447d8a5ba45SMiklos Szeredi if (!inc_mount_count() && current->uid != 0) 448d8a5ba45SMiklos Szeredi goto err; 449d8a5ba45SMiklos Szeredi 450d8a5ba45SMiklos Szeredi err = -ENOMEM; 451d8a5ba45SMiklos Szeredi root = get_root_inode(sb, d.rootmode); 452d8a5ba45SMiklos Szeredi if (root == NULL) 453d8a5ba45SMiklos Szeredi goto err; 454d8a5ba45SMiklos Szeredi 455d8a5ba45SMiklos Szeredi sb->s_root = d_alloc_root(root); 456d8a5ba45SMiklos Szeredi if (!sb->s_root) { 457d8a5ba45SMiklos Szeredi iput(root); 458d8a5ba45SMiklos Szeredi goto err; 459d8a5ba45SMiklos Szeredi } 460334f485dSMiklos Szeredi fuse_send_init(fc); 461d8a5ba45SMiklos Szeredi return 0; 462d8a5ba45SMiklos Szeredi 463d8a5ba45SMiklos Szeredi err: 464d8a5ba45SMiklos Szeredi spin_lock(&fuse_lock); 465d8a5ba45SMiklos Szeredi mount_count --; 466d8a5ba45SMiklos Szeredi fc->sb = NULL; 467d8a5ba45SMiklos Szeredi fuse_release_conn(fc); 468d8a5ba45SMiklos Szeredi spin_unlock(&fuse_lock); 469d8a5ba45SMiklos Szeredi *get_fuse_conn_super_p(sb) = NULL; 470d8a5ba45SMiklos Szeredi return err; 471d8a5ba45SMiklos Szeredi } 472d8a5ba45SMiklos Szeredi 473d8a5ba45SMiklos Szeredi static struct super_block *fuse_get_sb(struct file_system_type *fs_type, 474d8a5ba45SMiklos Szeredi int flags, const char *dev_name, 475d8a5ba45SMiklos Szeredi void *raw_data) 476d8a5ba45SMiklos Szeredi { 477d8a5ba45SMiklos Szeredi return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super); 478d8a5ba45SMiklos Szeredi } 479d8a5ba45SMiklos Szeredi 480d8a5ba45SMiklos Szeredi static struct file_system_type fuse_fs_type = { 481d8a5ba45SMiklos Szeredi .owner = THIS_MODULE, 482d8a5ba45SMiklos Szeredi .name = "fuse", 483d8a5ba45SMiklos Szeredi .get_sb = fuse_get_sb, 484d8a5ba45SMiklos Szeredi .kill_sb = kill_anon_super, 485d8a5ba45SMiklos Szeredi }; 486d8a5ba45SMiklos Szeredi 487d8a5ba45SMiklos Szeredi static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, 488d8a5ba45SMiklos Szeredi unsigned long flags) 489d8a5ba45SMiklos Szeredi { 490d8a5ba45SMiklos Szeredi struct inode * inode = foo; 491d8a5ba45SMiklos Szeredi 492d8a5ba45SMiklos Szeredi if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 493d8a5ba45SMiklos Szeredi SLAB_CTOR_CONSTRUCTOR) 494d8a5ba45SMiklos Szeredi inode_init_once(inode); 495d8a5ba45SMiklos Szeredi } 496d8a5ba45SMiklos Szeredi 497d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void) 498d8a5ba45SMiklos Szeredi { 499d8a5ba45SMiklos Szeredi int err; 500d8a5ba45SMiklos Szeredi 501d8a5ba45SMiklos Szeredi err = register_filesystem(&fuse_fs_type); 502d8a5ba45SMiklos Szeredi if (err) 503d8a5ba45SMiklos Szeredi printk("fuse: failed to register filesystem\n"); 504d8a5ba45SMiklos Szeredi else { 505d8a5ba45SMiklos Szeredi fuse_inode_cachep = kmem_cache_create("fuse_inode", 506d8a5ba45SMiklos Szeredi sizeof(struct fuse_inode), 507d8a5ba45SMiklos Szeredi 0, SLAB_HWCACHE_ALIGN, 508d8a5ba45SMiklos Szeredi fuse_inode_init_once, NULL); 509d8a5ba45SMiklos Szeredi if (!fuse_inode_cachep) { 510d8a5ba45SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 511d8a5ba45SMiklos Szeredi err = -ENOMEM; 512d8a5ba45SMiklos Szeredi } 513d8a5ba45SMiklos Szeredi } 514d8a5ba45SMiklos Szeredi 515d8a5ba45SMiklos Szeredi return err; 516d8a5ba45SMiklos Szeredi } 517d8a5ba45SMiklos Szeredi 518d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void) 519d8a5ba45SMiklos Szeredi { 520d8a5ba45SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 521d8a5ba45SMiklos Szeredi kmem_cache_destroy(fuse_inode_cachep); 522d8a5ba45SMiklos Szeredi } 523d8a5ba45SMiklos Szeredi 524d8a5ba45SMiklos Szeredi static int __init fuse_init(void) 525d8a5ba45SMiklos Szeredi { 526d8a5ba45SMiklos Szeredi int res; 527d8a5ba45SMiklos Szeredi 528d8a5ba45SMiklos Szeredi printk("fuse init (API version %i.%i)\n", 529d8a5ba45SMiklos Szeredi FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 530d8a5ba45SMiklos Szeredi 531d8a5ba45SMiklos Szeredi spin_lock_init(&fuse_lock); 532d8a5ba45SMiklos Szeredi res = fuse_fs_init(); 533d8a5ba45SMiklos Szeredi if (res) 534d8a5ba45SMiklos Szeredi goto err; 535d8a5ba45SMiklos Szeredi 536334f485dSMiklos Szeredi res = fuse_dev_init(); 537334f485dSMiklos Szeredi if (res) 538334f485dSMiklos Szeredi goto err_fs_cleanup; 539334f485dSMiklos Szeredi 540d8a5ba45SMiklos Szeredi return 0; 541d8a5ba45SMiklos Szeredi 542334f485dSMiklos Szeredi err_fs_cleanup: 543334f485dSMiklos Szeredi fuse_fs_cleanup(); 544d8a5ba45SMiklos Szeredi err: 545d8a5ba45SMiklos Szeredi return res; 546d8a5ba45SMiklos Szeredi } 547d8a5ba45SMiklos Szeredi 548d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void) 549d8a5ba45SMiklos Szeredi { 550d8a5ba45SMiklos Szeredi printk(KERN_DEBUG "fuse exit\n"); 551d8a5ba45SMiklos Szeredi 552d8a5ba45SMiklos Szeredi fuse_fs_cleanup(); 553334f485dSMiklos Szeredi fuse_dev_cleanup(); 554d8a5ba45SMiklos Szeredi } 555d8a5ba45SMiklos Szeredi 556d8a5ba45SMiklos Szeredi module_init(fuse_init); 557d8a5ba45SMiklos Szeredi module_exit(fuse_exit); 558