1d8a5ba45SMiklos Szeredi /* 2d8a5ba45SMiklos Szeredi FUSE: Filesystem in Userspace 31729a16cSMiklos Szeredi Copyright (C) 2001-2008 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> 21dbd561d2SMiklos Szeredi #include <linux/exportfs.h> 22d8a5ba45SMiklos Szeredi 23d8a5ba45SMiklos Szeredi MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); 24d8a5ba45SMiklos Szeredi MODULE_DESCRIPTION("Filesystem in Userspace"); 25d8a5ba45SMiklos Szeredi MODULE_LICENSE("GPL"); 26d8a5ba45SMiklos Szeredi 27e18b890bSChristoph Lameter static struct kmem_cache *fuse_inode_cachep; 28bafa9654SMiklos Szeredi struct list_head fuse_conn_list; 29bafa9654SMiklos Szeredi DEFINE_MUTEX(fuse_mutex); 30d8a5ba45SMiklos Szeredi 31d8a5ba45SMiklos Szeredi #define FUSE_SUPER_MAGIC 0x65735546 32d8a5ba45SMiklos Szeredi 33d1875dbaSMiklos Szeredi #define FUSE_DEFAULT_BLKSIZE 512 34d1875dbaSMiklos Szeredi 35d8a5ba45SMiklos Szeredi struct fuse_mount_data { 36d8a5ba45SMiklos Szeredi int fd; 37d8a5ba45SMiklos Szeredi unsigned rootmode; 38d8a5ba45SMiklos Szeredi unsigned user_id; 3987729a55SMiklos Szeredi unsigned group_id; 405a533682SMiklos Szeredi unsigned fd_present:1; 415a533682SMiklos Szeredi unsigned rootmode_present:1; 425a533682SMiklos Szeredi unsigned user_id_present:1; 435a533682SMiklos Szeredi unsigned group_id_present:1; 441e9a4ed9SMiklos Szeredi unsigned flags; 45db50b96cSMiklos Szeredi unsigned max_read; 46d8091614SMiklos Szeredi unsigned blksize; 47d8a5ba45SMiklos Szeredi }; 48d8a5ba45SMiklos Szeredi 49d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb) 50d8a5ba45SMiklos Szeredi { 51d8a5ba45SMiklos Szeredi struct inode *inode; 52d8a5ba45SMiklos Szeredi struct fuse_inode *fi; 53d8a5ba45SMiklos Szeredi 54e94b1766SChristoph Lameter inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); 55d8a5ba45SMiklos Szeredi if (!inode) 56d8a5ba45SMiklos Szeredi return NULL; 57d8a5ba45SMiklos Szeredi 58d8a5ba45SMiklos Szeredi fi = get_fuse_inode(inode); 590a0898cfSMiklos Szeredi fi->i_time = 0; 60d8a5ba45SMiklos Szeredi fi->nodeid = 0; 619e6268dbSMiklos Szeredi fi->nlookup = 0; 62fbee36b9SJohn Muir fi->attr_version = 0; 633be5a52bSMiklos Szeredi fi->writectr = 0; 6493a8c3cdSMiklos Szeredi INIT_LIST_HEAD(&fi->write_files); 653be5a52bSMiklos Szeredi INIT_LIST_HEAD(&fi->queued_writes); 663be5a52bSMiklos Szeredi INIT_LIST_HEAD(&fi->writepages); 673be5a52bSMiklos Szeredi init_waitqueue_head(&fi->page_waitq); 68e5e5558eSMiklos Szeredi fi->forget_req = fuse_request_alloc(); 69e5e5558eSMiklos Szeredi if (!fi->forget_req) { 70e5e5558eSMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 71e5e5558eSMiklos Szeredi return NULL; 72e5e5558eSMiklos Szeredi } 73d8a5ba45SMiklos Szeredi 74d8a5ba45SMiklos Szeredi return inode; 75d8a5ba45SMiklos Szeredi } 76d8a5ba45SMiklos Szeredi 77d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode) 78d8a5ba45SMiklos Szeredi { 79e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 8093a8c3cdSMiklos Szeredi BUG_ON(!list_empty(&fi->write_files)); 813be5a52bSMiklos Szeredi BUG_ON(!list_empty(&fi->queued_writes)); 82e5e5558eSMiklos Szeredi if (fi->forget_req) 83e5e5558eSMiklos Szeredi fuse_request_free(fi->forget_req); 84d8a5ba45SMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 85d8a5ba45SMiklos Szeredi } 86d8a5ba45SMiklos Szeredi 87e5e5558eSMiklos Szeredi void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, 88b48badf0SMiklos Szeredi u64 nodeid, u64 nlookup) 89e5e5558eSMiklos Szeredi { 90e5e5558eSMiklos Szeredi struct fuse_forget_in *inarg = &req->misc.forget_in; 919e6268dbSMiklos Szeredi inarg->nlookup = nlookup; 92e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_FORGET; 93e5e5558eSMiklos Szeredi req->in.h.nodeid = nodeid; 94e5e5558eSMiklos Szeredi req->in.numargs = 1; 95e5e5558eSMiklos Szeredi req->in.args[0].size = sizeof(struct fuse_forget_in); 96e5e5558eSMiklos Szeredi req->in.args[0].value = inarg; 97e5e5558eSMiklos Szeredi request_send_noreply(fc, req); 98e5e5558eSMiklos Szeredi } 99e5e5558eSMiklos Szeredi 100d8a5ba45SMiklos Szeredi static void fuse_clear_inode(struct inode *inode) 101d8a5ba45SMiklos Szeredi { 1021e9a4ed9SMiklos Szeredi if (inode->i_sb->s_flags & MS_ACTIVE) { 103e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 104e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 1059e6268dbSMiklos Szeredi fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); 106e5e5558eSMiklos Szeredi fi->forget_req = NULL; 107e5e5558eSMiklos Szeredi } 108d8a5ba45SMiklos Szeredi } 109d8a5ba45SMiklos Szeredi 11071421259SMiklos Szeredi static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) 11171421259SMiklos Szeredi { 11271421259SMiklos Szeredi if (*flags & MS_MANDLOCK) 11371421259SMiklos Szeredi return -EINVAL; 11471421259SMiklos Szeredi 11571421259SMiklos Szeredi return 0; 11671421259SMiklos Szeredi } 11771421259SMiklos Szeredi 1183be5a52bSMiklos Szeredi void fuse_truncate(struct address_space *mapping, loff_t offset) 119e00d2c2dSMiklos Szeredi { 120e00d2c2dSMiklos Szeredi /* See vmtruncate() */ 121e00d2c2dSMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 122e00d2c2dSMiklos Szeredi truncate_inode_pages(mapping, offset); 123e00d2c2dSMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 124e00d2c2dSMiklos Szeredi } 125e00d2c2dSMiklos Szeredi 1263be5a52bSMiklos Szeredi void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, 1273be5a52bSMiklos Szeredi u64 attr_valid) 128d8a5ba45SMiklos Szeredi { 1299ffbb916SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 130ebc14c4dSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 131d8a5ba45SMiklos Szeredi 1321fb69e78SMiklos Szeredi fi->attr_version = ++fc->attr_version; 1331fb69e78SMiklos Szeredi fi->i_time = attr_valid; 1341fb69e78SMiklos Szeredi 135d8a5ba45SMiklos Szeredi inode->i_ino = attr->ino; 136ebc14c4dSMiklos Szeredi inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 137d8a5ba45SMiklos Szeredi inode->i_nlink = attr->nlink; 138d8a5ba45SMiklos Szeredi inode->i_uid = attr->uid; 139d8a5ba45SMiklos Szeredi inode->i_gid = attr->gid; 140d8a5ba45SMiklos Szeredi inode->i_blocks = attr->blocks; 141d8a5ba45SMiklos Szeredi inode->i_atime.tv_sec = attr->atime; 142d8a5ba45SMiklos Szeredi inode->i_atime.tv_nsec = attr->atimensec; 143d8a5ba45SMiklos Szeredi inode->i_mtime.tv_sec = attr->mtime; 144d8a5ba45SMiklos Szeredi inode->i_mtime.tv_nsec = attr->mtimensec; 145d8a5ba45SMiklos Szeredi inode->i_ctime.tv_sec = attr->ctime; 146d8a5ba45SMiklos Szeredi inode->i_ctime.tv_nsec = attr->ctimensec; 147e00d2c2dSMiklos Szeredi 1480e9663eeSMiklos Szeredi if (attr->blksize != 0) 1490e9663eeSMiklos Szeredi inode->i_blkbits = ilog2(attr->blksize); 1500e9663eeSMiklos Szeredi else 1510e9663eeSMiklos Szeredi inode->i_blkbits = inode->i_sb->s_blocksize_bits; 1520e9663eeSMiklos Szeredi 153ebc14c4dSMiklos Szeredi /* 154ebc14c4dSMiklos Szeredi * Don't set the sticky bit in i_mode, unless we want the VFS 155ebc14c4dSMiklos Szeredi * to check permissions. This prevents failures due to the 156ebc14c4dSMiklos Szeredi * check in may_delete(). 157ebc14c4dSMiklos Szeredi */ 158ebc14c4dSMiklos Szeredi fi->orig_i_mode = inode->i_mode; 159ebc14c4dSMiklos Szeredi if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) 160ebc14c4dSMiklos Szeredi inode->i_mode &= ~S_ISVTX; 1613be5a52bSMiklos Szeredi } 1623be5a52bSMiklos Szeredi 1633be5a52bSMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, 1643be5a52bSMiklos Szeredi u64 attr_valid, u64 attr_version) 1653be5a52bSMiklos Szeredi { 1663be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1673be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 1683be5a52bSMiklos Szeredi loff_t oldsize; 1693be5a52bSMiklos Szeredi 1703be5a52bSMiklos Szeredi spin_lock(&fc->lock); 1713be5a52bSMiklos Szeredi if (attr_version != 0 && fi->attr_version > attr_version) { 1723be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 1733be5a52bSMiklos Szeredi return; 1743be5a52bSMiklos Szeredi } 1753be5a52bSMiklos Szeredi 1763be5a52bSMiklos Szeredi fuse_change_attributes_common(inode, attr, attr_valid); 177ebc14c4dSMiklos Szeredi 178e00d2c2dSMiklos Szeredi oldsize = inode->i_size; 179e00d2c2dSMiklos Szeredi i_size_write(inode, attr->size); 180e00d2c2dSMiklos Szeredi spin_unlock(&fc->lock); 181e00d2c2dSMiklos Szeredi 182e00d2c2dSMiklos Szeredi if (S_ISREG(inode->i_mode) && oldsize != attr->size) { 183e00d2c2dSMiklos Szeredi if (attr->size < oldsize) 184e00d2c2dSMiklos Szeredi fuse_truncate(inode->i_mapping, attr->size); 185b1009979SMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 186e00d2c2dSMiklos Szeredi } 187d8a5ba45SMiklos Szeredi } 188d8a5ba45SMiklos Szeredi 189d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) 190d8a5ba45SMiklos Szeredi { 191d8a5ba45SMiklos Szeredi inode->i_mode = attr->mode & S_IFMT; 1929ffbb916SMiklos Szeredi inode->i_size = attr->size; 193e5e5558eSMiklos Szeredi if (S_ISREG(inode->i_mode)) { 194e5e5558eSMiklos Szeredi fuse_init_common(inode); 195b6aeadedSMiklos Szeredi fuse_init_file_inode(inode); 196e5e5558eSMiklos Szeredi } else if (S_ISDIR(inode->i_mode)) 197e5e5558eSMiklos Szeredi fuse_init_dir(inode); 198e5e5558eSMiklos Szeredi else if (S_ISLNK(inode->i_mode)) 199e5e5558eSMiklos Szeredi fuse_init_symlink(inode); 200e5e5558eSMiklos Szeredi else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || 201e5e5558eSMiklos Szeredi S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { 202e5e5558eSMiklos Szeredi fuse_init_common(inode); 203e5e5558eSMiklos Szeredi init_special_inode(inode, inode->i_mode, 204e5e5558eSMiklos Szeredi new_decode_dev(attr->rdev)); 20539ee059aSMiklos Szeredi } else 20639ee059aSMiklos Szeredi BUG(); 207d8a5ba45SMiklos Szeredi } 208d8a5ba45SMiklos Szeredi 209d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp) 210d8a5ba45SMiklos Szeredi { 211b48badf0SMiklos Szeredi u64 nodeid = *(u64 *) _nodeidp; 212d8a5ba45SMiklos Szeredi if (get_node_id(inode) == nodeid) 213d8a5ba45SMiklos Szeredi return 1; 214d8a5ba45SMiklos Szeredi else 215d8a5ba45SMiklos Szeredi return 0; 216d8a5ba45SMiklos Szeredi } 217d8a5ba45SMiklos Szeredi 218d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp) 219d8a5ba45SMiklos Szeredi { 220b48badf0SMiklos Szeredi u64 nodeid = *(u64 *) _nodeidp; 221d8a5ba45SMiklos Szeredi get_fuse_inode(inode)->nodeid = nodeid; 222d8a5ba45SMiklos Szeredi return 0; 223d8a5ba45SMiklos Szeredi } 224d8a5ba45SMiklos Szeredi 225b48badf0SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, u64 nodeid, 2261fb69e78SMiklos Szeredi int generation, struct fuse_attr *attr, 2271fb69e78SMiklos Szeredi u64 attr_valid, u64 attr_version) 228d8a5ba45SMiklos Szeredi { 229d8a5ba45SMiklos Szeredi struct inode *inode; 2309e6268dbSMiklos Szeredi struct fuse_inode *fi; 231d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 232d8a5ba45SMiklos Szeredi 233d8a5ba45SMiklos Szeredi retry: 234d8a5ba45SMiklos Szeredi inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); 235d8a5ba45SMiklos Szeredi if (!inode) 236d8a5ba45SMiklos Szeredi return NULL; 237d8a5ba45SMiklos Szeredi 238d8a5ba45SMiklos Szeredi if ((inode->i_state & I_NEW)) { 239b36c31baSMiklos Szeredi inode->i_flags |= S_NOATIME|S_NOCMTIME; 240d8a5ba45SMiklos Szeredi inode->i_generation = generation; 241d8a5ba45SMiklos Szeredi inode->i_data.backing_dev_info = &fc->bdi; 242d8a5ba45SMiklos Szeredi fuse_init_inode(inode, attr); 243d8a5ba45SMiklos Szeredi unlock_new_inode(inode); 244d8a5ba45SMiklos Szeredi } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { 245d8a5ba45SMiklos Szeredi /* Inode has changed type, any I/O on the old should fail */ 246d8a5ba45SMiklos Szeredi make_bad_inode(inode); 247d8a5ba45SMiklos Szeredi iput(inode); 248d8a5ba45SMiklos Szeredi goto retry; 249d8a5ba45SMiklos Szeredi } 250d8a5ba45SMiklos Szeredi 2519e6268dbSMiklos Szeredi fi = get_fuse_inode(inode); 2528da5ff23SMiklos Szeredi spin_lock(&fc->lock); 2539e6268dbSMiklos Szeredi fi->nlookup++; 2548da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 2551fb69e78SMiklos Szeredi fuse_change_attributes(inode, attr, attr_valid, attr_version); 2561fb69e78SMiklos Szeredi 257d8a5ba45SMiklos Szeredi return inode; 258d8a5ba45SMiklos Szeredi } 259d8a5ba45SMiklos Szeredi 26042faad99SAl Viro static void fuse_umount_begin(struct super_block *sb) 26169a53bf2SMiklos Szeredi { 26242faad99SAl Viro fuse_abort_conn(get_fuse_conn_super(sb)); 26369a53bf2SMiklos Szeredi } 26469a53bf2SMiklos Szeredi 2650ec7ca41SMiklos Szeredi static void fuse_send_destroy(struct fuse_conn *fc) 2660ec7ca41SMiklos Szeredi { 2670ec7ca41SMiklos Szeredi struct fuse_req *req = fc->destroy_req; 2680ec7ca41SMiklos Szeredi if (req && fc->conn_init) { 2690ec7ca41SMiklos Szeredi fc->destroy_req = NULL; 2700ec7ca41SMiklos Szeredi req->in.h.opcode = FUSE_DESTROY; 2710ec7ca41SMiklos Szeredi req->force = 1; 2720ec7ca41SMiklos Szeredi request_send(fc, req); 2730ec7ca41SMiklos Szeredi fuse_put_request(fc, req); 2740ec7ca41SMiklos Szeredi } 2750ec7ca41SMiklos Szeredi } 2760ec7ca41SMiklos Szeredi 277d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb) 278d8a5ba45SMiklos Szeredi { 279d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 280d8a5ba45SMiklos Szeredi 2810ec7ca41SMiklos Szeredi fuse_send_destroy(fc); 282d7133114SMiklos Szeredi spin_lock(&fc->lock); 2839ba7cbbaSMiklos Szeredi fc->connected = 0; 28451eb01e7SMiklos Szeredi fc->blocked = 0; 285d7133114SMiklos Szeredi spin_unlock(&fc->lock); 286334f485dSMiklos Szeredi /* Flush all readers on this fs */ 287385a17bfSJeff Dike kill_fasync(&fc->fasync, SIGIO, POLL_IN); 288334f485dSMiklos Szeredi wake_up_all(&fc->waitq); 28951eb01e7SMiklos Szeredi wake_up_all(&fc->blocked_waitq); 290de5e3decSMiklos Szeredi wake_up_all(&fc->reserved_req_waitq); 291bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 292bafa9654SMiklos Szeredi list_del(&fc->entry); 293bafa9654SMiklos Szeredi fuse_ctl_remove_conn(fc); 294bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 295bafa9654SMiklos Szeredi fuse_conn_put(fc); 296d8a5ba45SMiklos Szeredi } 297d8a5ba45SMiklos Szeredi 298e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) 299e5e5558eSMiklos Szeredi { 300e5e5558eSMiklos Szeredi stbuf->f_type = FUSE_SUPER_MAGIC; 301e5e5558eSMiklos Szeredi stbuf->f_bsize = attr->bsize; 302de5f1202SMiklos Szeredi stbuf->f_frsize = attr->frsize; 303e5e5558eSMiklos Szeredi stbuf->f_blocks = attr->blocks; 304e5e5558eSMiklos Szeredi stbuf->f_bfree = attr->bfree; 305e5e5558eSMiklos Szeredi stbuf->f_bavail = attr->bavail; 306e5e5558eSMiklos Szeredi stbuf->f_files = attr->files; 307e5e5558eSMiklos Szeredi stbuf->f_ffree = attr->ffree; 308e5e5558eSMiklos Szeredi stbuf->f_namelen = attr->namelen; 309e5e5558eSMiklos Szeredi /* fsid is left zero */ 310e5e5558eSMiklos Szeredi } 311e5e5558eSMiklos Szeredi 312726c3342SDavid Howells static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) 313e5e5558eSMiklos Szeredi { 314726c3342SDavid Howells struct super_block *sb = dentry->d_sb; 315e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 316e5e5558eSMiklos Szeredi struct fuse_req *req; 317e5e5558eSMiklos Szeredi struct fuse_statfs_out outarg; 318e5e5558eSMiklos Szeredi int err; 319e5e5558eSMiklos Szeredi 320e57ac683SMiklos Szeredi if (!fuse_allow_task(fc, current)) { 321e57ac683SMiklos Szeredi buf->f_type = FUSE_SUPER_MAGIC; 322e57ac683SMiklos Szeredi return 0; 323e57ac683SMiklos Szeredi } 324e57ac683SMiklos Szeredi 325ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 326ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 327ce1d5a49SMiklos Szeredi return PTR_ERR(req); 328e5e5558eSMiklos Szeredi 329de5f1202SMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 330e5e5558eSMiklos Szeredi req->in.numargs = 0; 331e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_STATFS; 3325b35e8e5SMiklos Szeredi req->in.h.nodeid = get_node_id(dentry->d_inode); 333e5e5558eSMiklos Szeredi req->out.numargs = 1; 334de5f1202SMiklos Szeredi req->out.args[0].size = 335de5f1202SMiklos Szeredi fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); 336e5e5558eSMiklos Szeredi req->out.args[0].value = &outarg; 337e5e5558eSMiklos Szeredi request_send(fc, req); 338e5e5558eSMiklos Szeredi err = req->out.h.error; 339e5e5558eSMiklos Szeredi if (!err) 340e5e5558eSMiklos Szeredi convert_fuse_statfs(buf, &outarg.st); 341e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 342e5e5558eSMiklos Szeredi return err; 343e5e5558eSMiklos Szeredi } 344e5e5558eSMiklos Szeredi 345d8a5ba45SMiklos Szeredi enum { 346d8a5ba45SMiklos Szeredi OPT_FD, 347d8a5ba45SMiklos Szeredi OPT_ROOTMODE, 348d8a5ba45SMiklos Szeredi OPT_USER_ID, 34987729a55SMiklos Szeredi OPT_GROUP_ID, 350d8a5ba45SMiklos Szeredi OPT_DEFAULT_PERMISSIONS, 351d8a5ba45SMiklos Szeredi OPT_ALLOW_OTHER, 352db50b96cSMiklos Szeredi OPT_MAX_READ, 353d8091614SMiklos Szeredi OPT_BLKSIZE, 354d8a5ba45SMiklos Szeredi OPT_ERR 355d8a5ba45SMiklos Szeredi }; 356d8a5ba45SMiklos Szeredi 357a447c093SSteven Whitehouse static const match_table_t tokens = { 358d8a5ba45SMiklos Szeredi {OPT_FD, "fd=%u"}, 359d8a5ba45SMiklos Szeredi {OPT_ROOTMODE, "rootmode=%o"}, 360d8a5ba45SMiklos Szeredi {OPT_USER_ID, "user_id=%u"}, 36187729a55SMiklos Szeredi {OPT_GROUP_ID, "group_id=%u"}, 362d8a5ba45SMiklos Szeredi {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 363d8a5ba45SMiklos Szeredi {OPT_ALLOW_OTHER, "allow_other"}, 364db50b96cSMiklos Szeredi {OPT_MAX_READ, "max_read=%u"}, 365d8091614SMiklos Szeredi {OPT_BLKSIZE, "blksize=%u"}, 366d8a5ba45SMiklos Szeredi {OPT_ERR, NULL} 367d8a5ba45SMiklos Szeredi }; 368d8a5ba45SMiklos Szeredi 369d8091614SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) 370d8a5ba45SMiklos Szeredi { 371d8a5ba45SMiklos Szeredi char *p; 372d8a5ba45SMiklos Szeredi memset(d, 0, sizeof(struct fuse_mount_data)); 373db50b96cSMiklos Szeredi d->max_read = ~0; 374d1875dbaSMiklos Szeredi d->blksize = FUSE_DEFAULT_BLKSIZE; 375d8a5ba45SMiklos Szeredi 376d8a5ba45SMiklos Szeredi while ((p = strsep(&opt, ",")) != NULL) { 377d8a5ba45SMiklos Szeredi int token; 378d8a5ba45SMiklos Szeredi int value; 379d8a5ba45SMiklos Szeredi substring_t args[MAX_OPT_ARGS]; 380d8a5ba45SMiklos Szeredi if (!*p) 381d8a5ba45SMiklos Szeredi continue; 382d8a5ba45SMiklos Szeredi 383d8a5ba45SMiklos Szeredi token = match_token(p, tokens, args); 384d8a5ba45SMiklos Szeredi switch (token) { 385d8a5ba45SMiklos Szeredi case OPT_FD: 386d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 387d8a5ba45SMiklos Szeredi return 0; 388d8a5ba45SMiklos Szeredi d->fd = value; 3895a533682SMiklos Szeredi d->fd_present = 1; 390d8a5ba45SMiklos Szeredi break; 391d8a5ba45SMiklos Szeredi 392d8a5ba45SMiklos Szeredi case OPT_ROOTMODE: 393d8a5ba45SMiklos Szeredi if (match_octal(&args[0], &value)) 394d8a5ba45SMiklos Szeredi return 0; 395a5bfffacSTimo Savola if (!fuse_valid_type(value)) 396a5bfffacSTimo Savola return 0; 397d8a5ba45SMiklos Szeredi d->rootmode = value; 3985a533682SMiklos Szeredi d->rootmode_present = 1; 399d8a5ba45SMiklos Szeredi break; 400d8a5ba45SMiklos Szeredi 401d8a5ba45SMiklos Szeredi case OPT_USER_ID: 402d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 403d8a5ba45SMiklos Szeredi return 0; 404d8a5ba45SMiklos Szeredi d->user_id = value; 4055a533682SMiklos Szeredi d->user_id_present = 1; 406d8a5ba45SMiklos Szeredi break; 407d8a5ba45SMiklos Szeredi 40887729a55SMiklos Szeredi case OPT_GROUP_ID: 40987729a55SMiklos Szeredi if (match_int(&args[0], &value)) 41087729a55SMiklos Szeredi return 0; 41187729a55SMiklos Szeredi d->group_id = value; 4125a533682SMiklos Szeredi d->group_id_present = 1; 41387729a55SMiklos Szeredi break; 41487729a55SMiklos Szeredi 4151e9a4ed9SMiklos Szeredi case OPT_DEFAULT_PERMISSIONS: 4161e9a4ed9SMiklos Szeredi d->flags |= FUSE_DEFAULT_PERMISSIONS; 4171e9a4ed9SMiklos Szeredi break; 4181e9a4ed9SMiklos Szeredi 4191e9a4ed9SMiklos Szeredi case OPT_ALLOW_OTHER: 4201e9a4ed9SMiklos Szeredi d->flags |= FUSE_ALLOW_OTHER; 4211e9a4ed9SMiklos Szeredi break; 4221e9a4ed9SMiklos Szeredi 423db50b96cSMiklos Szeredi case OPT_MAX_READ: 424db50b96cSMiklos Szeredi if (match_int(&args[0], &value)) 425db50b96cSMiklos Szeredi return 0; 426db50b96cSMiklos Szeredi d->max_read = value; 427db50b96cSMiklos Szeredi break; 428db50b96cSMiklos Szeredi 429d8091614SMiklos Szeredi case OPT_BLKSIZE: 430d8091614SMiklos Szeredi if (!is_bdev || match_int(&args[0], &value)) 431d8091614SMiklos Szeredi return 0; 432d8091614SMiklos Szeredi d->blksize = value; 433d8091614SMiklos Szeredi break; 434d8091614SMiklos Szeredi 435d8a5ba45SMiklos Szeredi default: 436d8a5ba45SMiklos Szeredi return 0; 437d8a5ba45SMiklos Szeredi } 438d8a5ba45SMiklos Szeredi } 4395a533682SMiklos Szeredi 4405a533682SMiklos Szeredi if (!d->fd_present || !d->rootmode_present || 4415a533682SMiklos Szeredi !d->user_id_present || !d->group_id_present) 442d8a5ba45SMiklos Szeredi return 0; 443d8a5ba45SMiklos Szeredi 444d8a5ba45SMiklos Szeredi return 1; 445d8a5ba45SMiklos Szeredi } 446d8a5ba45SMiklos Szeredi 447d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) 448d8a5ba45SMiklos Szeredi { 449d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 450d8a5ba45SMiklos Szeredi 451d8a5ba45SMiklos Szeredi seq_printf(m, ",user_id=%u", fc->user_id); 45287729a55SMiklos Szeredi seq_printf(m, ",group_id=%u", fc->group_id); 4531e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) 4541e9a4ed9SMiklos Szeredi seq_puts(m, ",default_permissions"); 4551e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 4561e9a4ed9SMiklos Szeredi seq_puts(m, ",allow_other"); 457db50b96cSMiklos Szeredi if (fc->max_read != ~0) 458db50b96cSMiklos Szeredi seq_printf(m, ",max_read=%u", fc->max_read); 459d1875dbaSMiklos Szeredi if (mnt->mnt_sb->s_bdev && 460d1875dbaSMiklos Szeredi mnt->mnt_sb->s_blocksize != FUSE_DEFAULT_BLKSIZE) 461d1875dbaSMiklos Szeredi seq_printf(m, ",blksize=%lu", mnt->mnt_sb->s_blocksize); 462d8a5ba45SMiklos Szeredi return 0; 463d8a5ba45SMiklos Szeredi } 464d8a5ba45SMiklos Szeredi 465b6f2fcbcSMiklos Szeredi static struct fuse_conn *new_conn(struct super_block *sb) 466d8a5ba45SMiklos Szeredi { 467d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 468e0bf68ddSPeter Zijlstra int err; 469d8a5ba45SMiklos Szeredi 4706383bdaaSMiklos Szeredi fc = kzalloc(sizeof(*fc), GFP_KERNEL); 471f543f253SMiklos Szeredi if (fc) { 472d7133114SMiklos Szeredi spin_lock_init(&fc->lock); 473d2a85164SMiklos Szeredi mutex_init(&fc->inst_mutex); 474bafa9654SMiklos Szeredi atomic_set(&fc->count, 1); 475334f485dSMiklos Szeredi init_waitqueue_head(&fc->waitq); 47608a53cdcSMiklos Szeredi init_waitqueue_head(&fc->blocked_waitq); 477de5e3decSMiklos Szeredi init_waitqueue_head(&fc->reserved_req_waitq); 478334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->pending); 479334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->processing); 480d77a1d5bSMiklos Szeredi INIT_LIST_HEAD(&fc->io); 481a4d27e75SMiklos Szeredi INIT_LIST_HEAD(&fc->interrupts); 482d12def1bSMiklos Szeredi INIT_LIST_HEAD(&fc->bg_queue); 483095da6cbSMiklos Szeredi atomic_set(&fc->num_waiting, 0); 484d8a5ba45SMiklos Szeredi fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 485d8a5ba45SMiklos Szeredi fc->bdi.unplug_io_fn = default_unplug_io_fn; 4863be5a52bSMiklos Szeredi /* fuse does it's own writeback accounting */ 4873be5a52bSMiklos Szeredi fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB; 488b6f2fcbcSMiklos Szeredi fc->dev = sb->s_dev; 489e0bf68ddSPeter Zijlstra err = bdi_init(&fc->bdi); 490b6f2fcbcSMiklos Szeredi if (err) 491b6f2fcbcSMiklos Szeredi goto error_kfree; 49203fb0bceSMiklos Szeredi if (sb->s_bdev) { 49303fb0bceSMiklos Szeredi err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk", 49403fb0bceSMiklos Szeredi MAJOR(fc->dev), MINOR(fc->dev)); 49503fb0bceSMiklos Szeredi } else { 496b6f2fcbcSMiklos Szeredi err = bdi_register_dev(&fc->bdi, fc->dev); 49703fb0bceSMiklos Szeredi } 498b6f2fcbcSMiklos Szeredi if (err) 499b6f2fcbcSMiklos Szeredi goto error_bdi_destroy; 5003be5a52bSMiklos Szeredi /* 5013be5a52bSMiklos Szeredi * For a single fuse filesystem use max 1% of dirty + 5023be5a52bSMiklos Szeredi * writeback threshold. 5033be5a52bSMiklos Szeredi * 5043be5a52bSMiklos Szeredi * This gives about 1M of write buffer for memory maps on a 5053be5a52bSMiklos Szeredi * machine with 1G and 10% dirty_ratio, which should be more 5063be5a52bSMiklos Szeredi * than enough. 5073be5a52bSMiklos Szeredi * 5083be5a52bSMiklos Szeredi * Privileged users can raise it by writing to 5093be5a52bSMiklos Szeredi * 5103be5a52bSMiklos Szeredi * /sys/class/bdi/<bdi>/max_ratio 5113be5a52bSMiklos Szeredi */ 5123be5a52bSMiklos Szeredi bdi_set_max_ratio(&fc->bdi, 1); 513334f485dSMiklos Szeredi fc->reqctr = 0; 51408a53cdcSMiklos Szeredi fc->blocked = 1; 5151fb69e78SMiklos Szeredi fc->attr_version = 1; 5169c8ef561SMiklos Szeredi get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); 517d8a5ba45SMiklos Szeredi } 518d8a5ba45SMiklos Szeredi return fc; 519b6f2fcbcSMiklos Szeredi 520b6f2fcbcSMiklos Szeredi error_bdi_destroy: 521b6f2fcbcSMiklos Szeredi bdi_destroy(&fc->bdi); 522b6f2fcbcSMiklos Szeredi error_kfree: 523b6f2fcbcSMiklos Szeredi mutex_destroy(&fc->inst_mutex); 524b6f2fcbcSMiklos Szeredi kfree(fc); 525b6f2fcbcSMiklos Szeredi return NULL; 526d8a5ba45SMiklos Szeredi } 527d8a5ba45SMiklos Szeredi 528bafa9654SMiklos Szeredi void fuse_conn_put(struct fuse_conn *fc) 529bafa9654SMiklos Szeredi { 530d2a85164SMiklos Szeredi if (atomic_dec_and_test(&fc->count)) { 5310ec7ca41SMiklos Szeredi if (fc->destroy_req) 5320ec7ca41SMiklos Szeredi fuse_request_free(fc->destroy_req); 533d2a85164SMiklos Szeredi mutex_destroy(&fc->inst_mutex); 534e0bf68ddSPeter Zijlstra bdi_destroy(&fc->bdi); 535bafa9654SMiklos Szeredi kfree(fc); 536bafa9654SMiklos Szeredi } 537d2a85164SMiklos Szeredi } 538bafa9654SMiklos Szeredi 539bafa9654SMiklos Szeredi struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) 540bafa9654SMiklos Szeredi { 541bafa9654SMiklos Szeredi atomic_inc(&fc->count); 542bafa9654SMiklos Szeredi return fc; 543bafa9654SMiklos Szeredi } 544bafa9654SMiklos Szeredi 545d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode) 546d8a5ba45SMiklos Szeredi { 547d8a5ba45SMiklos Szeredi struct fuse_attr attr; 548d8a5ba45SMiklos Szeredi memset(&attr, 0, sizeof(attr)); 549d8a5ba45SMiklos Szeredi 550d8a5ba45SMiklos Szeredi attr.mode = mode; 551d8a5ba45SMiklos Szeredi attr.ino = FUSE_ROOT_ID; 552074406faSMiklos Szeredi attr.nlink = 1; 5531fb69e78SMiklos Szeredi return fuse_iget(sb, 1, 0, &attr, 0, 0); 554d8a5ba45SMiklos Szeredi } 555d8a5ba45SMiklos Szeredi 5561729a16cSMiklos Szeredi struct fuse_inode_handle { 557dbd561d2SMiklos Szeredi u64 nodeid; 558dbd561d2SMiklos Szeredi u32 generation; 559dbd561d2SMiklos Szeredi }; 560dbd561d2SMiklos Szeredi 561dbd561d2SMiklos Szeredi static struct dentry *fuse_get_dentry(struct super_block *sb, 562dbd561d2SMiklos Szeredi struct fuse_inode_handle *handle) 563dbd561d2SMiklos Szeredi { 56433670fa2SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 565dbd561d2SMiklos Szeredi struct inode *inode; 566dbd561d2SMiklos Szeredi struct dentry *entry; 567dbd561d2SMiklos Szeredi int err = -ESTALE; 568dbd561d2SMiklos Szeredi 569dbd561d2SMiklos Szeredi if (handle->nodeid == 0) 570dbd561d2SMiklos Szeredi goto out_err; 571dbd561d2SMiklos Szeredi 572dbd561d2SMiklos Szeredi inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); 57333670fa2SMiklos Szeredi if (!inode) { 57433670fa2SMiklos Szeredi struct fuse_entry_out outarg; 57533670fa2SMiklos Szeredi struct qstr name; 57633670fa2SMiklos Szeredi 57733670fa2SMiklos Szeredi if (!fc->export_support) 578dbd561d2SMiklos Szeredi goto out_err; 57933670fa2SMiklos Szeredi 58033670fa2SMiklos Szeredi name.len = 1; 58133670fa2SMiklos Szeredi name.name = "."; 58233670fa2SMiklos Szeredi err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg, 58333670fa2SMiklos Szeredi &inode); 58433670fa2SMiklos Szeredi if (err && err != -ENOENT) 58533670fa2SMiklos Szeredi goto out_err; 58633670fa2SMiklos Szeredi if (err || !inode) { 58733670fa2SMiklos Szeredi err = -ESTALE; 58833670fa2SMiklos Szeredi goto out_err; 58933670fa2SMiklos Szeredi } 59033670fa2SMiklos Szeredi err = -EIO; 59133670fa2SMiklos Szeredi if (get_node_id(inode) != handle->nodeid) 59233670fa2SMiklos Szeredi goto out_iput; 59333670fa2SMiklos Szeredi } 594dbd561d2SMiklos Szeredi err = -ESTALE; 595dbd561d2SMiklos Szeredi if (inode->i_generation != handle->generation) 596dbd561d2SMiklos Szeredi goto out_iput; 597dbd561d2SMiklos Szeredi 59844003728SChristoph Hellwig entry = d_obtain_alias(inode); 59944003728SChristoph Hellwig if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) { 600dbd561d2SMiklos Szeredi entry->d_op = &fuse_dentry_operations; 601dbd561d2SMiklos Szeredi fuse_invalidate_entry_cache(entry); 602dbd561d2SMiklos Szeredi } 603dbd561d2SMiklos Szeredi 604dbd561d2SMiklos Szeredi return entry; 605dbd561d2SMiklos Szeredi 606dbd561d2SMiklos Szeredi out_iput: 607dbd561d2SMiklos Szeredi iput(inode); 608dbd561d2SMiklos Szeredi out_err: 609dbd561d2SMiklos Szeredi return ERR_PTR(err); 610dbd561d2SMiklos Szeredi } 611dbd561d2SMiklos Szeredi 612dbd561d2SMiklos Szeredi static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, 613dbd561d2SMiklos Szeredi int connectable) 614dbd561d2SMiklos Szeredi { 615dbd561d2SMiklos Szeredi struct inode *inode = dentry->d_inode; 616dbd561d2SMiklos Szeredi bool encode_parent = connectable && !S_ISDIR(inode->i_mode); 617dbd561d2SMiklos Szeredi int len = encode_parent ? 6 : 3; 618dbd561d2SMiklos Szeredi u64 nodeid; 619dbd561d2SMiklos Szeredi u32 generation; 620dbd561d2SMiklos Szeredi 621dbd561d2SMiklos Szeredi if (*max_len < len) 622dbd561d2SMiklos Szeredi return 255; 623dbd561d2SMiklos Szeredi 624dbd561d2SMiklos Szeredi nodeid = get_fuse_inode(inode)->nodeid; 625dbd561d2SMiklos Szeredi generation = inode->i_generation; 626dbd561d2SMiklos Szeredi 627dbd561d2SMiklos Szeredi fh[0] = (u32)(nodeid >> 32); 628dbd561d2SMiklos Szeredi fh[1] = (u32)(nodeid & 0xffffffff); 629dbd561d2SMiklos Szeredi fh[2] = generation; 630dbd561d2SMiklos Szeredi 631dbd561d2SMiklos Szeredi if (encode_parent) { 632dbd561d2SMiklos Szeredi struct inode *parent; 633dbd561d2SMiklos Szeredi 634dbd561d2SMiklos Szeredi spin_lock(&dentry->d_lock); 635dbd561d2SMiklos Szeredi parent = dentry->d_parent->d_inode; 636dbd561d2SMiklos Szeredi nodeid = get_fuse_inode(parent)->nodeid; 637dbd561d2SMiklos Szeredi generation = parent->i_generation; 638dbd561d2SMiklos Szeredi spin_unlock(&dentry->d_lock); 639dbd561d2SMiklos Szeredi 640dbd561d2SMiklos Szeredi fh[3] = (u32)(nodeid >> 32); 641dbd561d2SMiklos Szeredi fh[4] = (u32)(nodeid & 0xffffffff); 642dbd561d2SMiklos Szeredi fh[5] = generation; 643dbd561d2SMiklos Szeredi } 644dbd561d2SMiklos Szeredi 645dbd561d2SMiklos Szeredi *max_len = len; 646dbd561d2SMiklos Szeredi return encode_parent ? 0x82 : 0x81; 647dbd561d2SMiklos Szeredi } 648dbd561d2SMiklos Szeredi 649dbd561d2SMiklos Szeredi static struct dentry *fuse_fh_to_dentry(struct super_block *sb, 650dbd561d2SMiklos Szeredi struct fid *fid, int fh_len, int fh_type) 651dbd561d2SMiklos Szeredi { 652dbd561d2SMiklos Szeredi struct fuse_inode_handle handle; 653dbd561d2SMiklos Szeredi 654dbd561d2SMiklos Szeredi if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3) 655dbd561d2SMiklos Szeredi return NULL; 656dbd561d2SMiklos Szeredi 657dbd561d2SMiklos Szeredi handle.nodeid = (u64) fid->raw[0] << 32; 658dbd561d2SMiklos Szeredi handle.nodeid |= (u64) fid->raw[1]; 659dbd561d2SMiklos Szeredi handle.generation = fid->raw[2]; 660dbd561d2SMiklos Szeredi return fuse_get_dentry(sb, &handle); 661dbd561d2SMiklos Szeredi } 662dbd561d2SMiklos Szeredi 663dbd561d2SMiklos Szeredi static struct dentry *fuse_fh_to_parent(struct super_block *sb, 664dbd561d2SMiklos Szeredi struct fid *fid, int fh_len, int fh_type) 665dbd561d2SMiklos Szeredi { 666dbd561d2SMiklos Szeredi struct fuse_inode_handle parent; 667dbd561d2SMiklos Szeredi 668dbd561d2SMiklos Szeredi if (fh_type != 0x82 || fh_len < 6) 669dbd561d2SMiklos Szeredi return NULL; 670dbd561d2SMiklos Szeredi 671dbd561d2SMiklos Szeredi parent.nodeid = (u64) fid->raw[3] << 32; 672dbd561d2SMiklos Szeredi parent.nodeid |= (u64) fid->raw[4]; 673dbd561d2SMiklos Szeredi parent.generation = fid->raw[5]; 674dbd561d2SMiklos Szeredi return fuse_get_dentry(sb, &parent); 675dbd561d2SMiklos Szeredi } 676dbd561d2SMiklos Szeredi 67733670fa2SMiklos Szeredi static struct dentry *fuse_get_parent(struct dentry *child) 67833670fa2SMiklos Szeredi { 67933670fa2SMiklos Szeredi struct inode *child_inode = child->d_inode; 68033670fa2SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(child_inode); 68133670fa2SMiklos Szeredi struct inode *inode; 68233670fa2SMiklos Szeredi struct dentry *parent; 68333670fa2SMiklos Szeredi struct fuse_entry_out outarg; 68433670fa2SMiklos Szeredi struct qstr name; 68533670fa2SMiklos Szeredi int err; 68633670fa2SMiklos Szeredi 68733670fa2SMiklos Szeredi if (!fc->export_support) 68833670fa2SMiklos Szeredi return ERR_PTR(-ESTALE); 68933670fa2SMiklos Szeredi 69033670fa2SMiklos Szeredi name.len = 2; 69133670fa2SMiklos Szeredi name.name = ".."; 69233670fa2SMiklos Szeredi err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode), 69333670fa2SMiklos Szeredi &name, &outarg, &inode); 69444003728SChristoph Hellwig if (err) { 69544003728SChristoph Hellwig if (err == -ENOENT) 69633670fa2SMiklos Szeredi return ERR_PTR(-ESTALE); 69744003728SChristoph Hellwig return ERR_PTR(err); 69833670fa2SMiklos Szeredi } 69944003728SChristoph Hellwig 70044003728SChristoph Hellwig parent = d_obtain_alias(inode); 70144003728SChristoph Hellwig if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID) { 70233670fa2SMiklos Szeredi parent->d_op = &fuse_dentry_operations; 70333670fa2SMiklos Szeredi fuse_invalidate_entry_cache(parent); 70433670fa2SMiklos Szeredi } 70533670fa2SMiklos Szeredi 70633670fa2SMiklos Szeredi return parent; 70733670fa2SMiklos Szeredi } 708dbd561d2SMiklos Szeredi 709dbd561d2SMiklos Szeredi static const struct export_operations fuse_export_operations = { 710dbd561d2SMiklos Szeredi .fh_to_dentry = fuse_fh_to_dentry, 711dbd561d2SMiklos Szeredi .fh_to_parent = fuse_fh_to_parent, 712dbd561d2SMiklos Szeredi .encode_fh = fuse_encode_fh, 71333670fa2SMiklos Szeredi .get_parent = fuse_get_parent, 714dbd561d2SMiklos Szeredi }; 715dbd561d2SMiklos Szeredi 716ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = { 717d8a5ba45SMiklos Szeredi .alloc_inode = fuse_alloc_inode, 718d8a5ba45SMiklos Szeredi .destroy_inode = fuse_destroy_inode, 719d8a5ba45SMiklos Szeredi .clear_inode = fuse_clear_inode, 720ead5f0b5SMiklos Szeredi .drop_inode = generic_delete_inode, 72171421259SMiklos Szeredi .remount_fs = fuse_remount_fs, 722d8a5ba45SMiklos Szeredi .put_super = fuse_put_super, 72369a53bf2SMiklos Szeredi .umount_begin = fuse_umount_begin, 724e5e5558eSMiklos Szeredi .statfs = fuse_statfs, 725d8a5ba45SMiklos Szeredi .show_options = fuse_show_options, 726d8a5ba45SMiklos Szeredi }; 727d8a5ba45SMiklos Szeredi 7289b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) 7299b9a0469SMiklos Szeredi { 7309b9a0469SMiklos Szeredi struct fuse_init_out *arg = &req->misc.init_out; 7319b9a0469SMiklos Szeredi 7329b9a0469SMiklos Szeredi if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) 7339b9a0469SMiklos Szeredi fc->conn_error = 1; 7349b9a0469SMiklos Szeredi else { 7359cd68455SMiklos Szeredi unsigned long ra_pages; 7369cd68455SMiklos Szeredi 7379cd68455SMiklos Szeredi if (arg->minor >= 6) { 7389cd68455SMiklos Szeredi ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; 7399cd68455SMiklos Szeredi if (arg->flags & FUSE_ASYNC_READ) 7409cd68455SMiklos Szeredi fc->async_read = 1; 74171421259SMiklos Szeredi if (!(arg->flags & FUSE_POSIX_LOCKS)) 74271421259SMiklos Szeredi fc->no_lock = 1; 7436ff958edSMiklos Szeredi if (arg->flags & FUSE_ATOMIC_O_TRUNC) 7446ff958edSMiklos Szeredi fc->atomic_o_trunc = 1; 74533670fa2SMiklos Szeredi if (arg->minor >= 9) { 74633670fa2SMiklos Szeredi /* LOOKUP has dependency on proto version */ 74733670fa2SMiklos Szeredi if (arg->flags & FUSE_EXPORT_SUPPORT) 74833670fa2SMiklos Szeredi fc->export_support = 1; 74933670fa2SMiklos Szeredi } 75078bb6cb9SMiklos Szeredi if (arg->flags & FUSE_BIG_WRITES) 75178bb6cb9SMiklos Szeredi fc->big_writes = 1; 75271421259SMiklos Szeredi } else { 7539cd68455SMiklos Szeredi ra_pages = fc->max_read / PAGE_CACHE_SIZE; 75471421259SMiklos Szeredi fc->no_lock = 1; 75571421259SMiklos Szeredi } 7569cd68455SMiklos Szeredi 7579cd68455SMiklos Szeredi fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); 7589b9a0469SMiklos Szeredi fc->minor = arg->minor; 7599b9a0469SMiklos Szeredi fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; 760f948d564SMiklos Szeredi fc->max_write = max_t(unsigned, 4096, fc->max_write); 7610ec7ca41SMiklos Szeredi fc->conn_init = 1; 7629b9a0469SMiklos Szeredi } 7639b9a0469SMiklos Szeredi fuse_put_request(fc, req); 76408a53cdcSMiklos Szeredi fc->blocked = 0; 76508a53cdcSMiklos Szeredi wake_up_all(&fc->blocked_waitq); 7669b9a0469SMiklos Szeredi } 7679b9a0469SMiklos Szeredi 768ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) 7699b9a0469SMiklos Szeredi { 7709b9a0469SMiklos Szeredi struct fuse_init_in *arg = &req->misc.init_in; 771095da6cbSMiklos Szeredi 7729b9a0469SMiklos Szeredi arg->major = FUSE_KERNEL_VERSION; 7739b9a0469SMiklos Szeredi arg->minor = FUSE_KERNEL_MINOR_VERSION; 7749cd68455SMiklos Szeredi arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; 77578bb6cb9SMiklos Szeredi arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | 77633670fa2SMiklos Szeredi FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES; 7779b9a0469SMiklos Szeredi req->in.h.opcode = FUSE_INIT; 7789b9a0469SMiklos Szeredi req->in.numargs = 1; 7799b9a0469SMiklos Szeredi req->in.args[0].size = sizeof(*arg); 7809b9a0469SMiklos Szeredi req->in.args[0].value = arg; 7819b9a0469SMiklos Szeredi req->out.numargs = 1; 7829b9a0469SMiklos Szeredi /* Variable length arguement used for backward compatibility 7839b9a0469SMiklos Szeredi with interface version < 7.5. Rest of init_out is zeroed 7849b9a0469SMiklos Szeredi by do_get_request(), so a short reply is not a problem */ 7859b9a0469SMiklos Szeredi req->out.argvar = 1; 7869b9a0469SMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_init_out); 7879b9a0469SMiklos Szeredi req->out.args[0].value = &req->misc.init_out; 7889b9a0469SMiklos Szeredi req->end = process_init_reply; 7899b9a0469SMiklos Szeredi request_send_background(fc, req); 7909b9a0469SMiklos Szeredi } 7919b9a0469SMiklos Szeredi 792d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent) 793d8a5ba45SMiklos Szeredi { 794d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 795d8a5ba45SMiklos Szeredi struct inode *root; 796d8a5ba45SMiklos Szeredi struct fuse_mount_data d; 797d8a5ba45SMiklos Szeredi struct file *file; 798f543f253SMiklos Szeredi struct dentry *root_dentry; 799ce1d5a49SMiklos Szeredi struct fuse_req *init_req; 800d8a5ba45SMiklos Szeredi int err; 801d8091614SMiklos Szeredi int is_bdev = sb->s_bdev != NULL; 802d8a5ba45SMiklos Szeredi 80371421259SMiklos Szeredi if (sb->s_flags & MS_MANDLOCK) 80471421259SMiklos Szeredi return -EINVAL; 80571421259SMiklos Szeredi 806d8091614SMiklos Szeredi if (!parse_fuse_opt((char *) data, &d, is_bdev)) 807d8a5ba45SMiklos Szeredi return -EINVAL; 808d8a5ba45SMiklos Szeredi 809d8091614SMiklos Szeredi if (is_bdev) { 810875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 811d8091614SMiklos Szeredi if (!sb_set_blocksize(sb, d.blksize)) 812d8091614SMiklos Szeredi return -EINVAL; 813875d95ecSMiklos Szeredi #endif 814d8091614SMiklos Szeredi } else { 815d8a5ba45SMiklos Szeredi sb->s_blocksize = PAGE_CACHE_SIZE; 816d8a5ba45SMiklos Szeredi sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 817d8091614SMiklos Szeredi } 818d8a5ba45SMiklos Szeredi sb->s_magic = FUSE_SUPER_MAGIC; 819d8a5ba45SMiklos Szeredi sb->s_op = &fuse_super_operations; 820d8a5ba45SMiklos Szeredi sb->s_maxbytes = MAX_LFS_FILESIZE; 821dbd561d2SMiklos Szeredi sb->s_export_op = &fuse_export_operations; 822d8a5ba45SMiklos Szeredi 823d8a5ba45SMiklos Szeredi file = fget(d.fd); 824d8a5ba45SMiklos Szeredi if (!file) 825d8a5ba45SMiklos Szeredi return -EINVAL; 826d8a5ba45SMiklos Szeredi 8270720b315SMiklos Szeredi if (file->f_op != &fuse_dev_operations) 8280720b315SMiklos Szeredi return -EINVAL; 8290720b315SMiklos Szeredi 830b6f2fcbcSMiklos Szeredi fc = new_conn(sb); 8310720b315SMiklos Szeredi if (!fc) 8320720b315SMiklos Szeredi return -ENOMEM; 833d8a5ba45SMiklos Szeredi 8341e9a4ed9SMiklos Szeredi fc->flags = d.flags; 835d8a5ba45SMiklos Szeredi fc->user_id = d.user_id; 83687729a55SMiklos Szeredi fc->group_id = d.group_id; 837f948d564SMiklos Szeredi fc->max_read = max_t(unsigned, 4096, d.max_read); 838d8a5ba45SMiklos Szeredi 839f543f253SMiklos Szeredi /* Used by get_root_inode() */ 840f543f253SMiklos Szeredi sb->s_fs_info = fc; 841f543f253SMiklos Szeredi 842d8a5ba45SMiklos Szeredi err = -ENOMEM; 843d8a5ba45SMiklos Szeredi root = get_root_inode(sb, d.rootmode); 844f543f253SMiklos Szeredi if (!root) 845d8a5ba45SMiklos Szeredi goto err; 846d8a5ba45SMiklos Szeredi 847f543f253SMiklos Szeredi root_dentry = d_alloc_root(root); 848f543f253SMiklos Szeredi if (!root_dentry) { 849d8a5ba45SMiklos Szeredi iput(root); 850d8a5ba45SMiklos Szeredi goto err; 851d8a5ba45SMiklos Szeredi } 852f543f253SMiklos Szeredi 853ce1d5a49SMiklos Szeredi init_req = fuse_request_alloc(); 854ce1d5a49SMiklos Szeredi if (!init_req) 855ce1d5a49SMiklos Szeredi goto err_put_root; 856ce1d5a49SMiklos Szeredi 8570ec7ca41SMiklos Szeredi if (is_bdev) { 8580ec7ca41SMiklos Szeredi fc->destroy_req = fuse_request_alloc(); 8590ec7ca41SMiklos Szeredi if (!fc->destroy_req) 86017e18ab6SJulia Lawall goto err_free_init_req; 8610ec7ca41SMiklos Szeredi } 8620ec7ca41SMiklos Szeredi 863bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 8648aa09a50SMiklos Szeredi err = -EINVAL; 8658aa09a50SMiklos Szeredi if (file->private_data) 866bafa9654SMiklos Szeredi goto err_unlock; 8678aa09a50SMiklos Szeredi 868bafa9654SMiklos Szeredi err = fuse_ctl_add_conn(fc); 869bafa9654SMiklos Szeredi if (err) 870bafa9654SMiklos Szeredi goto err_unlock; 871bafa9654SMiklos Szeredi 872bafa9654SMiklos Szeredi list_add_tail(&fc->entry, &fuse_conn_list); 873f543f253SMiklos Szeredi sb->s_root = root_dentry; 874f543f253SMiklos Szeredi fc->connected = 1; 875bafa9654SMiklos Szeredi file->private_data = fuse_conn_get(fc); 876bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 8770720b315SMiklos Szeredi /* 8780720b315SMiklos Szeredi * atomic_dec_and_test() in fput() provides the necessary 8790720b315SMiklos Szeredi * memory barrier for file->private_data to be visible on all 8800720b315SMiklos Szeredi * CPUs after this 8810720b315SMiklos Szeredi */ 8820720b315SMiklos Szeredi fput(file); 883f543f253SMiklos Szeredi 884ce1d5a49SMiklos Szeredi fuse_send_init(fc, init_req); 885f543f253SMiklos Szeredi 886d8a5ba45SMiklos Szeredi return 0; 887d8a5ba45SMiklos Szeredi 888bafa9654SMiklos Szeredi err_unlock: 889bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 89017e18ab6SJulia Lawall err_free_init_req: 891ce1d5a49SMiklos Szeredi fuse_request_free(init_req); 892f543f253SMiklos Szeredi err_put_root: 893f543f253SMiklos Szeredi dput(root_dentry); 894d8a5ba45SMiklos Szeredi err: 8950720b315SMiklos Szeredi fput(file); 896bafa9654SMiklos Szeredi fuse_conn_put(fc); 897d8a5ba45SMiklos Szeredi return err; 898d8a5ba45SMiklos Szeredi } 899d8a5ba45SMiklos Szeredi 900454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type, 901d8a5ba45SMiklos Szeredi int flags, const char *dev_name, 902454e2398SDavid Howells void *raw_data, struct vfsmount *mnt) 903d8a5ba45SMiklos Szeredi { 904454e2398SDavid Howells return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); 905d8a5ba45SMiklos Szeredi } 906d8a5ba45SMiklos Szeredi 907875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = { 908875d95ecSMiklos Szeredi .owner = THIS_MODULE, 909875d95ecSMiklos Szeredi .name = "fuse", 91079c0b2dfSMiklos Szeredi .fs_flags = FS_HAS_SUBTYPE, 911875d95ecSMiklos Szeredi .get_sb = fuse_get_sb, 912875d95ecSMiklos Szeredi .kill_sb = kill_anon_super, 913875d95ecSMiklos Szeredi }; 914875d95ecSMiklos Szeredi 915875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 916d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type, 917d6392f87SMiklos Szeredi int flags, const char *dev_name, 918d6392f87SMiklos Szeredi void *raw_data, struct vfsmount *mnt) 919d6392f87SMiklos Szeredi { 920d6392f87SMiklos Szeredi return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, 921d6392f87SMiklos Szeredi mnt); 922d6392f87SMiklos Szeredi } 923d6392f87SMiklos Szeredi 924d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = { 925d6392f87SMiklos Szeredi .owner = THIS_MODULE, 926d6392f87SMiklos Szeredi .name = "fuseblk", 927d6392f87SMiklos Szeredi .get_sb = fuse_get_sb_blk, 928d6392f87SMiklos Szeredi .kill_sb = kill_block_super, 929edad01e2SAlexey Dobriyan .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, 930d6392f87SMiklos Szeredi }; 931d6392f87SMiklos Szeredi 932875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 933875d95ecSMiklos Szeredi { 934875d95ecSMiklos Szeredi return register_filesystem(&fuseblk_fs_type); 935875d95ecSMiklos Szeredi } 936875d95ecSMiklos Szeredi 937875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 938875d95ecSMiklos Szeredi { 939875d95ecSMiklos Szeredi unregister_filesystem(&fuseblk_fs_type); 940875d95ecSMiklos Szeredi } 941875d95ecSMiklos Szeredi #else 942875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 943875d95ecSMiklos Szeredi { 944875d95ecSMiklos Szeredi return 0; 945875d95ecSMiklos Szeredi } 946875d95ecSMiklos Szeredi 947875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 948875d95ecSMiklos Szeredi { 949875d95ecSMiklos Szeredi } 950875d95ecSMiklos Szeredi #endif 951875d95ecSMiklos Szeredi 95251cc5068SAlexey Dobriyan static void fuse_inode_init_once(void *foo) 953d8a5ba45SMiklos Szeredi { 954d8a5ba45SMiklos Szeredi struct inode *inode = foo; 955d8a5ba45SMiklos Szeredi 956d8a5ba45SMiklos Szeredi inode_init_once(inode); 957d8a5ba45SMiklos Szeredi } 958d8a5ba45SMiklos Szeredi 959d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void) 960d8a5ba45SMiklos Szeredi { 961d8a5ba45SMiklos Szeredi int err; 962d8a5ba45SMiklos Szeredi 963d8a5ba45SMiklos Szeredi err = register_filesystem(&fuse_fs_type); 964d8a5ba45SMiklos Szeredi if (err) 965d6392f87SMiklos Szeredi goto out; 966d6392f87SMiklos Szeredi 967875d95ecSMiklos Szeredi err = register_fuseblk(); 968d6392f87SMiklos Szeredi if (err) 969d6392f87SMiklos Szeredi goto out_unreg; 970d6392f87SMiklos Szeredi 971d8a5ba45SMiklos Szeredi fuse_inode_cachep = kmem_cache_create("fuse_inode", 972d8a5ba45SMiklos Szeredi sizeof(struct fuse_inode), 973d8a5ba45SMiklos Szeredi 0, SLAB_HWCACHE_ALIGN, 97420c2df83SPaul Mundt fuse_inode_init_once); 975d8a5ba45SMiklos Szeredi err = -ENOMEM; 976d6392f87SMiklos Szeredi if (!fuse_inode_cachep) 977d6392f87SMiklos Szeredi goto out_unreg2; 978d8a5ba45SMiklos Szeredi 979d6392f87SMiklos Szeredi return 0; 980d6392f87SMiklos Szeredi 981d6392f87SMiklos Szeredi out_unreg2: 982875d95ecSMiklos Szeredi unregister_fuseblk(); 983d6392f87SMiklos Szeredi out_unreg: 984d6392f87SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 985d6392f87SMiklos Szeredi out: 986d8a5ba45SMiklos Szeredi return err; 987d8a5ba45SMiklos Szeredi } 988d8a5ba45SMiklos Szeredi 989d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void) 990d8a5ba45SMiklos Szeredi { 991d8a5ba45SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 992875d95ecSMiklos Szeredi unregister_fuseblk(); 993d8a5ba45SMiklos Szeredi kmem_cache_destroy(fuse_inode_cachep); 994d8a5ba45SMiklos Szeredi } 995d8a5ba45SMiklos Szeredi 9965c89e17eSGreg Kroah-Hartman static struct kobject *fuse_kobj; 9975c89e17eSGreg Kroah-Hartman static struct kobject *connections_kobj; 9985c89e17eSGreg Kroah-Hartman 999f543f253SMiklos Szeredi static int fuse_sysfs_init(void) 1000f543f253SMiklos Szeredi { 1001f543f253SMiklos Szeredi int err; 1002f543f253SMiklos Szeredi 100300d26666SGreg Kroah-Hartman fuse_kobj = kobject_create_and_add("fuse", fs_kobj); 10045c89e17eSGreg Kroah-Hartman if (!fuse_kobj) { 10055c89e17eSGreg Kroah-Hartman err = -ENOMEM; 1006f543f253SMiklos Szeredi goto out_err; 10075c89e17eSGreg Kroah-Hartman } 1008f543f253SMiklos Szeredi 10095c89e17eSGreg Kroah-Hartman connections_kobj = kobject_create_and_add("connections", fuse_kobj); 10105c89e17eSGreg Kroah-Hartman if (!connections_kobj) { 10115c89e17eSGreg Kroah-Hartman err = -ENOMEM; 1012f543f253SMiklos Szeredi goto out_fuse_unregister; 10135c89e17eSGreg Kroah-Hartman } 1014f543f253SMiklos Szeredi 1015f543f253SMiklos Szeredi return 0; 1016f543f253SMiklos Szeredi 1017f543f253SMiklos Szeredi out_fuse_unregister: 1018197b12d6SGreg Kroah-Hartman kobject_put(fuse_kobj); 1019f543f253SMiklos Szeredi out_err: 1020f543f253SMiklos Szeredi return err; 1021f543f253SMiklos Szeredi } 1022f543f253SMiklos Szeredi 1023f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void) 1024f543f253SMiklos Szeredi { 1025197b12d6SGreg Kroah-Hartman kobject_put(connections_kobj); 1026197b12d6SGreg Kroah-Hartman kobject_put(fuse_kobj); 1027f543f253SMiklos Szeredi } 1028f543f253SMiklos Szeredi 1029d8a5ba45SMiklos Szeredi static int __init fuse_init(void) 1030d8a5ba45SMiklos Szeredi { 1031d8a5ba45SMiklos Szeredi int res; 1032d8a5ba45SMiklos Szeredi 10331729a16cSMiklos Szeredi printk(KERN_INFO "fuse init (API version %i.%i)\n", 1034d8a5ba45SMiklos Szeredi FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 1035d8a5ba45SMiklos Szeredi 1036bafa9654SMiklos Szeredi INIT_LIST_HEAD(&fuse_conn_list); 1037d8a5ba45SMiklos Szeredi res = fuse_fs_init(); 1038d8a5ba45SMiklos Szeredi if (res) 1039d8a5ba45SMiklos Szeredi goto err; 1040d8a5ba45SMiklos Szeredi 1041334f485dSMiklos Szeredi res = fuse_dev_init(); 1042334f485dSMiklos Szeredi if (res) 1043334f485dSMiklos Szeredi goto err_fs_cleanup; 1044334f485dSMiklos Szeredi 1045f543f253SMiklos Szeredi res = fuse_sysfs_init(); 1046f543f253SMiklos Szeredi if (res) 1047f543f253SMiklos Szeredi goto err_dev_cleanup; 1048f543f253SMiklos Szeredi 1049bafa9654SMiklos Szeredi res = fuse_ctl_init(); 1050bafa9654SMiklos Szeredi if (res) 1051bafa9654SMiklos Szeredi goto err_sysfs_cleanup; 1052bafa9654SMiklos Szeredi 1053d8a5ba45SMiklos Szeredi return 0; 1054d8a5ba45SMiklos Szeredi 1055bafa9654SMiklos Szeredi err_sysfs_cleanup: 1056bafa9654SMiklos Szeredi fuse_sysfs_cleanup(); 1057f543f253SMiklos Szeredi err_dev_cleanup: 1058f543f253SMiklos Szeredi fuse_dev_cleanup(); 1059334f485dSMiklos Szeredi err_fs_cleanup: 1060334f485dSMiklos Szeredi fuse_fs_cleanup(); 1061d8a5ba45SMiklos Szeredi err: 1062d8a5ba45SMiklos Szeredi return res; 1063d8a5ba45SMiklos Szeredi } 1064d8a5ba45SMiklos Szeredi 1065d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void) 1066d8a5ba45SMiklos Szeredi { 1067d8a5ba45SMiklos Szeredi printk(KERN_DEBUG "fuse exit\n"); 1068d8a5ba45SMiklos Szeredi 1069bafa9654SMiklos Szeredi fuse_ctl_cleanup(); 1070f543f253SMiklos Szeredi fuse_sysfs_cleanup(); 1071d8a5ba45SMiklos Szeredi fuse_fs_cleanup(); 1072334f485dSMiklos Szeredi fuse_dev_cleanup(); 1073d8a5ba45SMiklos Szeredi } 1074d8a5ba45SMiklos Szeredi 1075d8a5ba45SMiklos Szeredi module_init(fuse_init); 1076d8a5ba45SMiklos Szeredi module_exit(fuse_exit); 1077