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> 20d8a5ba45SMiklos Szeredi 21d8a5ba45SMiklos Szeredi MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); 22d8a5ba45SMiklos Szeredi MODULE_DESCRIPTION("Filesystem in Userspace"); 23d8a5ba45SMiklos Szeredi MODULE_LICENSE("GPL"); 24d8a5ba45SMiklos Szeredi 25e18b890bSChristoph Lameter static struct kmem_cache *fuse_inode_cachep; 26bafa9654SMiklos Szeredi struct list_head fuse_conn_list; 27bafa9654SMiklos Szeredi DEFINE_MUTEX(fuse_mutex); 28d8a5ba45SMiklos Szeredi 29d8a5ba45SMiklos Szeredi #define FUSE_SUPER_MAGIC 0x65735546 30d8a5ba45SMiklos Szeredi 31d8a5ba45SMiklos Szeredi struct fuse_mount_data { 32d8a5ba45SMiklos Szeredi int fd; 33d8a5ba45SMiklos Szeredi unsigned rootmode; 34d8a5ba45SMiklos Szeredi unsigned user_id; 3587729a55SMiklos Szeredi unsigned group_id; 365a533682SMiklos Szeredi unsigned fd_present : 1; 375a533682SMiklos Szeredi unsigned rootmode_present : 1; 385a533682SMiklos Szeredi unsigned user_id_present : 1; 395a533682SMiklos Szeredi unsigned group_id_present : 1; 401e9a4ed9SMiklos Szeredi unsigned flags; 41db50b96cSMiklos Szeredi unsigned max_read; 42d8091614SMiklos Szeredi unsigned blksize; 43d8a5ba45SMiklos Szeredi }; 44d8a5ba45SMiklos Szeredi 45d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb) 46d8a5ba45SMiklos Szeredi { 47d8a5ba45SMiklos Szeredi struct inode *inode; 48d8a5ba45SMiklos Szeredi struct fuse_inode *fi; 49d8a5ba45SMiklos Szeredi 50e94b1766SChristoph Lameter inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); 51d8a5ba45SMiklos Szeredi if (!inode) 52d8a5ba45SMiklos Szeredi return NULL; 53d8a5ba45SMiklos Szeredi 54d8a5ba45SMiklos Szeredi fi = get_fuse_inode(inode); 550a0898cfSMiklos Szeredi fi->i_time = 0; 56d8a5ba45SMiklos Szeredi fi->nodeid = 0; 579e6268dbSMiklos Szeredi fi->nlookup = 0; 58e5e5558eSMiklos Szeredi fi->forget_req = fuse_request_alloc(); 59e5e5558eSMiklos Szeredi if (!fi->forget_req) { 60e5e5558eSMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 61e5e5558eSMiklos Szeredi return NULL; 62e5e5558eSMiklos Szeredi } 63d8a5ba45SMiklos Szeredi 64d8a5ba45SMiklos Szeredi return inode; 65d8a5ba45SMiklos Szeredi } 66d8a5ba45SMiklos Szeredi 67d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode) 68d8a5ba45SMiklos Szeredi { 69e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 70e5e5558eSMiklos Szeredi if (fi->forget_req) 71e5e5558eSMiklos Szeredi fuse_request_free(fi->forget_req); 72d8a5ba45SMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 73d8a5ba45SMiklos Szeredi } 74d8a5ba45SMiklos Szeredi 75d8a5ba45SMiklos Szeredi static void fuse_read_inode(struct inode *inode) 76d8a5ba45SMiklos Szeredi { 77d8a5ba45SMiklos Szeredi /* No op */ 78d8a5ba45SMiklos Szeredi } 79d8a5ba45SMiklos Szeredi 80e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, 819e6268dbSMiklos Szeredi unsigned long nodeid, u64 nlookup) 82e5e5558eSMiklos Szeredi { 83e5e5558eSMiklos Szeredi struct fuse_forget_in *inarg = &req->misc.forget_in; 849e6268dbSMiklos Szeredi inarg->nlookup = nlookup; 85e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_FORGET; 86e5e5558eSMiklos Szeredi req->in.h.nodeid = nodeid; 87e5e5558eSMiklos Szeredi req->in.numargs = 1; 88e5e5558eSMiklos Szeredi req->in.args[0].size = sizeof(struct fuse_forget_in); 89e5e5558eSMiklos Szeredi req->in.args[0].value = inarg; 90e5e5558eSMiklos Szeredi request_send_noreply(fc, req); 91e5e5558eSMiklos Szeredi } 92e5e5558eSMiklos Szeredi 93d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode) 94d8a5ba45SMiklos Szeredi { 951e9a4ed9SMiklos Szeredi if (inode->i_sb->s_flags & MS_ACTIVE) { 96e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 97e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 989e6268dbSMiklos Szeredi fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); 99e5e5558eSMiklos Szeredi fi->forget_req = NULL; 100e5e5558eSMiklos Szeredi } 101d8a5ba45SMiklos Szeredi } 102d8a5ba45SMiklos Szeredi 10371421259SMiklos Szeredi static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) 10471421259SMiklos Szeredi { 10571421259SMiklos Szeredi if (*flags & MS_MANDLOCK) 10671421259SMiklos Szeredi return -EINVAL; 10771421259SMiklos Szeredi 10871421259SMiklos Szeredi return 0; 10971421259SMiklos Szeredi } 11071421259SMiklos Szeredi 111d8a5ba45SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) 112d8a5ba45SMiklos Szeredi { 1139ffbb916SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 114d8a5ba45SMiklos Szeredi if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) 115fc0ecff6SAndrew Morton invalidate_mapping_pages(inode->i_mapping, 0, -1); 116d8a5ba45SMiklos Szeredi 117d8a5ba45SMiklos Szeredi inode->i_ino = attr->ino; 118d8a5ba45SMiklos Szeredi inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); 119d8a5ba45SMiklos Szeredi inode->i_nlink = attr->nlink; 120d8a5ba45SMiklos Szeredi inode->i_uid = attr->uid; 121d8a5ba45SMiklos Szeredi inode->i_gid = attr->gid; 1229ffbb916SMiklos Szeredi spin_lock(&fc->lock); 123d8a5ba45SMiklos Szeredi i_size_write(inode, attr->size); 1249ffbb916SMiklos Szeredi spin_unlock(&fc->lock); 125d8a5ba45SMiklos Szeredi inode->i_blocks = attr->blocks; 126d8a5ba45SMiklos Szeredi inode->i_atime.tv_sec = attr->atime; 127d8a5ba45SMiklos Szeredi inode->i_atime.tv_nsec = attr->atimensec; 128d8a5ba45SMiklos Szeredi inode->i_mtime.tv_sec = attr->mtime; 129d8a5ba45SMiklos Szeredi inode->i_mtime.tv_nsec = attr->mtimensec; 130d8a5ba45SMiklos Szeredi inode->i_ctime.tv_sec = attr->ctime; 131d8a5ba45SMiklos Szeredi inode->i_ctime.tv_nsec = attr->ctimensec; 132d8a5ba45SMiklos Szeredi } 133d8a5ba45SMiklos Szeredi 134d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) 135d8a5ba45SMiklos Szeredi { 136d8a5ba45SMiklos Szeredi inode->i_mode = attr->mode & S_IFMT; 1379ffbb916SMiklos Szeredi inode->i_size = attr->size; 138e5e5558eSMiklos Szeredi if (S_ISREG(inode->i_mode)) { 139e5e5558eSMiklos Szeredi fuse_init_common(inode); 140b6aeadedSMiklos Szeredi fuse_init_file_inode(inode); 141e5e5558eSMiklos Szeredi } else if (S_ISDIR(inode->i_mode)) 142e5e5558eSMiklos Szeredi fuse_init_dir(inode); 143e5e5558eSMiklos Szeredi else if (S_ISLNK(inode->i_mode)) 144e5e5558eSMiklos Szeredi fuse_init_symlink(inode); 145e5e5558eSMiklos Szeredi else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || 146e5e5558eSMiklos Szeredi S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { 147e5e5558eSMiklos Szeredi fuse_init_common(inode); 148e5e5558eSMiklos Szeredi init_special_inode(inode, inode->i_mode, 149e5e5558eSMiklos Szeredi new_decode_dev(attr->rdev)); 15039ee059aSMiklos Szeredi } else 15139ee059aSMiklos Szeredi BUG(); 152d8a5ba45SMiklos Szeredi } 153d8a5ba45SMiklos Szeredi 154d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp) 155d8a5ba45SMiklos Szeredi { 156d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 157d8a5ba45SMiklos Szeredi if (get_node_id(inode) == nodeid) 158d8a5ba45SMiklos Szeredi return 1; 159d8a5ba45SMiklos Szeredi else 160d8a5ba45SMiklos Szeredi return 0; 161d8a5ba45SMiklos Szeredi } 162d8a5ba45SMiklos Szeredi 163d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp) 164d8a5ba45SMiklos Szeredi { 165d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 166d8a5ba45SMiklos Szeredi get_fuse_inode(inode)->nodeid = nodeid; 167d8a5ba45SMiklos Szeredi return 0; 168d8a5ba45SMiklos Szeredi } 169d8a5ba45SMiklos Szeredi 170d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 1719e6268dbSMiklos Szeredi int generation, struct fuse_attr *attr) 172d8a5ba45SMiklos Szeredi { 173d8a5ba45SMiklos Szeredi struct inode *inode; 1749e6268dbSMiklos Szeredi struct fuse_inode *fi; 175d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 176d8a5ba45SMiklos Szeredi 177d8a5ba45SMiklos Szeredi retry: 178d8a5ba45SMiklos Szeredi inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); 179d8a5ba45SMiklos Szeredi if (!inode) 180d8a5ba45SMiklos Szeredi return NULL; 181d8a5ba45SMiklos Szeredi 182d8a5ba45SMiklos Szeredi if ((inode->i_state & I_NEW)) { 183b36c31baSMiklos Szeredi inode->i_flags |= S_NOATIME|S_NOCMTIME; 184d8a5ba45SMiklos Szeredi inode->i_generation = generation; 185d8a5ba45SMiklos Szeredi inode->i_data.backing_dev_info = &fc->bdi; 186d8a5ba45SMiklos Szeredi fuse_init_inode(inode, attr); 187d8a5ba45SMiklos Szeredi unlock_new_inode(inode); 188d8a5ba45SMiklos Szeredi } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { 189d8a5ba45SMiklos Szeredi /* Inode has changed type, any I/O on the old should fail */ 190d8a5ba45SMiklos Szeredi make_bad_inode(inode); 191d8a5ba45SMiklos Szeredi iput(inode); 192d8a5ba45SMiklos Szeredi goto retry; 193d8a5ba45SMiklos Szeredi } 194d8a5ba45SMiklos Szeredi 1959e6268dbSMiklos Szeredi fi = get_fuse_inode(inode); 1968da5ff23SMiklos Szeredi spin_lock(&fc->lock); 1979e6268dbSMiklos Szeredi fi->nlookup ++; 1988da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 199d8a5ba45SMiklos Szeredi fuse_change_attributes(inode, attr); 200d8a5ba45SMiklos Szeredi return inode; 201d8a5ba45SMiklos Szeredi } 202d8a5ba45SMiklos Szeredi 2038b512d9aSTrond Myklebust static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) 20469a53bf2SMiklos Szeredi { 2058b512d9aSTrond Myklebust if (flags & MNT_FORCE) 2068b512d9aSTrond Myklebust fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); 20769a53bf2SMiklos Szeredi } 20869a53bf2SMiklos Szeredi 2090ec7ca41SMiklos Szeredi static void fuse_send_destroy(struct fuse_conn *fc) 2100ec7ca41SMiklos Szeredi { 2110ec7ca41SMiklos Szeredi struct fuse_req *req = fc->destroy_req; 2120ec7ca41SMiklos Szeredi if (req && fc->conn_init) { 2130ec7ca41SMiklos Szeredi fc->destroy_req = NULL; 2140ec7ca41SMiklos Szeredi req->in.h.opcode = FUSE_DESTROY; 2150ec7ca41SMiklos Szeredi req->force = 1; 2160ec7ca41SMiklos Szeredi request_send(fc, req); 2170ec7ca41SMiklos Szeredi fuse_put_request(fc, req); 2180ec7ca41SMiklos Szeredi } 2190ec7ca41SMiklos Szeredi } 2200ec7ca41SMiklos Szeredi 221d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb) 222d8a5ba45SMiklos Szeredi { 223d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 224d8a5ba45SMiklos Szeredi 2250ec7ca41SMiklos Szeredi fuse_send_destroy(fc); 226d7133114SMiklos Szeredi spin_lock(&fc->lock); 2279ba7cbbaSMiklos Szeredi fc->connected = 0; 22851eb01e7SMiklos Szeredi fc->blocked = 0; 229d7133114SMiklos Szeredi spin_unlock(&fc->lock); 230334f485dSMiklos Szeredi /* Flush all readers on this fs */ 231385a17bfSJeff Dike kill_fasync(&fc->fasync, SIGIO, POLL_IN); 232334f485dSMiklos Szeredi wake_up_all(&fc->waitq); 23351eb01e7SMiklos Szeredi wake_up_all(&fc->blocked_waitq); 234bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 235bafa9654SMiklos Szeredi list_del(&fc->entry); 236bafa9654SMiklos Szeredi fuse_ctl_remove_conn(fc); 237bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 238bafa9654SMiklos Szeredi fuse_conn_put(fc); 239d8a5ba45SMiklos Szeredi } 240d8a5ba45SMiklos Szeredi 241e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) 242e5e5558eSMiklos Szeredi { 243e5e5558eSMiklos Szeredi stbuf->f_type = FUSE_SUPER_MAGIC; 244e5e5558eSMiklos Szeredi stbuf->f_bsize = attr->bsize; 245de5f1202SMiklos Szeredi stbuf->f_frsize = attr->frsize; 246e5e5558eSMiklos Szeredi stbuf->f_blocks = attr->blocks; 247e5e5558eSMiklos Szeredi stbuf->f_bfree = attr->bfree; 248e5e5558eSMiklos Szeredi stbuf->f_bavail = attr->bavail; 249e5e5558eSMiklos Szeredi stbuf->f_files = attr->files; 250e5e5558eSMiklos Szeredi stbuf->f_ffree = attr->ffree; 251e5e5558eSMiklos Szeredi stbuf->f_namelen = attr->namelen; 252e5e5558eSMiklos Szeredi /* fsid is left zero */ 253e5e5558eSMiklos Szeredi } 254e5e5558eSMiklos Szeredi 255726c3342SDavid Howells static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) 256e5e5558eSMiklos Szeredi { 257726c3342SDavid Howells struct super_block *sb = dentry->d_sb; 258e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 259e5e5558eSMiklos Szeredi struct fuse_req *req; 260e5e5558eSMiklos Szeredi struct fuse_statfs_out outarg; 261e5e5558eSMiklos Szeredi int err; 262e5e5558eSMiklos Szeredi 263ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 264ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 265ce1d5a49SMiklos Szeredi return PTR_ERR(req); 266e5e5558eSMiklos Szeredi 267de5f1202SMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 268e5e5558eSMiklos Szeredi req->in.numargs = 0; 269e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_STATFS; 2705b35e8e5SMiklos Szeredi req->in.h.nodeid = get_node_id(dentry->d_inode); 271e5e5558eSMiklos Szeredi req->out.numargs = 1; 272de5f1202SMiklos Szeredi req->out.args[0].size = 273de5f1202SMiklos Szeredi fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); 274e5e5558eSMiklos Szeredi req->out.args[0].value = &outarg; 275e5e5558eSMiklos Szeredi request_send(fc, req); 276e5e5558eSMiklos Szeredi err = req->out.h.error; 277e5e5558eSMiklos Szeredi if (!err) 278e5e5558eSMiklos Szeredi convert_fuse_statfs(buf, &outarg.st); 279e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 280e5e5558eSMiklos Szeredi return err; 281e5e5558eSMiklos Szeredi } 282e5e5558eSMiklos Szeredi 283d8a5ba45SMiklos Szeredi enum { 284d8a5ba45SMiklos Szeredi OPT_FD, 285d8a5ba45SMiklos Szeredi OPT_ROOTMODE, 286d8a5ba45SMiklos Szeredi OPT_USER_ID, 28787729a55SMiklos Szeredi OPT_GROUP_ID, 288d8a5ba45SMiklos Szeredi OPT_DEFAULT_PERMISSIONS, 289d8a5ba45SMiklos Szeredi OPT_ALLOW_OTHER, 290db50b96cSMiklos Szeredi OPT_MAX_READ, 291d8091614SMiklos Szeredi OPT_BLKSIZE, 292d8a5ba45SMiklos Szeredi OPT_ERR 293d8a5ba45SMiklos Szeredi }; 294d8a5ba45SMiklos Szeredi 295d8a5ba45SMiklos Szeredi static match_table_t tokens = { 296d8a5ba45SMiklos Szeredi {OPT_FD, "fd=%u"}, 297d8a5ba45SMiklos Szeredi {OPT_ROOTMODE, "rootmode=%o"}, 298d8a5ba45SMiklos Szeredi {OPT_USER_ID, "user_id=%u"}, 29987729a55SMiklos Szeredi {OPT_GROUP_ID, "group_id=%u"}, 300d8a5ba45SMiklos Szeredi {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 301d8a5ba45SMiklos Szeredi {OPT_ALLOW_OTHER, "allow_other"}, 302db50b96cSMiklos Szeredi {OPT_MAX_READ, "max_read=%u"}, 303d8091614SMiklos Szeredi {OPT_BLKSIZE, "blksize=%u"}, 304d8a5ba45SMiklos Szeredi {OPT_ERR, NULL} 305d8a5ba45SMiklos Szeredi }; 306d8a5ba45SMiklos Szeredi 307d8091614SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) 308d8a5ba45SMiklos Szeredi { 309d8a5ba45SMiklos Szeredi char *p; 310d8a5ba45SMiklos Szeredi memset(d, 0, sizeof(struct fuse_mount_data)); 311db50b96cSMiklos Szeredi d->max_read = ~0; 312d8091614SMiklos Szeredi d->blksize = 512; 313d8a5ba45SMiklos Szeredi 314d8a5ba45SMiklos Szeredi while ((p = strsep(&opt, ",")) != NULL) { 315d8a5ba45SMiklos Szeredi int token; 316d8a5ba45SMiklos Szeredi int value; 317d8a5ba45SMiklos Szeredi substring_t args[MAX_OPT_ARGS]; 318d8a5ba45SMiklos Szeredi if (!*p) 319d8a5ba45SMiklos Szeredi continue; 320d8a5ba45SMiklos Szeredi 321d8a5ba45SMiklos Szeredi token = match_token(p, tokens, args); 322d8a5ba45SMiklos Szeredi switch (token) { 323d8a5ba45SMiklos Szeredi case OPT_FD: 324d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 325d8a5ba45SMiklos Szeredi return 0; 326d8a5ba45SMiklos Szeredi d->fd = value; 3275a533682SMiklos Szeredi d->fd_present = 1; 328d8a5ba45SMiklos Szeredi break; 329d8a5ba45SMiklos Szeredi 330d8a5ba45SMiklos Szeredi case OPT_ROOTMODE: 331d8a5ba45SMiklos Szeredi if (match_octal(&args[0], &value)) 332d8a5ba45SMiklos Szeredi return 0; 333a5bfffacSTimo Savola if (!fuse_valid_type(value)) 334a5bfffacSTimo Savola return 0; 335d8a5ba45SMiklos Szeredi d->rootmode = value; 3365a533682SMiklos Szeredi d->rootmode_present = 1; 337d8a5ba45SMiklos Szeredi break; 338d8a5ba45SMiklos Szeredi 339d8a5ba45SMiklos Szeredi case OPT_USER_ID: 340d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 341d8a5ba45SMiklos Szeredi return 0; 342d8a5ba45SMiklos Szeredi d->user_id = value; 3435a533682SMiklos Szeredi d->user_id_present = 1; 344d8a5ba45SMiklos Szeredi break; 345d8a5ba45SMiklos Szeredi 34687729a55SMiklos Szeredi case OPT_GROUP_ID: 34787729a55SMiklos Szeredi if (match_int(&args[0], &value)) 34887729a55SMiklos Szeredi return 0; 34987729a55SMiklos Szeredi d->group_id = value; 3505a533682SMiklos Szeredi d->group_id_present = 1; 35187729a55SMiklos Szeredi break; 35287729a55SMiklos Szeredi 3531e9a4ed9SMiklos Szeredi case OPT_DEFAULT_PERMISSIONS: 3541e9a4ed9SMiklos Szeredi d->flags |= FUSE_DEFAULT_PERMISSIONS; 3551e9a4ed9SMiklos Szeredi break; 3561e9a4ed9SMiklos Szeredi 3571e9a4ed9SMiklos Szeredi case OPT_ALLOW_OTHER: 3581e9a4ed9SMiklos Szeredi d->flags |= FUSE_ALLOW_OTHER; 3591e9a4ed9SMiklos Szeredi break; 3601e9a4ed9SMiklos Szeredi 361db50b96cSMiklos Szeredi case OPT_MAX_READ: 362db50b96cSMiklos Szeredi if (match_int(&args[0], &value)) 363db50b96cSMiklos Szeredi return 0; 364db50b96cSMiklos Szeredi d->max_read = value; 365db50b96cSMiklos Szeredi break; 366db50b96cSMiklos Szeredi 367d8091614SMiklos Szeredi case OPT_BLKSIZE: 368d8091614SMiklos Szeredi if (!is_bdev || match_int(&args[0], &value)) 369d8091614SMiklos Szeredi return 0; 370d8091614SMiklos Szeredi d->blksize = value; 371d8091614SMiklos Szeredi break; 372d8091614SMiklos Szeredi 373d8a5ba45SMiklos Szeredi default: 374d8a5ba45SMiklos Szeredi return 0; 375d8a5ba45SMiklos Szeredi } 376d8a5ba45SMiklos Szeredi } 3775a533682SMiklos Szeredi 3785a533682SMiklos Szeredi if (!d->fd_present || !d->rootmode_present || 3795a533682SMiklos Szeredi !d->user_id_present || !d->group_id_present) 380d8a5ba45SMiklos Szeredi return 0; 381d8a5ba45SMiklos Szeredi 382d8a5ba45SMiklos Szeredi return 1; 383d8a5ba45SMiklos Szeredi } 384d8a5ba45SMiklos Szeredi 385d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) 386d8a5ba45SMiklos Szeredi { 387d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 388d8a5ba45SMiklos Szeredi 389d8a5ba45SMiklos Szeredi seq_printf(m, ",user_id=%u", fc->user_id); 39087729a55SMiklos Szeredi seq_printf(m, ",group_id=%u", fc->group_id); 3911e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) 3921e9a4ed9SMiklos Szeredi seq_puts(m, ",default_permissions"); 3931e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 3941e9a4ed9SMiklos Szeredi seq_puts(m, ",allow_other"); 395db50b96cSMiklos Szeredi if (fc->max_read != ~0) 396db50b96cSMiklos Szeredi seq_printf(m, ",max_read=%u", fc->max_read); 397d8a5ba45SMiklos Szeredi return 0; 398d8a5ba45SMiklos Szeredi } 399d8a5ba45SMiklos Szeredi 400d8a5ba45SMiklos Szeredi static struct fuse_conn *new_conn(void) 401d8a5ba45SMiklos Szeredi { 402d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 403d8a5ba45SMiklos Szeredi 4046383bdaaSMiklos Szeredi fc = kzalloc(sizeof(*fc), GFP_KERNEL); 405f543f253SMiklos Szeredi if (fc) { 406d7133114SMiklos Szeredi spin_lock_init(&fc->lock); 407d2a85164SMiklos Szeredi mutex_init(&fc->inst_mutex); 408bafa9654SMiklos Szeredi atomic_set(&fc->count, 1); 409334f485dSMiklos Szeredi init_waitqueue_head(&fc->waitq); 41008a53cdcSMiklos Szeredi init_waitqueue_head(&fc->blocked_waitq); 411334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->pending); 412334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->processing); 413d77a1d5bSMiklos Szeredi INIT_LIST_HEAD(&fc->io); 414a4d27e75SMiklos Szeredi INIT_LIST_HEAD(&fc->interrupts); 415095da6cbSMiklos Szeredi atomic_set(&fc->num_waiting, 0); 416d8a5ba45SMiklos Szeredi fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 417d8a5ba45SMiklos Szeredi fc->bdi.unplug_io_fn = default_unplug_io_fn; 418334f485dSMiklos Szeredi fc->reqctr = 0; 41908a53cdcSMiklos Szeredi fc->blocked = 1; 4209c8ef561SMiklos Szeredi get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); 421d8a5ba45SMiklos Szeredi } 422d8a5ba45SMiklos Szeredi return fc; 423d8a5ba45SMiklos Szeredi } 424d8a5ba45SMiklos Szeredi 425bafa9654SMiklos Szeredi void fuse_conn_put(struct fuse_conn *fc) 426bafa9654SMiklos Szeredi { 427d2a85164SMiklos Szeredi if (atomic_dec_and_test(&fc->count)) { 4280ec7ca41SMiklos Szeredi if (fc->destroy_req) 4290ec7ca41SMiklos Szeredi fuse_request_free(fc->destroy_req); 430d2a85164SMiklos Szeredi mutex_destroy(&fc->inst_mutex); 431bafa9654SMiklos Szeredi kfree(fc); 432bafa9654SMiklos Szeredi } 433d2a85164SMiklos Szeredi } 434bafa9654SMiklos Szeredi 435bafa9654SMiklos Szeredi struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) 436bafa9654SMiklos Szeredi { 437bafa9654SMiklos Szeredi atomic_inc(&fc->count); 438bafa9654SMiklos Szeredi return fc; 439bafa9654SMiklos Szeredi } 440bafa9654SMiklos Szeredi 441d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode) 442d8a5ba45SMiklos Szeredi { 443d8a5ba45SMiklos Szeredi struct fuse_attr attr; 444d8a5ba45SMiklos Szeredi memset(&attr, 0, sizeof(attr)); 445d8a5ba45SMiklos Szeredi 446d8a5ba45SMiklos Szeredi attr.mode = mode; 447d8a5ba45SMiklos Szeredi attr.ino = FUSE_ROOT_ID; 4489e6268dbSMiklos Szeredi return fuse_iget(sb, 1, 0, &attr); 449d8a5ba45SMiklos Szeredi } 450d8a5ba45SMiklos Szeredi 451ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = { 452d8a5ba45SMiklos Szeredi .alloc_inode = fuse_alloc_inode, 453d8a5ba45SMiklos Szeredi .destroy_inode = fuse_destroy_inode, 454d8a5ba45SMiklos Szeredi .read_inode = fuse_read_inode, 455d8a5ba45SMiklos Szeredi .clear_inode = fuse_clear_inode, 45671421259SMiklos Szeredi .remount_fs = fuse_remount_fs, 457d8a5ba45SMiklos Szeredi .put_super = fuse_put_super, 45869a53bf2SMiklos Szeredi .umount_begin = fuse_umount_begin, 459e5e5558eSMiklos Szeredi .statfs = fuse_statfs, 460d8a5ba45SMiklos Szeredi .show_options = fuse_show_options, 461d8a5ba45SMiklos Szeredi }; 462d8a5ba45SMiklos Szeredi 4639b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) 4649b9a0469SMiklos Szeredi { 4659b9a0469SMiklos Szeredi struct fuse_init_out *arg = &req->misc.init_out; 4669b9a0469SMiklos Szeredi 4679b9a0469SMiklos Szeredi if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) 4689b9a0469SMiklos Szeredi fc->conn_error = 1; 4699b9a0469SMiklos Szeredi else { 4709cd68455SMiklos Szeredi unsigned long ra_pages; 4719cd68455SMiklos Szeredi 4729cd68455SMiklos Szeredi if (arg->minor >= 6) { 4739cd68455SMiklos Szeredi ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; 4749cd68455SMiklos Szeredi if (arg->flags & FUSE_ASYNC_READ) 4759cd68455SMiklos Szeredi fc->async_read = 1; 47671421259SMiklos Szeredi if (!(arg->flags & FUSE_POSIX_LOCKS)) 47771421259SMiklos Szeredi fc->no_lock = 1; 47871421259SMiklos Szeredi } else { 4799cd68455SMiklos Szeredi ra_pages = fc->max_read / PAGE_CACHE_SIZE; 48071421259SMiklos Szeredi fc->no_lock = 1; 48171421259SMiklos Szeredi } 4829cd68455SMiklos Szeredi 4839cd68455SMiklos Szeredi fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); 4849b9a0469SMiklos Szeredi fc->minor = arg->minor; 4859b9a0469SMiklos Szeredi fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; 4860ec7ca41SMiklos Szeredi fc->conn_init = 1; 4879b9a0469SMiklos Szeredi } 4889b9a0469SMiklos Szeredi fuse_put_request(fc, req); 48908a53cdcSMiklos Szeredi fc->blocked = 0; 49008a53cdcSMiklos Szeredi wake_up_all(&fc->blocked_waitq); 4919b9a0469SMiklos Szeredi } 4929b9a0469SMiklos Szeredi 493ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) 4949b9a0469SMiklos Szeredi { 4959b9a0469SMiklos Szeredi struct fuse_init_in *arg = &req->misc.init_in; 496095da6cbSMiklos Szeredi 4979b9a0469SMiklos Szeredi arg->major = FUSE_KERNEL_VERSION; 4989b9a0469SMiklos Szeredi arg->minor = FUSE_KERNEL_MINOR_VERSION; 4999cd68455SMiklos Szeredi arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; 50071421259SMiklos Szeredi arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; 5019b9a0469SMiklos Szeredi req->in.h.opcode = FUSE_INIT; 5029b9a0469SMiklos Szeredi req->in.numargs = 1; 5039b9a0469SMiklos Szeredi req->in.args[0].size = sizeof(*arg); 5049b9a0469SMiklos Szeredi req->in.args[0].value = arg; 5059b9a0469SMiklos Szeredi req->out.numargs = 1; 5069b9a0469SMiklos Szeredi /* Variable length arguement used for backward compatibility 5079b9a0469SMiklos Szeredi with interface version < 7.5. Rest of init_out is zeroed 5089b9a0469SMiklos Szeredi by do_get_request(), so a short reply is not a problem */ 5099b9a0469SMiklos Szeredi req->out.argvar = 1; 5109b9a0469SMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_init_out); 5119b9a0469SMiklos Szeredi req->out.args[0].value = &req->misc.init_out; 5129b9a0469SMiklos Szeredi req->end = process_init_reply; 5139b9a0469SMiklos Szeredi request_send_background(fc, req); 5149b9a0469SMiklos Szeredi } 5159b9a0469SMiklos Szeredi 516bafa9654SMiklos Szeredi static u64 conn_id(void) 517f543f253SMiklos Szeredi { 518bafa9654SMiklos Szeredi static u64 ctr = 1; 5190720b315SMiklos Szeredi return ctr++; 520f543f253SMiklos Szeredi } 521f543f253SMiklos Szeredi 522d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent) 523d8a5ba45SMiklos Szeredi { 524d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 525d8a5ba45SMiklos Szeredi struct inode *root; 526d8a5ba45SMiklos Szeredi struct fuse_mount_data d; 527d8a5ba45SMiklos Szeredi struct file *file; 528f543f253SMiklos Szeredi struct dentry *root_dentry; 529ce1d5a49SMiklos Szeredi struct fuse_req *init_req; 530d8a5ba45SMiklos Szeredi int err; 531d8091614SMiklos Szeredi int is_bdev = sb->s_bdev != NULL; 532d8a5ba45SMiklos Szeredi 53371421259SMiklos Szeredi if (sb->s_flags & MS_MANDLOCK) 53471421259SMiklos Szeredi return -EINVAL; 53571421259SMiklos Szeredi 536d8091614SMiklos Szeredi if (!parse_fuse_opt((char *) data, &d, is_bdev)) 537d8a5ba45SMiklos Szeredi return -EINVAL; 538d8a5ba45SMiklos Szeredi 539d8091614SMiklos Szeredi if (is_bdev) { 540875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 541d8091614SMiklos Szeredi if (!sb_set_blocksize(sb, d.blksize)) 542d8091614SMiklos Szeredi return -EINVAL; 543875d95ecSMiklos Szeredi #endif 544d8091614SMiklos Szeredi } else { 545d8a5ba45SMiklos Szeredi sb->s_blocksize = PAGE_CACHE_SIZE; 546d8a5ba45SMiklos Szeredi sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 547d8091614SMiklos Szeredi } 548d8a5ba45SMiklos Szeredi sb->s_magic = FUSE_SUPER_MAGIC; 549d8a5ba45SMiklos Szeredi sb->s_op = &fuse_super_operations; 550d8a5ba45SMiklos Szeredi sb->s_maxbytes = MAX_LFS_FILESIZE; 551d8a5ba45SMiklos Szeredi 552d8a5ba45SMiklos Szeredi file = fget(d.fd); 553d8a5ba45SMiklos Szeredi if (!file) 554d8a5ba45SMiklos Szeredi return -EINVAL; 555d8a5ba45SMiklos Szeredi 5560720b315SMiklos Szeredi if (file->f_op != &fuse_dev_operations) 5570720b315SMiklos Szeredi return -EINVAL; 5580720b315SMiklos Szeredi 5590720b315SMiklos Szeredi fc = new_conn(); 5600720b315SMiklos Szeredi if (!fc) 5610720b315SMiklos Szeredi return -ENOMEM; 562d8a5ba45SMiklos Szeredi 5631e9a4ed9SMiklos Szeredi fc->flags = d.flags; 564d8a5ba45SMiklos Szeredi fc->user_id = d.user_id; 56587729a55SMiklos Szeredi fc->group_id = d.group_id; 566db50b96cSMiklos Szeredi fc->max_read = d.max_read; 567d8a5ba45SMiklos Szeredi 568f543f253SMiklos Szeredi /* Used by get_root_inode() */ 569f543f253SMiklos Szeredi sb->s_fs_info = fc; 570f543f253SMiklos Szeredi 571d8a5ba45SMiklos Szeredi err = -ENOMEM; 572d8a5ba45SMiklos Szeredi root = get_root_inode(sb, d.rootmode); 573f543f253SMiklos Szeredi if (!root) 574d8a5ba45SMiklos Szeredi goto err; 575d8a5ba45SMiklos Szeredi 576f543f253SMiklos Szeredi root_dentry = d_alloc_root(root); 577f543f253SMiklos Szeredi if (!root_dentry) { 578d8a5ba45SMiklos Szeredi iput(root); 579d8a5ba45SMiklos Szeredi goto err; 580d8a5ba45SMiklos Szeredi } 581f543f253SMiklos Szeredi 582ce1d5a49SMiklos Szeredi init_req = fuse_request_alloc(); 583ce1d5a49SMiklos Szeredi if (!init_req) 584ce1d5a49SMiklos Szeredi goto err_put_root; 585ce1d5a49SMiklos Szeredi 5860ec7ca41SMiklos Szeredi if (is_bdev) { 5870ec7ca41SMiklos Szeredi fc->destroy_req = fuse_request_alloc(); 5880ec7ca41SMiklos Szeredi if (!fc->destroy_req) 5890ec7ca41SMiklos Szeredi goto err_put_root; 5900ec7ca41SMiklos Szeredi } 5910ec7ca41SMiklos Szeredi 592bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 5938aa09a50SMiklos Szeredi err = -EINVAL; 5948aa09a50SMiklos Szeredi if (file->private_data) 595bafa9654SMiklos Szeredi goto err_unlock; 5968aa09a50SMiklos Szeredi 597bafa9654SMiklos Szeredi fc->id = conn_id(); 598bafa9654SMiklos Szeredi err = fuse_ctl_add_conn(fc); 599bafa9654SMiklos Szeredi if (err) 600bafa9654SMiklos Szeredi goto err_unlock; 601bafa9654SMiklos Szeredi 602bafa9654SMiklos Szeredi list_add_tail(&fc->entry, &fuse_conn_list); 603f543f253SMiklos Szeredi sb->s_root = root_dentry; 604f543f253SMiklos Szeredi fc->connected = 1; 605bafa9654SMiklos Szeredi file->private_data = fuse_conn_get(fc); 606bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 6070720b315SMiklos Szeredi /* 6080720b315SMiklos Szeredi * atomic_dec_and_test() in fput() provides the necessary 6090720b315SMiklos Szeredi * memory barrier for file->private_data to be visible on all 6100720b315SMiklos Szeredi * CPUs after this 6110720b315SMiklos Szeredi */ 6120720b315SMiklos Szeredi fput(file); 613f543f253SMiklos Szeredi 614ce1d5a49SMiklos Szeredi fuse_send_init(fc, init_req); 615f543f253SMiklos Szeredi 616d8a5ba45SMiklos Szeredi return 0; 617d8a5ba45SMiklos Szeredi 618bafa9654SMiklos Szeredi err_unlock: 619bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 620ce1d5a49SMiklos Szeredi fuse_request_free(init_req); 621f543f253SMiklos Szeredi err_put_root: 622f543f253SMiklos Szeredi dput(root_dentry); 623d8a5ba45SMiklos Szeredi err: 6240720b315SMiklos Szeredi fput(file); 625bafa9654SMiklos Szeredi fuse_conn_put(fc); 626d8a5ba45SMiklos Szeredi return err; 627d8a5ba45SMiklos Szeredi } 628d8a5ba45SMiklos Szeredi 629454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type, 630d8a5ba45SMiklos Szeredi int flags, const char *dev_name, 631454e2398SDavid Howells void *raw_data, struct vfsmount *mnt) 632d8a5ba45SMiklos Szeredi { 633454e2398SDavid Howells return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); 634d8a5ba45SMiklos Szeredi } 635d8a5ba45SMiklos Szeredi 636875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = { 637875d95ecSMiklos Szeredi .owner = THIS_MODULE, 638875d95ecSMiklos Szeredi .name = "fuse", 63979c0b2dfSMiklos Szeredi .fs_flags = FS_HAS_SUBTYPE, 640875d95ecSMiklos Szeredi .get_sb = fuse_get_sb, 641875d95ecSMiklos Szeredi .kill_sb = kill_anon_super, 642875d95ecSMiklos Szeredi }; 643875d95ecSMiklos Szeredi 644875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 645d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type, 646d6392f87SMiklos Szeredi int flags, const char *dev_name, 647d6392f87SMiklos Szeredi void *raw_data, struct vfsmount *mnt) 648d6392f87SMiklos Szeredi { 649d6392f87SMiklos Szeredi return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, 650d6392f87SMiklos Szeredi mnt); 651d6392f87SMiklos Szeredi } 652d6392f87SMiklos Szeredi 653d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = { 654d6392f87SMiklos Szeredi .owner = THIS_MODULE, 655d6392f87SMiklos Szeredi .name = "fuseblk", 65679c0b2dfSMiklos Szeredi .fs_flags = FS_HAS_SUBTYPE, 657d6392f87SMiklos Szeredi .get_sb = fuse_get_sb_blk, 658d6392f87SMiklos Szeredi .kill_sb = kill_block_super, 659d6392f87SMiklos Szeredi .fs_flags = FS_REQUIRES_DEV, 660d6392f87SMiklos Szeredi }; 661d6392f87SMiklos Szeredi 662875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 663875d95ecSMiklos Szeredi { 664875d95ecSMiklos Szeredi return register_filesystem(&fuseblk_fs_type); 665875d95ecSMiklos Szeredi } 666875d95ecSMiklos Szeredi 667875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 668875d95ecSMiklos Szeredi { 669875d95ecSMiklos Szeredi unregister_filesystem(&fuseblk_fs_type); 670875d95ecSMiklos Szeredi } 671875d95ecSMiklos Szeredi #else 672875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 673875d95ecSMiklos Szeredi { 674875d95ecSMiklos Szeredi return 0; 675875d95ecSMiklos Szeredi } 676875d95ecSMiklos Szeredi 677875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 678875d95ecSMiklos Szeredi { 679875d95ecSMiklos Szeredi } 680875d95ecSMiklos Szeredi #endif 681875d95ecSMiklos Szeredi 682f543f253SMiklos Szeredi static decl_subsys(fuse, NULL, NULL); 683bafa9654SMiklos Szeredi static decl_subsys(connections, NULL, NULL); 684f543f253SMiklos Szeredi 685e18b890bSChristoph Lameter static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep, 686d8a5ba45SMiklos Szeredi unsigned long flags) 687d8a5ba45SMiklos Szeredi { 688d8a5ba45SMiklos Szeredi struct inode * inode = foo; 689d8a5ba45SMiklos Szeredi 69050953fe9SChristoph Lameter if (flags & SLAB_CTOR_CONSTRUCTOR) 691d8a5ba45SMiklos Szeredi inode_init_once(inode); 692d8a5ba45SMiklos Szeredi } 693d8a5ba45SMiklos Szeredi 694d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void) 695d8a5ba45SMiklos Szeredi { 696d8a5ba45SMiklos Szeredi int err; 697d8a5ba45SMiklos Szeredi 698d8a5ba45SMiklos Szeredi err = register_filesystem(&fuse_fs_type); 699d8a5ba45SMiklos Szeredi if (err) 700d6392f87SMiklos Szeredi goto out; 701d6392f87SMiklos Szeredi 702875d95ecSMiklos Szeredi err = register_fuseblk(); 703d6392f87SMiklos Szeredi if (err) 704d6392f87SMiklos Szeredi goto out_unreg; 705d6392f87SMiklos Szeredi 706d8a5ba45SMiklos Szeredi fuse_inode_cachep = kmem_cache_create("fuse_inode", 707d8a5ba45SMiklos Szeredi sizeof(struct fuse_inode), 708d8a5ba45SMiklos Szeredi 0, SLAB_HWCACHE_ALIGN, 709d8a5ba45SMiklos Szeredi fuse_inode_init_once, NULL); 710d8a5ba45SMiklos Szeredi err = -ENOMEM; 711d6392f87SMiklos Szeredi if (!fuse_inode_cachep) 712d6392f87SMiklos Szeredi goto out_unreg2; 713d8a5ba45SMiklos Szeredi 714d6392f87SMiklos Szeredi return 0; 715d6392f87SMiklos Szeredi 716d6392f87SMiklos Szeredi out_unreg2: 717875d95ecSMiklos Szeredi unregister_fuseblk(); 718d6392f87SMiklos Szeredi out_unreg: 719d6392f87SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 720d6392f87SMiklos Szeredi out: 721d8a5ba45SMiklos Szeredi return err; 722d8a5ba45SMiklos Szeredi } 723d8a5ba45SMiklos Szeredi 724d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void) 725d8a5ba45SMiklos Szeredi { 726d8a5ba45SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 727875d95ecSMiklos Szeredi unregister_fuseblk(); 728d8a5ba45SMiklos Szeredi kmem_cache_destroy(fuse_inode_cachep); 729d8a5ba45SMiklos Szeredi } 730d8a5ba45SMiklos Szeredi 731f543f253SMiklos Szeredi static int fuse_sysfs_init(void) 732f543f253SMiklos Szeredi { 733f543f253SMiklos Szeredi int err; 734f543f253SMiklos Szeredi 735823bccfcSGreg Kroah-Hartman kobj_set_kset_s(&fuse_subsys, fs_subsys); 736f543f253SMiklos Szeredi err = subsystem_register(&fuse_subsys); 737f543f253SMiklos Szeredi if (err) 738f543f253SMiklos Szeredi goto out_err; 739f543f253SMiklos Szeredi 740823bccfcSGreg Kroah-Hartman kobj_set_kset_s(&connections_subsys, fuse_subsys); 741f543f253SMiklos Szeredi err = subsystem_register(&connections_subsys); 742f543f253SMiklos Szeredi if (err) 743f543f253SMiklos Szeredi goto out_fuse_unregister; 744f543f253SMiklos Szeredi 745f543f253SMiklos Szeredi return 0; 746f543f253SMiklos Szeredi 747f543f253SMiklos Szeredi out_fuse_unregister: 748f543f253SMiklos Szeredi subsystem_unregister(&fuse_subsys); 749f543f253SMiklos Szeredi out_err: 750f543f253SMiklos Szeredi return err; 751f543f253SMiklos Szeredi } 752f543f253SMiklos Szeredi 753f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void) 754f543f253SMiklos Szeredi { 755f543f253SMiklos Szeredi subsystem_unregister(&connections_subsys); 756f543f253SMiklos Szeredi subsystem_unregister(&fuse_subsys); 757f543f253SMiklos Szeredi } 758f543f253SMiklos Szeredi 759d8a5ba45SMiklos Szeredi static int __init fuse_init(void) 760d8a5ba45SMiklos Szeredi { 761d8a5ba45SMiklos Szeredi int res; 762d8a5ba45SMiklos Szeredi 763d8a5ba45SMiklos Szeredi printk("fuse init (API version %i.%i)\n", 764d8a5ba45SMiklos Szeredi FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 765d8a5ba45SMiklos Szeredi 766bafa9654SMiklos Szeredi INIT_LIST_HEAD(&fuse_conn_list); 767d8a5ba45SMiklos Szeredi res = fuse_fs_init(); 768d8a5ba45SMiklos Szeredi if (res) 769d8a5ba45SMiklos Szeredi goto err; 770d8a5ba45SMiklos Szeredi 771334f485dSMiklos Szeredi res = fuse_dev_init(); 772334f485dSMiklos Szeredi if (res) 773334f485dSMiklos Szeredi goto err_fs_cleanup; 774334f485dSMiklos Szeredi 775f543f253SMiklos Szeredi res = fuse_sysfs_init(); 776f543f253SMiklos Szeredi if (res) 777f543f253SMiklos Szeredi goto err_dev_cleanup; 778f543f253SMiklos Szeredi 779bafa9654SMiklos Szeredi res = fuse_ctl_init(); 780bafa9654SMiklos Szeredi if (res) 781bafa9654SMiklos Szeredi goto err_sysfs_cleanup; 782bafa9654SMiklos Szeredi 783d8a5ba45SMiklos Szeredi return 0; 784d8a5ba45SMiklos Szeredi 785bafa9654SMiklos Szeredi err_sysfs_cleanup: 786bafa9654SMiklos Szeredi fuse_sysfs_cleanup(); 787f543f253SMiklos Szeredi err_dev_cleanup: 788f543f253SMiklos Szeredi fuse_dev_cleanup(); 789334f485dSMiklos Szeredi err_fs_cleanup: 790334f485dSMiklos Szeredi fuse_fs_cleanup(); 791d8a5ba45SMiklos Szeredi err: 792d8a5ba45SMiklos Szeredi return res; 793d8a5ba45SMiklos Szeredi } 794d8a5ba45SMiklos Szeredi 795d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void) 796d8a5ba45SMiklos Szeredi { 797d8a5ba45SMiklos Szeredi printk(KERN_DEBUG "fuse exit\n"); 798d8a5ba45SMiklos Szeredi 799bafa9654SMiklos Szeredi fuse_ctl_cleanup(); 800f543f253SMiklos Szeredi fuse_sysfs_cleanup(); 801d8a5ba45SMiklos Szeredi fuse_fs_cleanup(); 802334f485dSMiklos Szeredi fuse_dev_cleanup(); 803d8a5ba45SMiklos Szeredi } 804d8a5ba45SMiklos Szeredi 805d8a5ba45SMiklos Szeredi module_init(fuse_init); 806d8a5ba45SMiklos Szeredi module_exit(fuse_exit); 807