1d8a5ba45SMiklos Szeredi /* 2d8a5ba45SMiklos Szeredi FUSE: Filesystem in Userspace 3d7133114SMiklos Szeredi Copyright (C) 2001-2006 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/seq_file.h> 15d8a5ba45SMiklos Szeredi #include <linux/init.h> 16d8a5ba45SMiklos Szeredi #include <linux/module.h> 17d8a5ba45SMiklos Szeredi #include <linux/parser.h> 18d8a5ba45SMiklos Szeredi #include <linux/statfs.h> 199c8ef561SMiklos Szeredi #include <linux/random.h> 20e8edc6e0SAlexey Dobriyan #include <linux/sched.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 26e18b890bSChristoph Lameter static struct kmem_cache *fuse_inode_cachep; 27bafa9654SMiklos Szeredi struct list_head fuse_conn_list; 28bafa9654SMiklos Szeredi DEFINE_MUTEX(fuse_mutex); 29d8a5ba45SMiklos Szeredi 30d8a5ba45SMiklos Szeredi #define FUSE_SUPER_MAGIC 0x65735546 31d8a5ba45SMiklos Szeredi 32d8a5ba45SMiklos Szeredi struct fuse_mount_data { 33d8a5ba45SMiklos Szeredi int fd; 34d8a5ba45SMiklos Szeredi unsigned rootmode; 35d8a5ba45SMiklos Szeredi unsigned user_id; 3687729a55SMiklos Szeredi unsigned group_id; 375a533682SMiklos Szeredi unsigned fd_present : 1; 385a533682SMiklos Szeredi unsigned rootmode_present : 1; 395a533682SMiklos Szeredi unsigned user_id_present : 1; 405a533682SMiklos Szeredi unsigned group_id_present : 1; 411e9a4ed9SMiklos Szeredi unsigned flags; 42db50b96cSMiklos Szeredi unsigned max_read; 43d8091614SMiklos Szeredi unsigned blksize; 44d8a5ba45SMiklos Szeredi }; 45d8a5ba45SMiklos Szeredi 46d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb) 47d8a5ba45SMiklos Szeredi { 48d8a5ba45SMiklos Szeredi struct inode *inode; 49d8a5ba45SMiklos Szeredi struct fuse_inode *fi; 50d8a5ba45SMiklos Szeredi 51e94b1766SChristoph Lameter inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); 52d8a5ba45SMiklos Szeredi if (!inode) 53d8a5ba45SMiklos Szeredi return NULL; 54d8a5ba45SMiklos Szeredi 55d8a5ba45SMiklos Szeredi fi = get_fuse_inode(inode); 560a0898cfSMiklos Szeredi fi->i_time = 0; 57d8a5ba45SMiklos Szeredi fi->nodeid = 0; 589e6268dbSMiklos Szeredi fi->nlookup = 0; 59e5e5558eSMiklos Szeredi fi->forget_req = fuse_request_alloc(); 60e5e5558eSMiklos Szeredi if (!fi->forget_req) { 61e5e5558eSMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 62e5e5558eSMiklos Szeredi return NULL; 63e5e5558eSMiklos Szeredi } 64d8a5ba45SMiklos Szeredi 65d8a5ba45SMiklos Szeredi return inode; 66d8a5ba45SMiklos Szeredi } 67d8a5ba45SMiklos Szeredi 68d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode) 69d8a5ba45SMiklos Szeredi { 70e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 71e5e5558eSMiklos Szeredi if (fi->forget_req) 72e5e5558eSMiklos Szeredi fuse_request_free(fi->forget_req); 73d8a5ba45SMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 74d8a5ba45SMiklos Szeredi } 75d8a5ba45SMiklos Szeredi 76d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode) 77d8a5ba45SMiklos Szeredi { 78d8a5ba45SMiklos Szeredi /* No op */ 79d8a5ba45SMiklos Szeredi } 80d8a5ba45SMiklos Szeredi 81e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, 829e6268dbSMiklos Szeredi unsigned long nodeid, u64 nlookup) 83e5e5558eSMiklos Szeredi { 84e5e5558eSMiklos Szeredi struct fuse_forget_in *inarg = &req->misc.forget_in; 859e6268dbSMiklos Szeredi inarg->nlookup = nlookup; 86e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_FORGET; 87e5e5558eSMiklos Szeredi req->in.h.nodeid = nodeid; 88e5e5558eSMiklos Szeredi req->in.numargs = 1; 89e5e5558eSMiklos Szeredi req->in.args[0].size = sizeof(struct fuse_forget_in); 90e5e5558eSMiklos Szeredi req->in.args[0].value = inarg; 91e5e5558eSMiklos Szeredi request_send_noreply(fc, req); 92e5e5558eSMiklos Szeredi } 93e5e5558eSMiklos Szeredi 94d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode) 95d8a5ba45SMiklos Szeredi { 961e9a4ed9SMiklos Szeredi if (inode->i_sb->s_flags & MS_ACTIVE) { 97e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 98e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 999e6268dbSMiklos Szeredi fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); 100e5e5558eSMiklos Szeredi fi->forget_req = NULL; 101e5e5558eSMiklos Szeredi } 102d8a5ba45SMiklos Szeredi } 103d8a5ba45SMiklos Szeredi 10471421259SMiklos Szeredi static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) 10571421259SMiklos Szeredi { 10671421259SMiklos Szeredi if (*flags & MS_MANDLOCK) 10771421259SMiklos Szeredi return -EINVAL; 10871421259SMiklos Szeredi 10971421259SMiklos Szeredi return 0; 11071421259SMiklos Szeredi } 11171421259SMiklos Szeredi 112*e00d2c2dSMiklos Szeredi static void fuse_truncate(struct address_space *mapping, loff_t offset) 113*e00d2c2dSMiklos Szeredi { 114*e00d2c2dSMiklos Szeredi /* See vmtruncate() */ 115*e00d2c2dSMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 116*e00d2c2dSMiklos Szeredi truncate_inode_pages(mapping, offset); 117*e00d2c2dSMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 118*e00d2c2dSMiklos Szeredi } 119*e00d2c2dSMiklos Szeredi 120d8a5ba45SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) 121d8a5ba45SMiklos Szeredi { 1229ffbb916SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 123*e00d2c2dSMiklos Szeredi loff_t oldsize; 124d8a5ba45SMiklos Szeredi 125d8a5ba45SMiklos Szeredi inode->i_ino = attr->ino; 126d8a5ba45SMiklos Szeredi inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); 127d8a5ba45SMiklos Szeredi inode->i_nlink = attr->nlink; 128d8a5ba45SMiklos Szeredi inode->i_uid = attr->uid; 129d8a5ba45SMiklos Szeredi inode->i_gid = attr->gid; 130d8a5ba45SMiklos Szeredi inode->i_blocks = attr->blocks; 131d8a5ba45SMiklos Szeredi inode->i_atime.tv_sec = attr->atime; 132d8a5ba45SMiklos Szeredi inode->i_atime.tv_nsec = attr->atimensec; 133d8a5ba45SMiklos Szeredi inode->i_mtime.tv_sec = attr->mtime; 134d8a5ba45SMiklos Szeredi inode->i_mtime.tv_nsec = attr->mtimensec; 135d8a5ba45SMiklos Szeredi inode->i_ctime.tv_sec = attr->ctime; 136d8a5ba45SMiklos Szeredi inode->i_ctime.tv_nsec = attr->ctimensec; 137*e00d2c2dSMiklos Szeredi 138*e00d2c2dSMiklos Szeredi spin_lock(&fc->lock); 139*e00d2c2dSMiklos Szeredi oldsize = inode->i_size; 140*e00d2c2dSMiklos Szeredi i_size_write(inode, attr->size); 141*e00d2c2dSMiklos Szeredi spin_unlock(&fc->lock); 142*e00d2c2dSMiklos Szeredi 143*e00d2c2dSMiklos Szeredi if (S_ISREG(inode->i_mode) && oldsize != attr->size) { 144*e00d2c2dSMiklos Szeredi if (attr->size < oldsize) 145*e00d2c2dSMiklos Szeredi fuse_truncate(inode->i_mapping, attr->size); 146*e00d2c2dSMiklos Szeredi invalidate_mapping_pages(inode->i_mapping, 0, -1); 147*e00d2c2dSMiklos Szeredi } 148d8a5ba45SMiklos Szeredi } 149d8a5ba45SMiklos Szeredi 150d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) 151d8a5ba45SMiklos Szeredi { 152d8a5ba45SMiklos Szeredi inode->i_mode = attr->mode & S_IFMT; 1539ffbb916SMiklos Szeredi inode->i_size = attr->size; 154e5e5558eSMiklos Szeredi if (S_ISREG(inode->i_mode)) { 155e5e5558eSMiklos Szeredi fuse_init_common(inode); 156b6aeadedSMiklos Szeredi fuse_init_file_inode(inode); 157e5e5558eSMiklos Szeredi } else if (S_ISDIR(inode->i_mode)) 158e5e5558eSMiklos Szeredi fuse_init_dir(inode); 159e5e5558eSMiklos Szeredi else if (S_ISLNK(inode->i_mode)) 160e5e5558eSMiklos Szeredi fuse_init_symlink(inode); 161e5e5558eSMiklos Szeredi else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || 162e5e5558eSMiklos Szeredi S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { 163e5e5558eSMiklos Szeredi fuse_init_common(inode); 164e5e5558eSMiklos Szeredi init_special_inode(inode, inode->i_mode, 165e5e5558eSMiklos Szeredi new_decode_dev(attr->rdev)); 16639ee059aSMiklos Szeredi } else 16739ee059aSMiklos Szeredi BUG(); 168d8a5ba45SMiklos Szeredi } 169d8a5ba45SMiklos Szeredi 170d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp) 171d8a5ba45SMiklos Szeredi { 172d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 173d8a5ba45SMiklos Szeredi if (get_node_id(inode) == nodeid) 174d8a5ba45SMiklos Szeredi return 1; 175d8a5ba45SMiklos Szeredi else 176d8a5ba45SMiklos Szeredi return 0; 177d8a5ba45SMiklos Szeredi } 178d8a5ba45SMiklos Szeredi 179d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp) 180d8a5ba45SMiklos Szeredi { 181d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 182d8a5ba45SMiklos Szeredi get_fuse_inode(inode)->nodeid = nodeid; 183d8a5ba45SMiklos Szeredi return 0; 184d8a5ba45SMiklos Szeredi } 185d8a5ba45SMiklos Szeredi 186d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 1879e6268dbSMiklos Szeredi int generation, struct fuse_attr *attr) 188d8a5ba45SMiklos Szeredi { 189d8a5ba45SMiklos Szeredi struct inode *inode; 1909e6268dbSMiklos Szeredi struct fuse_inode *fi; 191d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 192d8a5ba45SMiklos Szeredi 193d8a5ba45SMiklos Szeredi retry: 194d8a5ba45SMiklos Szeredi inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); 195d8a5ba45SMiklos Szeredi if (!inode) 196d8a5ba45SMiklos Szeredi return NULL; 197d8a5ba45SMiklos Szeredi 198d8a5ba45SMiklos Szeredi if ((inode->i_state & I_NEW)) { 199b36c31baSMiklos Szeredi inode->i_flags |= S_NOATIME|S_NOCMTIME; 200d8a5ba45SMiklos Szeredi inode->i_generation = generation; 201d8a5ba45SMiklos Szeredi inode->i_data.backing_dev_info = &fc->bdi; 202d8a5ba45SMiklos Szeredi fuse_init_inode(inode, attr); 203d8a5ba45SMiklos Szeredi unlock_new_inode(inode); 204d8a5ba45SMiklos Szeredi } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { 205d8a5ba45SMiklos Szeredi /* Inode has changed type, any I/O on the old should fail */ 206d8a5ba45SMiklos Szeredi make_bad_inode(inode); 207d8a5ba45SMiklos Szeredi iput(inode); 208d8a5ba45SMiklos Szeredi goto retry; 209d8a5ba45SMiklos Szeredi } 210d8a5ba45SMiklos Szeredi 2119e6268dbSMiklos Szeredi fi = get_fuse_inode(inode); 2128da5ff23SMiklos Szeredi spin_lock(&fc->lock); 2139e6268dbSMiklos Szeredi fi->nlookup ++; 2148da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 215d8a5ba45SMiklos Szeredi fuse_change_attributes(inode, attr); 216d8a5ba45SMiklos Szeredi return inode; 217d8a5ba45SMiklos Szeredi } 218d8a5ba45SMiklos Szeredi 2198b512d9aSTrond Myklebust static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) 22069a53bf2SMiklos Szeredi { 2218b512d9aSTrond Myklebust if (flags & MNT_FORCE) 2228b512d9aSTrond Myklebust fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); 22369a53bf2SMiklos Szeredi } 22469a53bf2SMiklos Szeredi 2250ec7ca41SMiklos Szeredi static void fuse_send_destroy(struct fuse_conn *fc) 2260ec7ca41SMiklos Szeredi { 2270ec7ca41SMiklos Szeredi struct fuse_req *req = fc->destroy_req; 2280ec7ca41SMiklos Szeredi if (req && fc->conn_init) { 2290ec7ca41SMiklos Szeredi fc->destroy_req = NULL; 2300ec7ca41SMiklos Szeredi req->in.h.opcode = FUSE_DESTROY; 2310ec7ca41SMiklos Szeredi req->force = 1; 2320ec7ca41SMiklos Szeredi request_send(fc, req); 2330ec7ca41SMiklos Szeredi fuse_put_request(fc, req); 2340ec7ca41SMiklos Szeredi } 2350ec7ca41SMiklos Szeredi } 2360ec7ca41SMiklos Szeredi 237d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb) 238d8a5ba45SMiklos Szeredi { 239d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 240d8a5ba45SMiklos Szeredi 2410ec7ca41SMiklos Szeredi fuse_send_destroy(fc); 242d7133114SMiklos Szeredi spin_lock(&fc->lock); 2439ba7cbbaSMiklos Szeredi fc->connected = 0; 24451eb01e7SMiklos Szeredi fc->blocked = 0; 245d7133114SMiklos Szeredi spin_unlock(&fc->lock); 246334f485dSMiklos Szeredi /* Flush all readers on this fs */ 247385a17bfSJeff Dike kill_fasync(&fc->fasync, SIGIO, POLL_IN); 248334f485dSMiklos Szeredi wake_up_all(&fc->waitq); 24951eb01e7SMiklos Szeredi wake_up_all(&fc->blocked_waitq); 250de5e3decSMiklos Szeredi wake_up_all(&fc->reserved_req_waitq); 251bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 252bafa9654SMiklos Szeredi list_del(&fc->entry); 253bafa9654SMiklos Szeredi fuse_ctl_remove_conn(fc); 254bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 255bafa9654SMiklos Szeredi fuse_conn_put(fc); 256d8a5ba45SMiklos Szeredi } 257d8a5ba45SMiklos Szeredi 258e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) 259e5e5558eSMiklos Szeredi { 260e5e5558eSMiklos Szeredi stbuf->f_type = FUSE_SUPER_MAGIC; 261e5e5558eSMiklos Szeredi stbuf->f_bsize = attr->bsize; 262de5f1202SMiklos Szeredi stbuf->f_frsize = attr->frsize; 263e5e5558eSMiklos Szeredi stbuf->f_blocks = attr->blocks; 264e5e5558eSMiklos Szeredi stbuf->f_bfree = attr->bfree; 265e5e5558eSMiklos Szeredi stbuf->f_bavail = attr->bavail; 266e5e5558eSMiklos Szeredi stbuf->f_files = attr->files; 267e5e5558eSMiklos Szeredi stbuf->f_ffree = attr->ffree; 268e5e5558eSMiklos Szeredi stbuf->f_namelen = attr->namelen; 269e5e5558eSMiklos Szeredi /* fsid is left zero */ 270e5e5558eSMiklos Szeredi } 271e5e5558eSMiklos Szeredi 272726c3342SDavid Howells static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) 273e5e5558eSMiklos Szeredi { 274726c3342SDavid Howells struct super_block *sb = dentry->d_sb; 275e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 276e5e5558eSMiklos Szeredi struct fuse_req *req; 277e5e5558eSMiklos Szeredi struct fuse_statfs_out outarg; 278e5e5558eSMiklos Szeredi int err; 279e5e5558eSMiklos Szeredi 280ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 281ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 282ce1d5a49SMiklos Szeredi return PTR_ERR(req); 283e5e5558eSMiklos Szeredi 284de5f1202SMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 285e5e5558eSMiklos Szeredi req->in.numargs = 0; 286e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_STATFS; 2875b35e8e5SMiklos Szeredi req->in.h.nodeid = get_node_id(dentry->d_inode); 288e5e5558eSMiklos Szeredi req->out.numargs = 1; 289de5f1202SMiklos Szeredi req->out.args[0].size = 290de5f1202SMiklos Szeredi fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); 291e5e5558eSMiklos Szeredi req->out.args[0].value = &outarg; 292e5e5558eSMiklos Szeredi request_send(fc, req); 293e5e5558eSMiklos Szeredi err = req->out.h.error; 294e5e5558eSMiklos Szeredi if (!err) 295e5e5558eSMiklos Szeredi convert_fuse_statfs(buf, &outarg.st); 296e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 297e5e5558eSMiklos Szeredi return err; 298e5e5558eSMiklos Szeredi } 299e5e5558eSMiklos Szeredi 300d8a5ba45SMiklos Szeredi enum { 301d8a5ba45SMiklos Szeredi OPT_FD, 302d8a5ba45SMiklos Szeredi OPT_ROOTMODE, 303d8a5ba45SMiklos Szeredi OPT_USER_ID, 30487729a55SMiklos Szeredi OPT_GROUP_ID, 305d8a5ba45SMiklos Szeredi OPT_DEFAULT_PERMISSIONS, 306d8a5ba45SMiklos Szeredi OPT_ALLOW_OTHER, 307db50b96cSMiklos Szeredi OPT_MAX_READ, 308d8091614SMiklos Szeredi OPT_BLKSIZE, 309d8a5ba45SMiklos Szeredi OPT_ERR 310d8a5ba45SMiklos Szeredi }; 311d8a5ba45SMiklos Szeredi 312d8a5ba45SMiklos Szeredi static match_table_t tokens = { 313d8a5ba45SMiklos Szeredi {OPT_FD, "fd=%u"}, 314d8a5ba45SMiklos Szeredi {OPT_ROOTMODE, "rootmode=%o"}, 315d8a5ba45SMiklos Szeredi {OPT_USER_ID, "user_id=%u"}, 31687729a55SMiklos Szeredi {OPT_GROUP_ID, "group_id=%u"}, 317d8a5ba45SMiklos Szeredi {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 318d8a5ba45SMiklos Szeredi {OPT_ALLOW_OTHER, "allow_other"}, 319db50b96cSMiklos Szeredi {OPT_MAX_READ, "max_read=%u"}, 320d8091614SMiklos Szeredi {OPT_BLKSIZE, "blksize=%u"}, 321d8a5ba45SMiklos Szeredi {OPT_ERR, NULL} 322d8a5ba45SMiklos Szeredi }; 323d8a5ba45SMiklos Szeredi 324d8091614SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) 325d8a5ba45SMiklos Szeredi { 326d8a5ba45SMiklos Szeredi char *p; 327d8a5ba45SMiklos Szeredi memset(d, 0, sizeof(struct fuse_mount_data)); 328db50b96cSMiklos Szeredi d->max_read = ~0; 329d8091614SMiklos Szeredi d->blksize = 512; 330d8a5ba45SMiklos Szeredi 331d8a5ba45SMiklos Szeredi while ((p = strsep(&opt, ",")) != NULL) { 332d8a5ba45SMiklos Szeredi int token; 333d8a5ba45SMiklos Szeredi int value; 334d8a5ba45SMiklos Szeredi substring_t args[MAX_OPT_ARGS]; 335d8a5ba45SMiklos Szeredi if (!*p) 336d8a5ba45SMiklos Szeredi continue; 337d8a5ba45SMiklos Szeredi 338d8a5ba45SMiklos Szeredi token = match_token(p, tokens, args); 339d8a5ba45SMiklos Szeredi switch (token) { 340d8a5ba45SMiklos Szeredi case OPT_FD: 341d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 342d8a5ba45SMiklos Szeredi return 0; 343d8a5ba45SMiklos Szeredi d->fd = value; 3445a533682SMiklos Szeredi d->fd_present = 1; 345d8a5ba45SMiklos Szeredi break; 346d8a5ba45SMiklos Szeredi 347d8a5ba45SMiklos Szeredi case OPT_ROOTMODE: 348d8a5ba45SMiklos Szeredi if (match_octal(&args[0], &value)) 349d8a5ba45SMiklos Szeredi return 0; 350a5bfffacSTimo Savola if (!fuse_valid_type(value)) 351a5bfffacSTimo Savola return 0; 352d8a5ba45SMiklos Szeredi d->rootmode = value; 3535a533682SMiklos Szeredi d->rootmode_present = 1; 354d8a5ba45SMiklos Szeredi break; 355d8a5ba45SMiklos Szeredi 356d8a5ba45SMiklos Szeredi case OPT_USER_ID: 357d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 358d8a5ba45SMiklos Szeredi return 0; 359d8a5ba45SMiklos Szeredi d->user_id = value; 3605a533682SMiklos Szeredi d->user_id_present = 1; 361d8a5ba45SMiklos Szeredi break; 362d8a5ba45SMiklos Szeredi 36387729a55SMiklos Szeredi case OPT_GROUP_ID: 36487729a55SMiklos Szeredi if (match_int(&args[0], &value)) 36587729a55SMiklos Szeredi return 0; 36687729a55SMiklos Szeredi d->group_id = value; 3675a533682SMiklos Szeredi d->group_id_present = 1; 36887729a55SMiklos Szeredi break; 36987729a55SMiklos Szeredi 3701e9a4ed9SMiklos Szeredi case OPT_DEFAULT_PERMISSIONS: 3711e9a4ed9SMiklos Szeredi d->flags |= FUSE_DEFAULT_PERMISSIONS; 3721e9a4ed9SMiklos Szeredi break; 3731e9a4ed9SMiklos Szeredi 3741e9a4ed9SMiklos Szeredi case OPT_ALLOW_OTHER: 3751e9a4ed9SMiklos Szeredi d->flags |= FUSE_ALLOW_OTHER; 3761e9a4ed9SMiklos Szeredi break; 3771e9a4ed9SMiklos Szeredi 378db50b96cSMiklos Szeredi case OPT_MAX_READ: 379db50b96cSMiklos Szeredi if (match_int(&args[0], &value)) 380db50b96cSMiklos Szeredi return 0; 381db50b96cSMiklos Szeredi d->max_read = value; 382db50b96cSMiklos Szeredi break; 383db50b96cSMiklos Szeredi 384d8091614SMiklos Szeredi case OPT_BLKSIZE: 385d8091614SMiklos Szeredi if (!is_bdev || match_int(&args[0], &value)) 386d8091614SMiklos Szeredi return 0; 387d8091614SMiklos Szeredi d->blksize = value; 388d8091614SMiklos Szeredi break; 389d8091614SMiklos Szeredi 390d8a5ba45SMiklos Szeredi default: 391d8a5ba45SMiklos Szeredi return 0; 392d8a5ba45SMiklos Szeredi } 393d8a5ba45SMiklos Szeredi } 3945a533682SMiklos Szeredi 3955a533682SMiklos Szeredi if (!d->fd_present || !d->rootmode_present || 3965a533682SMiklos Szeredi !d->user_id_present || !d->group_id_present) 397d8a5ba45SMiklos Szeredi return 0; 398d8a5ba45SMiklos Szeredi 399d8a5ba45SMiklos Szeredi return 1; 400d8a5ba45SMiklos Szeredi } 401d8a5ba45SMiklos Szeredi 402d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) 403d8a5ba45SMiklos Szeredi { 404d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 405d8a5ba45SMiklos Szeredi 406d8a5ba45SMiklos Szeredi seq_printf(m, ",user_id=%u", fc->user_id); 40787729a55SMiklos Szeredi seq_printf(m, ",group_id=%u", fc->group_id); 4081e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) 4091e9a4ed9SMiklos Szeredi seq_puts(m, ",default_permissions"); 4101e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 4111e9a4ed9SMiklos Szeredi seq_puts(m, ",allow_other"); 412db50b96cSMiklos Szeredi if (fc->max_read != ~0) 413db50b96cSMiklos Szeredi seq_printf(m, ",max_read=%u", fc->max_read); 414d8a5ba45SMiklos Szeredi return 0; 415d8a5ba45SMiklos Szeredi } 416d8a5ba45SMiklos Szeredi 417d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void) 418d8a5ba45SMiklos Szeredi { 419d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 420e0bf68ddSPeter Zijlstra int err; 421d8a5ba45SMiklos Szeredi 4226383bdaaSMiklos Szeredi fc = kzalloc(sizeof(*fc), GFP_KERNEL); 423f543f253SMiklos Szeredi if (fc) { 424d7133114SMiklos Szeredi spin_lock_init(&fc->lock); 425d2a85164SMiklos Szeredi mutex_init(&fc->inst_mutex); 426bafa9654SMiklos Szeredi atomic_set(&fc->count, 1); 427334f485dSMiklos Szeredi init_waitqueue_head(&fc->waitq); 42808a53cdcSMiklos Szeredi init_waitqueue_head(&fc->blocked_waitq); 429de5e3decSMiklos Szeredi init_waitqueue_head(&fc->reserved_req_waitq); 430334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->pending); 431334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->processing); 432d77a1d5bSMiklos Szeredi INIT_LIST_HEAD(&fc->io); 433a4d27e75SMiklos Szeredi INIT_LIST_HEAD(&fc->interrupts); 434095da6cbSMiklos Szeredi atomic_set(&fc->num_waiting, 0); 435d8a5ba45SMiklos Szeredi fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 436d8a5ba45SMiklos Szeredi fc->bdi.unplug_io_fn = default_unplug_io_fn; 437e0bf68ddSPeter Zijlstra err = bdi_init(&fc->bdi); 438e0bf68ddSPeter Zijlstra if (err) { 439e0bf68ddSPeter Zijlstra kfree(fc); 440e0bf68ddSPeter Zijlstra fc = NULL; 441e0bf68ddSPeter Zijlstra goto out; 442e0bf68ddSPeter Zijlstra } 443334f485dSMiklos Szeredi fc->reqctr = 0; 44408a53cdcSMiklos Szeredi fc->blocked = 1; 4459c8ef561SMiklos Szeredi get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); 446d8a5ba45SMiklos Szeredi } 447e0bf68ddSPeter Zijlstra out: 448d8a5ba45SMiklos Szeredi return fc; 449d8a5ba45SMiklos Szeredi } 450d8a5ba45SMiklos Szeredi 451bafa9654SMiklos Szeredi void fuse_conn_put(struct fuse_conn *fc) 452bafa9654SMiklos Szeredi { 453d2a85164SMiklos Szeredi if (atomic_dec_and_test(&fc->count)) { 4540ec7ca41SMiklos Szeredi if (fc->destroy_req) 4550ec7ca41SMiklos Szeredi fuse_request_free(fc->destroy_req); 456d2a85164SMiklos Szeredi mutex_destroy(&fc->inst_mutex); 457e0bf68ddSPeter Zijlstra bdi_destroy(&fc->bdi); 458bafa9654SMiklos Szeredi kfree(fc); 459bafa9654SMiklos Szeredi } 460d2a85164SMiklos Szeredi } 461bafa9654SMiklos Szeredi 462bafa9654SMiklos Szeredi struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) 463bafa9654SMiklos Szeredi { 464bafa9654SMiklos Szeredi atomic_inc(&fc->count); 465bafa9654SMiklos Szeredi return fc; 466bafa9654SMiklos Szeredi } 467bafa9654SMiklos Szeredi 468d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode) 469d8a5ba45SMiklos Szeredi { 470d8a5ba45SMiklos Szeredi struct fuse_attr attr; 471d8a5ba45SMiklos Szeredi memset(&attr, 0, sizeof(attr)); 472d8a5ba45SMiklos Szeredi 473d8a5ba45SMiklos Szeredi attr.mode = mode; 474d8a5ba45SMiklos Szeredi attr.ino = FUSE_ROOT_ID; 4759e6268dbSMiklos Szeredi return fuse_iget(sb, 1, 0, &attr); 476d8a5ba45SMiklos Szeredi } 477d8a5ba45SMiklos Szeredi 478ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = { 479d8a5ba45SMiklos Szeredi .alloc_inode = fuse_alloc_inode, 480d8a5ba45SMiklos Szeredi .destroy_inode = fuse_destroy_inode, 481d8a5ba45SMiklos Szeredi .read_inode = fuse_read_inode, 482d8a5ba45SMiklos Szeredi .clear_inode = fuse_clear_inode, 483ead5f0b5SMiklos Szeredi .drop_inode = generic_delete_inode, 48471421259SMiklos Szeredi .remount_fs = fuse_remount_fs, 485d8a5ba45SMiklos Szeredi .put_super = fuse_put_super, 48669a53bf2SMiklos Szeredi .umount_begin = fuse_umount_begin, 487e5e5558eSMiklos Szeredi .statfs = fuse_statfs, 488d8a5ba45SMiklos Szeredi .show_options = fuse_show_options, 489d8a5ba45SMiklos Szeredi }; 490d8a5ba45SMiklos Szeredi 4919b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) 4929b9a0469SMiklos Szeredi { 4939b9a0469SMiklos Szeredi struct fuse_init_out *arg = &req->misc.init_out; 4949b9a0469SMiklos Szeredi 4959b9a0469SMiklos Szeredi if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) 4969b9a0469SMiklos Szeredi fc->conn_error = 1; 4979b9a0469SMiklos Szeredi else { 4989cd68455SMiklos Szeredi unsigned long ra_pages; 4999cd68455SMiklos Szeredi 5009cd68455SMiklos Szeredi if (arg->minor >= 6) { 5019cd68455SMiklos Szeredi ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; 5029cd68455SMiklos Szeredi if (arg->flags & FUSE_ASYNC_READ) 5039cd68455SMiklos Szeredi fc->async_read = 1; 50471421259SMiklos Szeredi if (!(arg->flags & FUSE_POSIX_LOCKS)) 50571421259SMiklos Szeredi fc->no_lock = 1; 50671421259SMiklos Szeredi } else { 5079cd68455SMiklos Szeredi ra_pages = fc->max_read / PAGE_CACHE_SIZE; 50871421259SMiklos Szeredi fc->no_lock = 1; 50971421259SMiklos Szeredi } 5109cd68455SMiklos Szeredi 5119cd68455SMiklos Szeredi fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); 5129b9a0469SMiklos Szeredi fc->minor = arg->minor; 5139b9a0469SMiklos Szeredi fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; 5140ec7ca41SMiklos Szeredi fc->conn_init = 1; 5159b9a0469SMiklos Szeredi } 5169b9a0469SMiklos Szeredi fuse_put_request(fc, req); 51708a53cdcSMiklos Szeredi fc->blocked = 0; 51808a53cdcSMiklos Szeredi wake_up_all(&fc->blocked_waitq); 5199b9a0469SMiklos Szeredi } 5209b9a0469SMiklos Szeredi 521ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) 5229b9a0469SMiklos Szeredi { 5239b9a0469SMiklos Szeredi struct fuse_init_in *arg = &req->misc.init_in; 524095da6cbSMiklos Szeredi 5259b9a0469SMiklos Szeredi arg->major = FUSE_KERNEL_VERSION; 5269b9a0469SMiklos Szeredi arg->minor = FUSE_KERNEL_MINOR_VERSION; 5279cd68455SMiklos Szeredi arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; 52871421259SMiklos Szeredi arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; 5299b9a0469SMiklos Szeredi req->in.h.opcode = FUSE_INIT; 5309b9a0469SMiklos Szeredi req->in.numargs = 1; 5319b9a0469SMiklos Szeredi req->in.args[0].size = sizeof(*arg); 5329b9a0469SMiklos Szeredi req->in.args[0].value = arg; 5339b9a0469SMiklos Szeredi req->out.numargs = 1; 5349b9a0469SMiklos Szeredi /* Variable length arguement used for backward compatibility 5359b9a0469SMiklos Szeredi with interface version < 7.5. Rest of init_out is zeroed 5369b9a0469SMiklos Szeredi by do_get_request(), so a short reply is not a problem */ 5379b9a0469SMiklos Szeredi req->out.argvar = 1; 5389b9a0469SMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_init_out); 5399b9a0469SMiklos Szeredi req->out.args[0].value = &req->misc.init_out; 5409b9a0469SMiklos Szeredi req->end = process_init_reply; 5419b9a0469SMiklos Szeredi request_send_background(fc, req); 5429b9a0469SMiklos Szeredi } 5439b9a0469SMiklos Szeredi 544bafa9654SMiklos Szeredi static u64 conn_id(void) 545f543f253SMiklos Szeredi { 546bafa9654SMiklos Szeredi static u64 ctr = 1; 5470720b315SMiklos Szeredi return ctr++; 548f543f253SMiklos Szeredi } 549f543f253SMiklos Szeredi 550d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent) 551d8a5ba45SMiklos Szeredi { 552d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 553d8a5ba45SMiklos Szeredi struct inode *root; 554d8a5ba45SMiklos Szeredi struct fuse_mount_data d; 555d8a5ba45SMiklos Szeredi struct file *file; 556f543f253SMiklos Szeredi struct dentry *root_dentry; 557ce1d5a49SMiklos Szeredi struct fuse_req *init_req; 558d8a5ba45SMiklos Szeredi int err; 559d8091614SMiklos Szeredi int is_bdev = sb->s_bdev != NULL; 560d8a5ba45SMiklos Szeredi 56171421259SMiklos Szeredi if (sb->s_flags & MS_MANDLOCK) 56271421259SMiklos Szeredi return -EINVAL; 56371421259SMiklos Szeredi 564d8091614SMiklos Szeredi if (!parse_fuse_opt((char *) data, &d, is_bdev)) 565d8a5ba45SMiklos Szeredi return -EINVAL; 566d8a5ba45SMiklos Szeredi 567d8091614SMiklos Szeredi if (is_bdev) { 568875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 569d8091614SMiklos Szeredi if (!sb_set_blocksize(sb, d.blksize)) 570d8091614SMiklos Szeredi return -EINVAL; 571875d95ecSMiklos Szeredi #endif 572d8091614SMiklos Szeredi } else { 573d8a5ba45SMiklos Szeredi sb->s_blocksize = PAGE_CACHE_SIZE; 574d8a5ba45SMiklos Szeredi sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 575d8091614SMiklos Szeredi } 576d8a5ba45SMiklos Szeredi sb->s_magic = FUSE_SUPER_MAGIC; 577d8a5ba45SMiklos Szeredi sb->s_op = &fuse_super_operations; 578d8a5ba45SMiklos Szeredi sb->s_maxbytes = MAX_LFS_FILESIZE; 579d8a5ba45SMiklos Szeredi 580d8a5ba45SMiklos Szeredi file = fget(d.fd); 581d8a5ba45SMiklos Szeredi if (!file) 582d8a5ba45SMiklos Szeredi return -EINVAL; 583d8a5ba45SMiklos Szeredi 5840720b315SMiklos Szeredi if (file->f_op != &fuse_dev_operations) 5850720b315SMiklos Szeredi return -EINVAL; 5860720b315SMiklos Szeredi 5870720b315SMiklos Szeredi fc = new_conn(); 5880720b315SMiklos Szeredi if (!fc) 5890720b315SMiklos Szeredi return -ENOMEM; 590d8a5ba45SMiklos Szeredi 5911e9a4ed9SMiklos Szeredi fc->flags = d.flags; 592d8a5ba45SMiklos Szeredi fc->user_id = d.user_id; 59387729a55SMiklos Szeredi fc->group_id = d.group_id; 594db50b96cSMiklos Szeredi fc->max_read = d.max_read; 595d8a5ba45SMiklos Szeredi 596f543f253SMiklos Szeredi /* Used by get_root_inode() */ 597f543f253SMiklos Szeredi sb->s_fs_info = fc; 598f543f253SMiklos Szeredi 599d8a5ba45SMiklos Szeredi err = -ENOMEM; 600d8a5ba45SMiklos Szeredi root = get_root_inode(sb, d.rootmode); 601f543f253SMiklos Szeredi if (!root) 602d8a5ba45SMiklos Szeredi goto err; 603d8a5ba45SMiklos Szeredi 604f543f253SMiklos Szeredi root_dentry = d_alloc_root(root); 605f543f253SMiklos Szeredi if (!root_dentry) { 606d8a5ba45SMiklos Szeredi iput(root); 607d8a5ba45SMiklos Szeredi goto err; 608d8a5ba45SMiklos Szeredi } 609f543f253SMiklos Szeredi 610ce1d5a49SMiklos Szeredi init_req = fuse_request_alloc(); 611ce1d5a49SMiklos Szeredi if (!init_req) 612ce1d5a49SMiklos Szeredi goto err_put_root; 613ce1d5a49SMiklos Szeredi 6140ec7ca41SMiklos Szeredi if (is_bdev) { 6150ec7ca41SMiklos Szeredi fc->destroy_req = fuse_request_alloc(); 6160ec7ca41SMiklos Szeredi if (!fc->destroy_req) 6170ec7ca41SMiklos Szeredi goto err_put_root; 6180ec7ca41SMiklos Szeredi } 6190ec7ca41SMiklos Szeredi 620bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 6218aa09a50SMiklos Szeredi err = -EINVAL; 6228aa09a50SMiklos Szeredi if (file->private_data) 623bafa9654SMiklos Szeredi goto err_unlock; 6248aa09a50SMiklos Szeredi 625bafa9654SMiklos Szeredi fc->id = conn_id(); 626bafa9654SMiklos Szeredi err = fuse_ctl_add_conn(fc); 627bafa9654SMiklos Szeredi if (err) 628bafa9654SMiklos Szeredi goto err_unlock; 629bafa9654SMiklos Szeredi 630bafa9654SMiklos Szeredi list_add_tail(&fc->entry, &fuse_conn_list); 631f543f253SMiklos Szeredi sb->s_root = root_dentry; 632f543f253SMiklos Szeredi fc->connected = 1; 633bafa9654SMiklos Szeredi file->private_data = fuse_conn_get(fc); 634bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 6350720b315SMiklos Szeredi /* 6360720b315SMiklos Szeredi * atomic_dec_and_test() in fput() provides the necessary 6370720b315SMiklos Szeredi * memory barrier for file->private_data to be visible on all 6380720b315SMiklos Szeredi * CPUs after this 6390720b315SMiklos Szeredi */ 6400720b315SMiklos Szeredi fput(file); 641f543f253SMiklos Szeredi 642ce1d5a49SMiklos Szeredi fuse_send_init(fc, init_req); 643f543f253SMiklos Szeredi 644d8a5ba45SMiklos Szeredi return 0; 645d8a5ba45SMiklos Szeredi 646bafa9654SMiklos Szeredi err_unlock: 647bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 648ce1d5a49SMiklos Szeredi fuse_request_free(init_req); 649f543f253SMiklos Szeredi err_put_root: 650f543f253SMiklos Szeredi dput(root_dentry); 651d8a5ba45SMiklos Szeredi err: 6520720b315SMiklos Szeredi fput(file); 653bafa9654SMiklos Szeredi fuse_conn_put(fc); 654d8a5ba45SMiklos Szeredi return err; 655d8a5ba45SMiklos Szeredi } 656d8a5ba45SMiklos Szeredi 657454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type, 658d8a5ba45SMiklos Szeredi int flags, const char *dev_name, 659454e2398SDavid Howells void *raw_data, struct vfsmount *mnt) 660d8a5ba45SMiklos Szeredi { 661454e2398SDavid Howells return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); 662d8a5ba45SMiklos Szeredi } 663d8a5ba45SMiklos Szeredi 664875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = { 665875d95ecSMiklos Szeredi .owner = THIS_MODULE, 666875d95ecSMiklos Szeredi .name = "fuse", 66779c0b2dfSMiklos Szeredi .fs_flags = FS_HAS_SUBTYPE, 668875d95ecSMiklos Szeredi .get_sb = fuse_get_sb, 669875d95ecSMiklos Szeredi .kill_sb = kill_anon_super, 670875d95ecSMiklos Szeredi }; 671875d95ecSMiklos Szeredi 672875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 673d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type, 674d6392f87SMiklos Szeredi int flags, const char *dev_name, 675d6392f87SMiklos Szeredi void *raw_data, struct vfsmount *mnt) 676d6392f87SMiklos Szeredi { 677d6392f87SMiklos Szeredi return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, 678d6392f87SMiklos Szeredi mnt); 679d6392f87SMiklos Szeredi } 680d6392f87SMiklos Szeredi 681d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = { 682d6392f87SMiklos Szeredi .owner = THIS_MODULE, 683d6392f87SMiklos Szeredi .name = "fuseblk", 684d6392f87SMiklos Szeredi .get_sb = fuse_get_sb_blk, 685d6392f87SMiklos Szeredi .kill_sb = kill_block_super, 686edad01e2SAlexey Dobriyan .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, 687d6392f87SMiklos Szeredi }; 688d6392f87SMiklos Szeredi 689875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 690875d95ecSMiklos Szeredi { 691875d95ecSMiklos Szeredi return register_filesystem(&fuseblk_fs_type); 692875d95ecSMiklos Szeredi } 693875d95ecSMiklos Szeredi 694875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 695875d95ecSMiklos Szeredi { 696875d95ecSMiklos Szeredi unregister_filesystem(&fuseblk_fs_type); 697875d95ecSMiklos Szeredi } 698875d95ecSMiklos Szeredi #else 699875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 700875d95ecSMiklos Szeredi { 701875d95ecSMiklos Szeredi return 0; 702875d95ecSMiklos Szeredi } 703875d95ecSMiklos Szeredi 704875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 705875d95ecSMiklos Szeredi { 706875d95ecSMiklos Szeredi } 707875d95ecSMiklos Szeredi #endif 708875d95ecSMiklos Szeredi 709f543f253SMiklos Szeredi static decl_subsys(fuse, NULL, NULL); 710bafa9654SMiklos Szeredi static decl_subsys(connections, NULL, NULL); 711f543f253SMiklos Szeredi 7124ba9b9d0SChristoph Lameter static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo) 713d8a5ba45SMiklos Szeredi { 714d8a5ba45SMiklos Szeredi struct inode * inode = foo; 715d8a5ba45SMiklos Szeredi 716d8a5ba45SMiklos Szeredi inode_init_once(inode); 717d8a5ba45SMiklos Szeredi } 718d8a5ba45SMiklos Szeredi 719d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void) 720d8a5ba45SMiklos Szeredi { 721d8a5ba45SMiklos Szeredi int err; 722d8a5ba45SMiklos Szeredi 723d8a5ba45SMiklos Szeredi err = register_filesystem(&fuse_fs_type); 724d8a5ba45SMiklos Szeredi if (err) 725d6392f87SMiklos Szeredi goto out; 726d6392f87SMiklos Szeredi 727875d95ecSMiklos Szeredi err = register_fuseblk(); 728d6392f87SMiklos Szeredi if (err) 729d6392f87SMiklos Szeredi goto out_unreg; 730d6392f87SMiklos Szeredi 731d8a5ba45SMiklos Szeredi fuse_inode_cachep = kmem_cache_create("fuse_inode", 732d8a5ba45SMiklos Szeredi sizeof(struct fuse_inode), 733d8a5ba45SMiklos Szeredi 0, SLAB_HWCACHE_ALIGN, 73420c2df83SPaul Mundt fuse_inode_init_once); 735d8a5ba45SMiklos Szeredi err = -ENOMEM; 736d6392f87SMiklos Szeredi if (!fuse_inode_cachep) 737d6392f87SMiklos Szeredi goto out_unreg2; 738d8a5ba45SMiklos Szeredi 739d6392f87SMiklos Szeredi return 0; 740d6392f87SMiklos Szeredi 741d6392f87SMiklos Szeredi out_unreg2: 742875d95ecSMiklos Szeredi unregister_fuseblk(); 743d6392f87SMiklos Szeredi out_unreg: 744d6392f87SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 745d6392f87SMiklos Szeredi out: 746d8a5ba45SMiklos Szeredi return err; 747d8a5ba45SMiklos Szeredi } 748d8a5ba45SMiklos Szeredi 749d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void) 750d8a5ba45SMiklos Szeredi { 751d8a5ba45SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 752875d95ecSMiklos Szeredi unregister_fuseblk(); 753d8a5ba45SMiklos Szeredi kmem_cache_destroy(fuse_inode_cachep); 754d8a5ba45SMiklos Szeredi } 755d8a5ba45SMiklos Szeredi 756f543f253SMiklos Szeredi static int fuse_sysfs_init(void) 757f543f253SMiklos Szeredi { 758f543f253SMiklos Szeredi int err; 759f543f253SMiklos Szeredi 760823bccfcSGreg Kroah-Hartman kobj_set_kset_s(&fuse_subsys, fs_subsys); 761f543f253SMiklos Szeredi err = subsystem_register(&fuse_subsys); 762f543f253SMiklos Szeredi if (err) 763f543f253SMiklos Szeredi goto out_err; 764f543f253SMiklos Szeredi 765823bccfcSGreg Kroah-Hartman kobj_set_kset_s(&connections_subsys, fuse_subsys); 766f543f253SMiklos Szeredi err = subsystem_register(&connections_subsys); 767f543f253SMiklos Szeredi if (err) 768f543f253SMiklos Szeredi goto out_fuse_unregister; 769f543f253SMiklos Szeredi 770f543f253SMiklos Szeredi return 0; 771f543f253SMiklos Szeredi 772f543f253SMiklos Szeredi out_fuse_unregister: 773f543f253SMiklos Szeredi subsystem_unregister(&fuse_subsys); 774f543f253SMiklos Szeredi out_err: 775f543f253SMiklos Szeredi return err; 776f543f253SMiklos Szeredi } 777f543f253SMiklos Szeredi 778f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void) 779f543f253SMiklos Szeredi { 780f543f253SMiklos Szeredi subsystem_unregister(&connections_subsys); 781f543f253SMiklos Szeredi subsystem_unregister(&fuse_subsys); 782f543f253SMiklos Szeredi } 783f543f253SMiklos Szeredi 784d8a5ba45SMiklos Szeredi static int __init fuse_init(void) 785d8a5ba45SMiklos Szeredi { 786d8a5ba45SMiklos Szeredi int res; 787d8a5ba45SMiklos Szeredi 788d8a5ba45SMiklos Szeredi printk("fuse init (API version %i.%i)\n", 789d8a5ba45SMiklos Szeredi FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 790d8a5ba45SMiklos Szeredi 791bafa9654SMiklos Szeredi INIT_LIST_HEAD(&fuse_conn_list); 792d8a5ba45SMiklos Szeredi res = fuse_fs_init(); 793d8a5ba45SMiklos Szeredi if (res) 794d8a5ba45SMiklos Szeredi goto err; 795d8a5ba45SMiklos Szeredi 796334f485dSMiklos Szeredi res = fuse_dev_init(); 797334f485dSMiklos Szeredi if (res) 798334f485dSMiklos Szeredi goto err_fs_cleanup; 799334f485dSMiklos Szeredi 800f543f253SMiklos Szeredi res = fuse_sysfs_init(); 801f543f253SMiklos Szeredi if (res) 802f543f253SMiklos Szeredi goto err_dev_cleanup; 803f543f253SMiklos Szeredi 804bafa9654SMiklos Szeredi res = fuse_ctl_init(); 805bafa9654SMiklos Szeredi if (res) 806bafa9654SMiklos Szeredi goto err_sysfs_cleanup; 807bafa9654SMiklos Szeredi 808d8a5ba45SMiklos Szeredi return 0; 809d8a5ba45SMiklos Szeredi 810bafa9654SMiklos Szeredi err_sysfs_cleanup: 811bafa9654SMiklos Szeredi fuse_sysfs_cleanup(); 812f543f253SMiklos Szeredi err_dev_cleanup: 813f543f253SMiklos Szeredi fuse_dev_cleanup(); 814334f485dSMiklos Szeredi err_fs_cleanup: 815334f485dSMiklos Szeredi fuse_fs_cleanup(); 816d8a5ba45SMiklos Szeredi err: 817d8a5ba45SMiklos Szeredi return res; 818d8a5ba45SMiklos Szeredi } 819d8a5ba45SMiklos Szeredi 820d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void) 821d8a5ba45SMiklos Szeredi { 822d8a5ba45SMiklos Szeredi printk(KERN_DEBUG "fuse exit\n"); 823d8a5ba45SMiklos Szeredi 824bafa9654SMiklos Szeredi fuse_ctl_cleanup(); 825f543f253SMiklos Szeredi fuse_sysfs_cleanup(); 826d8a5ba45SMiklos Szeredi fuse_fs_cleanup(); 827334f485dSMiklos Szeredi fuse_dev_cleanup(); 828d8a5ba45SMiklos Szeredi } 829d8a5ba45SMiklos Szeredi 830d8a5ba45SMiklos Szeredi module_init(fuse_init); 831d8a5ba45SMiklos Szeredi module_exit(fuse_exit); 832