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 32d1875dbaSMiklos Szeredi #define FUSE_DEFAULT_BLKSIZE 512 33d1875dbaSMiklos Szeredi 34d8a5ba45SMiklos Szeredi struct fuse_mount_data { 35d8a5ba45SMiklos Szeredi int fd; 36d8a5ba45SMiklos Szeredi unsigned rootmode; 37d8a5ba45SMiklos Szeredi unsigned user_id; 3887729a55SMiklos Szeredi unsigned group_id; 395a533682SMiklos Szeredi unsigned fd_present : 1; 405a533682SMiklos Szeredi unsigned rootmode_present : 1; 415a533682SMiklos Szeredi unsigned user_id_present : 1; 425a533682SMiklos Szeredi unsigned group_id_present : 1; 431e9a4ed9SMiklos Szeredi unsigned flags; 44db50b96cSMiklos Szeredi unsigned max_read; 45d8091614SMiklos Szeredi unsigned blksize; 46d8a5ba45SMiklos Szeredi }; 47d8a5ba45SMiklos Szeredi 48d8a5ba45SMiklos Szeredi static struct inode *fuse_alloc_inode(struct super_block *sb) 49d8a5ba45SMiklos Szeredi { 50d8a5ba45SMiklos Szeredi struct inode *inode; 51d8a5ba45SMiklos Szeredi struct fuse_inode *fi; 52d8a5ba45SMiklos Szeredi 53e94b1766SChristoph Lameter inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); 54d8a5ba45SMiklos Szeredi if (!inode) 55d8a5ba45SMiklos Szeredi return NULL; 56d8a5ba45SMiklos Szeredi 57d8a5ba45SMiklos Szeredi fi = get_fuse_inode(inode); 580a0898cfSMiklos Szeredi fi->i_time = 0; 59d8a5ba45SMiklos Szeredi fi->nodeid = 0; 609e6268dbSMiklos Szeredi fi->nlookup = 0; 61fbee36b9SJohn Muir fi->attr_version = 0; 6293a8c3cdSMiklos Szeredi INIT_LIST_HEAD(&fi->write_files); 63e5e5558eSMiklos Szeredi fi->forget_req = fuse_request_alloc(); 64e5e5558eSMiklos Szeredi if (!fi->forget_req) { 65e5e5558eSMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 66e5e5558eSMiklos Szeredi return NULL; 67e5e5558eSMiklos Szeredi } 68d8a5ba45SMiklos Szeredi 69d8a5ba45SMiklos Szeredi return inode; 70d8a5ba45SMiklos Szeredi } 71d8a5ba45SMiklos Szeredi 72d8a5ba45SMiklos Szeredi static void fuse_destroy_inode(struct inode *inode) 73d8a5ba45SMiklos Szeredi { 74e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 7593a8c3cdSMiklos Szeredi BUG_ON(!list_empty(&fi->write_files)); 76e5e5558eSMiklos Szeredi if (fi->forget_req) 77e5e5558eSMiklos Szeredi fuse_request_free(fi->forget_req); 78d8a5ba45SMiklos Szeredi kmem_cache_free(fuse_inode_cachep, inode); 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 112e00d2c2dSMiklos Szeredi static void fuse_truncate(struct address_space *mapping, loff_t offset) 113e00d2c2dSMiklos Szeredi { 114e00d2c2dSMiklos Szeredi /* See vmtruncate() */ 115e00d2c2dSMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 116e00d2c2dSMiklos Szeredi truncate_inode_pages(mapping, offset); 117e00d2c2dSMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 118e00d2c2dSMiklos Szeredi } 119e00d2c2dSMiklos Szeredi 1201fb69e78SMiklos Szeredi 1211fb69e78SMiklos Szeredi void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, 1221fb69e78SMiklos Szeredi u64 attr_valid, u64 attr_version) 123d8a5ba45SMiklos Szeredi { 1249ffbb916SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 125ebc14c4dSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 126e00d2c2dSMiklos Szeredi loff_t oldsize; 127d8a5ba45SMiklos Szeredi 1281fb69e78SMiklos Szeredi spin_lock(&fc->lock); 1291fb69e78SMiklos Szeredi if (attr_version != 0 && fi->attr_version > attr_version) { 1301fb69e78SMiklos Szeredi spin_unlock(&fc->lock); 1311fb69e78SMiklos Szeredi return; 1321fb69e78SMiklos Szeredi } 1331fb69e78SMiklos Szeredi fi->attr_version = ++fc->attr_version; 1341fb69e78SMiklos Szeredi fi->i_time = attr_valid; 1351fb69e78SMiklos Szeredi 136d8a5ba45SMiklos Szeredi inode->i_ino = attr->ino; 137ebc14c4dSMiklos Szeredi inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 138d8a5ba45SMiklos Szeredi inode->i_nlink = attr->nlink; 139d8a5ba45SMiklos Szeredi inode->i_uid = attr->uid; 140d8a5ba45SMiklos Szeredi inode->i_gid = attr->gid; 141d8a5ba45SMiklos Szeredi inode->i_blocks = attr->blocks; 142d8a5ba45SMiklos Szeredi inode->i_atime.tv_sec = attr->atime; 143d8a5ba45SMiklos Szeredi inode->i_atime.tv_nsec = attr->atimensec; 144d8a5ba45SMiklos Szeredi inode->i_mtime.tv_sec = attr->mtime; 145d8a5ba45SMiklos Szeredi inode->i_mtime.tv_nsec = attr->mtimensec; 146d8a5ba45SMiklos Szeredi inode->i_ctime.tv_sec = attr->ctime; 147d8a5ba45SMiklos Szeredi inode->i_ctime.tv_nsec = attr->ctimensec; 148e00d2c2dSMiklos Szeredi 1490e9663eeSMiklos Szeredi if (attr->blksize != 0) 1500e9663eeSMiklos Szeredi inode->i_blkbits = ilog2(attr->blksize); 1510e9663eeSMiklos Szeredi else 1520e9663eeSMiklos Szeredi inode->i_blkbits = inode->i_sb->s_blocksize_bits; 1530e9663eeSMiklos Szeredi 154ebc14c4dSMiklos Szeredi /* 155ebc14c4dSMiklos Szeredi * Don't set the sticky bit in i_mode, unless we want the VFS 156ebc14c4dSMiklos Szeredi * to check permissions. This prevents failures due to the 157ebc14c4dSMiklos Szeredi * check in may_delete(). 158ebc14c4dSMiklos Szeredi */ 159ebc14c4dSMiklos Szeredi fi->orig_i_mode = inode->i_mode; 160ebc14c4dSMiklos Szeredi if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) 161ebc14c4dSMiklos Szeredi inode->i_mode &= ~S_ISVTX; 162ebc14c4dSMiklos Szeredi 163e00d2c2dSMiklos Szeredi oldsize = inode->i_size; 164e00d2c2dSMiklos Szeredi i_size_write(inode, attr->size); 165e00d2c2dSMiklos Szeredi spin_unlock(&fc->lock); 166e00d2c2dSMiklos Szeredi 167e00d2c2dSMiklos Szeredi if (S_ISREG(inode->i_mode) && oldsize != attr->size) { 168e00d2c2dSMiklos Szeredi if (attr->size < oldsize) 169e00d2c2dSMiklos Szeredi fuse_truncate(inode->i_mapping, attr->size); 170b1009979SMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 171e00d2c2dSMiklos Szeredi } 172d8a5ba45SMiklos Szeredi } 173d8a5ba45SMiklos Szeredi 174d8a5ba45SMiklos Szeredi static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) 175d8a5ba45SMiklos Szeredi { 176d8a5ba45SMiklos Szeredi inode->i_mode = attr->mode & S_IFMT; 1779ffbb916SMiklos Szeredi inode->i_size = attr->size; 178e5e5558eSMiklos Szeredi if (S_ISREG(inode->i_mode)) { 179e5e5558eSMiklos Szeredi fuse_init_common(inode); 180b6aeadedSMiklos Szeredi fuse_init_file_inode(inode); 181e5e5558eSMiklos Szeredi } else if (S_ISDIR(inode->i_mode)) 182e5e5558eSMiklos Szeredi fuse_init_dir(inode); 183e5e5558eSMiklos Szeredi else if (S_ISLNK(inode->i_mode)) 184e5e5558eSMiklos Szeredi fuse_init_symlink(inode); 185e5e5558eSMiklos Szeredi else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || 186e5e5558eSMiklos Szeredi S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { 187e5e5558eSMiklos Szeredi fuse_init_common(inode); 188e5e5558eSMiklos Szeredi init_special_inode(inode, inode->i_mode, 189e5e5558eSMiklos Szeredi new_decode_dev(attr->rdev)); 19039ee059aSMiklos Szeredi } else 19139ee059aSMiklos Szeredi BUG(); 192d8a5ba45SMiklos Szeredi } 193d8a5ba45SMiklos Szeredi 194d8a5ba45SMiklos Szeredi static int fuse_inode_eq(struct inode *inode, void *_nodeidp) 195d8a5ba45SMiklos Szeredi { 196d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 197d8a5ba45SMiklos Szeredi if (get_node_id(inode) == nodeid) 198d8a5ba45SMiklos Szeredi return 1; 199d8a5ba45SMiklos Szeredi else 200d8a5ba45SMiklos Szeredi return 0; 201d8a5ba45SMiklos Szeredi } 202d8a5ba45SMiklos Szeredi 203d8a5ba45SMiklos Szeredi static int fuse_inode_set(struct inode *inode, void *_nodeidp) 204d8a5ba45SMiklos Szeredi { 205d8a5ba45SMiklos Szeredi unsigned long nodeid = *(unsigned long *) _nodeidp; 206d8a5ba45SMiklos Szeredi get_fuse_inode(inode)->nodeid = nodeid; 207d8a5ba45SMiklos Szeredi return 0; 208d8a5ba45SMiklos Szeredi } 209d8a5ba45SMiklos Szeredi 210d8a5ba45SMiklos Szeredi struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 2111fb69e78SMiklos Szeredi int generation, struct fuse_attr *attr, 2121fb69e78SMiklos Szeredi u64 attr_valid, u64 attr_version) 213d8a5ba45SMiklos Szeredi { 214d8a5ba45SMiklos Szeredi struct inode *inode; 2159e6268dbSMiklos Szeredi struct fuse_inode *fi; 216d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 217d8a5ba45SMiklos Szeredi 218d8a5ba45SMiklos Szeredi retry: 219d8a5ba45SMiklos Szeredi inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); 220d8a5ba45SMiklos Szeredi if (!inode) 221d8a5ba45SMiklos Szeredi return NULL; 222d8a5ba45SMiklos Szeredi 223d8a5ba45SMiklos Szeredi if ((inode->i_state & I_NEW)) { 224b36c31baSMiklos Szeredi inode->i_flags |= S_NOATIME|S_NOCMTIME; 225d8a5ba45SMiklos Szeredi inode->i_generation = generation; 226d8a5ba45SMiklos Szeredi inode->i_data.backing_dev_info = &fc->bdi; 227d8a5ba45SMiklos Szeredi fuse_init_inode(inode, attr); 228d8a5ba45SMiklos Szeredi unlock_new_inode(inode); 229d8a5ba45SMiklos Szeredi } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { 230d8a5ba45SMiklos Szeredi /* Inode has changed type, any I/O on the old should fail */ 231d8a5ba45SMiklos Szeredi make_bad_inode(inode); 232d8a5ba45SMiklos Szeredi iput(inode); 233d8a5ba45SMiklos Szeredi goto retry; 234d8a5ba45SMiklos Szeredi } 235d8a5ba45SMiklos Szeredi 2369e6268dbSMiklos Szeredi fi = get_fuse_inode(inode); 2378da5ff23SMiklos Szeredi spin_lock(&fc->lock); 2389e6268dbSMiklos Szeredi fi->nlookup ++; 2398da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 2401fb69e78SMiklos Szeredi fuse_change_attributes(inode, attr, attr_valid, attr_version); 2411fb69e78SMiklos Szeredi 242d8a5ba45SMiklos Szeredi return inode; 243d8a5ba45SMiklos Szeredi } 244d8a5ba45SMiklos Szeredi 24542faad99SAl Viro static void fuse_umount_begin(struct super_block *sb) 24669a53bf2SMiklos Szeredi { 24742faad99SAl Viro fuse_abort_conn(get_fuse_conn_super(sb)); 24869a53bf2SMiklos Szeredi } 24969a53bf2SMiklos Szeredi 2500ec7ca41SMiklos Szeredi static void fuse_send_destroy(struct fuse_conn *fc) 2510ec7ca41SMiklos Szeredi { 2520ec7ca41SMiklos Szeredi struct fuse_req *req = fc->destroy_req; 2530ec7ca41SMiklos Szeredi if (req && fc->conn_init) { 2540ec7ca41SMiklos Szeredi fc->destroy_req = NULL; 2550ec7ca41SMiklos Szeredi req->in.h.opcode = FUSE_DESTROY; 2560ec7ca41SMiklos Szeredi req->force = 1; 2570ec7ca41SMiklos Szeredi request_send(fc, req); 2580ec7ca41SMiklos Szeredi fuse_put_request(fc, req); 2590ec7ca41SMiklos Szeredi } 2600ec7ca41SMiklos Szeredi } 2610ec7ca41SMiklos Szeredi 262d8a5ba45SMiklos Szeredi static void fuse_put_super(struct super_block *sb) 263d8a5ba45SMiklos Szeredi { 264d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 265d8a5ba45SMiklos Szeredi 2660ec7ca41SMiklos Szeredi fuse_send_destroy(fc); 267d7133114SMiklos Szeredi spin_lock(&fc->lock); 2689ba7cbbaSMiklos Szeredi fc->connected = 0; 26951eb01e7SMiklos Szeredi fc->blocked = 0; 270d7133114SMiklos Szeredi spin_unlock(&fc->lock); 271334f485dSMiklos Szeredi /* Flush all readers on this fs */ 272385a17bfSJeff Dike kill_fasync(&fc->fasync, SIGIO, POLL_IN); 273334f485dSMiklos Szeredi wake_up_all(&fc->waitq); 27451eb01e7SMiklos Szeredi wake_up_all(&fc->blocked_waitq); 275de5e3decSMiklos Szeredi wake_up_all(&fc->reserved_req_waitq); 276bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 277bafa9654SMiklos Szeredi list_del(&fc->entry); 278bafa9654SMiklos Szeredi fuse_ctl_remove_conn(fc); 279bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 280bafa9654SMiklos Szeredi fuse_conn_put(fc); 281d8a5ba45SMiklos Szeredi } 282d8a5ba45SMiklos Szeredi 283e5e5558eSMiklos Szeredi static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) 284e5e5558eSMiklos Szeredi { 285e5e5558eSMiklos Szeredi stbuf->f_type = FUSE_SUPER_MAGIC; 286e5e5558eSMiklos Szeredi stbuf->f_bsize = attr->bsize; 287de5f1202SMiklos Szeredi stbuf->f_frsize = attr->frsize; 288e5e5558eSMiklos Szeredi stbuf->f_blocks = attr->blocks; 289e5e5558eSMiklos Szeredi stbuf->f_bfree = attr->bfree; 290e5e5558eSMiklos Szeredi stbuf->f_bavail = attr->bavail; 291e5e5558eSMiklos Szeredi stbuf->f_files = attr->files; 292e5e5558eSMiklos Szeredi stbuf->f_ffree = attr->ffree; 293e5e5558eSMiklos Szeredi stbuf->f_namelen = attr->namelen; 294e5e5558eSMiklos Szeredi /* fsid is left zero */ 295e5e5558eSMiklos Szeredi } 296e5e5558eSMiklos Szeredi 297726c3342SDavid Howells static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) 298e5e5558eSMiklos Szeredi { 299726c3342SDavid Howells struct super_block *sb = dentry->d_sb; 300e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 301e5e5558eSMiklos Szeredi struct fuse_req *req; 302e5e5558eSMiklos Szeredi struct fuse_statfs_out outarg; 303e5e5558eSMiklos Szeredi int err; 304e5e5558eSMiklos Szeredi 305e57ac683SMiklos Szeredi if (!fuse_allow_task(fc, current)) { 306e57ac683SMiklos Szeredi buf->f_type = FUSE_SUPER_MAGIC; 307e57ac683SMiklos Szeredi return 0; 308e57ac683SMiklos Szeredi } 309e57ac683SMiklos Szeredi 310ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 311ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 312ce1d5a49SMiklos Szeredi return PTR_ERR(req); 313e5e5558eSMiklos Szeredi 314de5f1202SMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 315e5e5558eSMiklos Szeredi req->in.numargs = 0; 316e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_STATFS; 3175b35e8e5SMiklos Szeredi req->in.h.nodeid = get_node_id(dentry->d_inode); 318e5e5558eSMiklos Szeredi req->out.numargs = 1; 319de5f1202SMiklos Szeredi req->out.args[0].size = 320de5f1202SMiklos Szeredi fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); 321e5e5558eSMiklos Szeredi req->out.args[0].value = &outarg; 322e5e5558eSMiklos Szeredi request_send(fc, req); 323e5e5558eSMiklos Szeredi err = req->out.h.error; 324e5e5558eSMiklos Szeredi if (!err) 325e5e5558eSMiklos Szeredi convert_fuse_statfs(buf, &outarg.st); 326e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 327e5e5558eSMiklos Szeredi return err; 328e5e5558eSMiklos Szeredi } 329e5e5558eSMiklos Szeredi 330d8a5ba45SMiklos Szeredi enum { 331d8a5ba45SMiklos Szeredi OPT_FD, 332d8a5ba45SMiklos Szeredi OPT_ROOTMODE, 333d8a5ba45SMiklos Szeredi OPT_USER_ID, 33487729a55SMiklos Szeredi OPT_GROUP_ID, 335d8a5ba45SMiklos Szeredi OPT_DEFAULT_PERMISSIONS, 336d8a5ba45SMiklos Szeredi OPT_ALLOW_OTHER, 337db50b96cSMiklos Szeredi OPT_MAX_READ, 338d8091614SMiklos Szeredi OPT_BLKSIZE, 339d8a5ba45SMiklos Szeredi OPT_ERR 340d8a5ba45SMiklos Szeredi }; 341d8a5ba45SMiklos Szeredi 342d8a5ba45SMiklos Szeredi static match_table_t tokens = { 343d8a5ba45SMiklos Szeredi {OPT_FD, "fd=%u"}, 344d8a5ba45SMiklos Szeredi {OPT_ROOTMODE, "rootmode=%o"}, 345d8a5ba45SMiklos Szeredi {OPT_USER_ID, "user_id=%u"}, 34687729a55SMiklos Szeredi {OPT_GROUP_ID, "group_id=%u"}, 347d8a5ba45SMiklos Szeredi {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 348d8a5ba45SMiklos Szeredi {OPT_ALLOW_OTHER, "allow_other"}, 349db50b96cSMiklos Szeredi {OPT_MAX_READ, "max_read=%u"}, 350d8091614SMiklos Szeredi {OPT_BLKSIZE, "blksize=%u"}, 351d8a5ba45SMiklos Szeredi {OPT_ERR, NULL} 352d8a5ba45SMiklos Szeredi }; 353d8a5ba45SMiklos Szeredi 354d8091614SMiklos Szeredi static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) 355d8a5ba45SMiklos Szeredi { 356d8a5ba45SMiklos Szeredi char *p; 357d8a5ba45SMiklos Szeredi memset(d, 0, sizeof(struct fuse_mount_data)); 358db50b96cSMiklos Szeredi d->max_read = ~0; 359d1875dbaSMiklos Szeredi d->blksize = FUSE_DEFAULT_BLKSIZE; 360d8a5ba45SMiklos Szeredi 361d8a5ba45SMiklos Szeredi while ((p = strsep(&opt, ",")) != NULL) { 362d8a5ba45SMiklos Szeredi int token; 363d8a5ba45SMiklos Szeredi int value; 364d8a5ba45SMiklos Szeredi substring_t args[MAX_OPT_ARGS]; 365d8a5ba45SMiklos Szeredi if (!*p) 366d8a5ba45SMiklos Szeredi continue; 367d8a5ba45SMiklos Szeredi 368d8a5ba45SMiklos Szeredi token = match_token(p, tokens, args); 369d8a5ba45SMiklos Szeredi switch (token) { 370d8a5ba45SMiklos Szeredi case OPT_FD: 371d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 372d8a5ba45SMiklos Szeredi return 0; 373d8a5ba45SMiklos Szeredi d->fd = value; 3745a533682SMiklos Szeredi d->fd_present = 1; 375d8a5ba45SMiklos Szeredi break; 376d8a5ba45SMiklos Szeredi 377d8a5ba45SMiklos Szeredi case OPT_ROOTMODE: 378d8a5ba45SMiklos Szeredi if (match_octal(&args[0], &value)) 379d8a5ba45SMiklos Szeredi return 0; 380a5bfffacSTimo Savola if (!fuse_valid_type(value)) 381a5bfffacSTimo Savola return 0; 382d8a5ba45SMiklos Szeredi d->rootmode = value; 3835a533682SMiklos Szeredi d->rootmode_present = 1; 384d8a5ba45SMiklos Szeredi break; 385d8a5ba45SMiklos Szeredi 386d8a5ba45SMiklos Szeredi case OPT_USER_ID: 387d8a5ba45SMiklos Szeredi if (match_int(&args[0], &value)) 388d8a5ba45SMiklos Szeredi return 0; 389d8a5ba45SMiklos Szeredi d->user_id = value; 3905a533682SMiklos Szeredi d->user_id_present = 1; 391d8a5ba45SMiklos Szeredi break; 392d8a5ba45SMiklos Szeredi 39387729a55SMiklos Szeredi case OPT_GROUP_ID: 39487729a55SMiklos Szeredi if (match_int(&args[0], &value)) 39587729a55SMiklos Szeredi return 0; 39687729a55SMiklos Szeredi d->group_id = value; 3975a533682SMiklos Szeredi d->group_id_present = 1; 39887729a55SMiklos Szeredi break; 39987729a55SMiklos Szeredi 4001e9a4ed9SMiklos Szeredi case OPT_DEFAULT_PERMISSIONS: 4011e9a4ed9SMiklos Szeredi d->flags |= FUSE_DEFAULT_PERMISSIONS; 4021e9a4ed9SMiklos Szeredi break; 4031e9a4ed9SMiklos Szeredi 4041e9a4ed9SMiklos Szeredi case OPT_ALLOW_OTHER: 4051e9a4ed9SMiklos Szeredi d->flags |= FUSE_ALLOW_OTHER; 4061e9a4ed9SMiklos Szeredi break; 4071e9a4ed9SMiklos Szeredi 408db50b96cSMiklos Szeredi case OPT_MAX_READ: 409db50b96cSMiklos Szeredi if (match_int(&args[0], &value)) 410db50b96cSMiklos Szeredi return 0; 411db50b96cSMiklos Szeredi d->max_read = value; 412db50b96cSMiklos Szeredi break; 413db50b96cSMiklos Szeredi 414d8091614SMiklos Szeredi case OPT_BLKSIZE: 415d8091614SMiklos Szeredi if (!is_bdev || match_int(&args[0], &value)) 416d8091614SMiklos Szeredi return 0; 417d8091614SMiklos Szeredi d->blksize = value; 418d8091614SMiklos Szeredi break; 419d8091614SMiklos Szeredi 420d8a5ba45SMiklos Szeredi default: 421d8a5ba45SMiklos Szeredi return 0; 422d8a5ba45SMiklos Szeredi } 423d8a5ba45SMiklos Szeredi } 4245a533682SMiklos Szeredi 4255a533682SMiklos Szeredi if (!d->fd_present || !d->rootmode_present || 4265a533682SMiklos Szeredi !d->user_id_present || !d->group_id_present) 427d8a5ba45SMiklos Szeredi return 0; 428d8a5ba45SMiklos Szeredi 429d8a5ba45SMiklos Szeredi return 1; 430d8a5ba45SMiklos Szeredi } 431d8a5ba45SMiklos Szeredi 432d8a5ba45SMiklos Szeredi static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) 433d8a5ba45SMiklos Szeredi { 434d8a5ba45SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 435d8a5ba45SMiklos Szeredi 436d8a5ba45SMiklos Szeredi seq_printf(m, ",user_id=%u", fc->user_id); 43787729a55SMiklos Szeredi seq_printf(m, ",group_id=%u", fc->group_id); 4381e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) 4391e9a4ed9SMiklos Szeredi seq_puts(m, ",default_permissions"); 4401e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 4411e9a4ed9SMiklos Szeredi seq_puts(m, ",allow_other"); 442db50b96cSMiklos Szeredi if (fc->max_read != ~0) 443db50b96cSMiklos Szeredi seq_printf(m, ",max_read=%u", fc->max_read); 444d1875dbaSMiklos Szeredi if (mnt->mnt_sb->s_bdev && 445d1875dbaSMiklos Szeredi mnt->mnt_sb->s_blocksize != FUSE_DEFAULT_BLKSIZE) 446d1875dbaSMiklos Szeredi seq_printf(m, ",blksize=%lu", mnt->mnt_sb->s_blocksize); 447d8a5ba45SMiklos Szeredi return 0; 448d8a5ba45SMiklos Szeredi } 449d8a5ba45SMiklos Szeredi 450*b6f2fcbcSMiklos Szeredi static struct fuse_conn *new_conn(struct super_block *sb) 451d8a5ba45SMiklos Szeredi { 452d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 453e0bf68ddSPeter Zijlstra int err; 454d8a5ba45SMiklos Szeredi 4556383bdaaSMiklos Szeredi fc = kzalloc(sizeof(*fc), GFP_KERNEL); 456f543f253SMiklos Szeredi if (fc) { 457d7133114SMiklos Szeredi spin_lock_init(&fc->lock); 458d2a85164SMiklos Szeredi mutex_init(&fc->inst_mutex); 459bafa9654SMiklos Szeredi atomic_set(&fc->count, 1); 460334f485dSMiklos Szeredi init_waitqueue_head(&fc->waitq); 46108a53cdcSMiklos Szeredi init_waitqueue_head(&fc->blocked_waitq); 462de5e3decSMiklos Szeredi init_waitqueue_head(&fc->reserved_req_waitq); 463334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->pending); 464334f485dSMiklos Szeredi INIT_LIST_HEAD(&fc->processing); 465d77a1d5bSMiklos Szeredi INIT_LIST_HEAD(&fc->io); 466a4d27e75SMiklos Szeredi INIT_LIST_HEAD(&fc->interrupts); 467d12def1bSMiklos Szeredi INIT_LIST_HEAD(&fc->bg_queue); 468095da6cbSMiklos Szeredi atomic_set(&fc->num_waiting, 0); 469d8a5ba45SMiklos Szeredi fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 470d8a5ba45SMiklos Szeredi fc->bdi.unplug_io_fn = default_unplug_io_fn; 471*b6f2fcbcSMiklos Szeredi fc->dev = sb->s_dev; 472e0bf68ddSPeter Zijlstra err = bdi_init(&fc->bdi); 473*b6f2fcbcSMiklos Szeredi if (err) 474*b6f2fcbcSMiklos Szeredi goto error_kfree; 475*b6f2fcbcSMiklos Szeredi err = bdi_register_dev(&fc->bdi, fc->dev); 476*b6f2fcbcSMiklos Szeredi if (err) 477*b6f2fcbcSMiklos Szeredi goto error_bdi_destroy; 478334f485dSMiklos Szeredi fc->reqctr = 0; 47908a53cdcSMiklos Szeredi fc->blocked = 1; 4801fb69e78SMiklos Szeredi fc->attr_version = 1; 4819c8ef561SMiklos Szeredi get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); 482d8a5ba45SMiklos Szeredi } 483d8a5ba45SMiklos Szeredi return fc; 484*b6f2fcbcSMiklos Szeredi 485*b6f2fcbcSMiklos Szeredi error_bdi_destroy: 486*b6f2fcbcSMiklos Szeredi bdi_destroy(&fc->bdi); 487*b6f2fcbcSMiklos Szeredi error_kfree: 488*b6f2fcbcSMiklos Szeredi mutex_destroy(&fc->inst_mutex); 489*b6f2fcbcSMiklos Szeredi kfree(fc); 490*b6f2fcbcSMiklos Szeredi return NULL; 491d8a5ba45SMiklos Szeredi } 492d8a5ba45SMiklos Szeredi 493bafa9654SMiklos Szeredi void fuse_conn_put(struct fuse_conn *fc) 494bafa9654SMiklos Szeredi { 495d2a85164SMiklos Szeredi if (atomic_dec_and_test(&fc->count)) { 4960ec7ca41SMiklos Szeredi if (fc->destroy_req) 4970ec7ca41SMiklos Szeredi fuse_request_free(fc->destroy_req); 498d2a85164SMiklos Szeredi mutex_destroy(&fc->inst_mutex); 499e0bf68ddSPeter Zijlstra bdi_destroy(&fc->bdi); 500bafa9654SMiklos Szeredi kfree(fc); 501bafa9654SMiklos Szeredi } 502d2a85164SMiklos Szeredi } 503bafa9654SMiklos Szeredi 504bafa9654SMiklos Szeredi struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) 505bafa9654SMiklos Szeredi { 506bafa9654SMiklos Szeredi atomic_inc(&fc->count); 507bafa9654SMiklos Szeredi return fc; 508bafa9654SMiklos Szeredi } 509bafa9654SMiklos Szeredi 510d8a5ba45SMiklos Szeredi static struct inode *get_root_inode(struct super_block *sb, unsigned mode) 511d8a5ba45SMiklos Szeredi { 512d8a5ba45SMiklos Szeredi struct fuse_attr attr; 513d8a5ba45SMiklos Szeredi memset(&attr, 0, sizeof(attr)); 514d8a5ba45SMiklos Szeredi 515d8a5ba45SMiklos Szeredi attr.mode = mode; 516d8a5ba45SMiklos Szeredi attr.ino = FUSE_ROOT_ID; 517074406faSMiklos Szeredi attr.nlink = 1; 5181fb69e78SMiklos Szeredi return fuse_iget(sb, 1, 0, &attr, 0, 0); 519d8a5ba45SMiklos Szeredi } 520d8a5ba45SMiklos Szeredi 521ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations fuse_super_operations = { 522d8a5ba45SMiklos Szeredi .alloc_inode = fuse_alloc_inode, 523d8a5ba45SMiklos Szeredi .destroy_inode = fuse_destroy_inode, 524d8a5ba45SMiklos Szeredi .clear_inode = fuse_clear_inode, 525ead5f0b5SMiklos Szeredi .drop_inode = generic_delete_inode, 52671421259SMiklos Szeredi .remount_fs = fuse_remount_fs, 527d8a5ba45SMiklos Szeredi .put_super = fuse_put_super, 52869a53bf2SMiklos Szeredi .umount_begin = fuse_umount_begin, 529e5e5558eSMiklos Szeredi .statfs = fuse_statfs, 530d8a5ba45SMiklos Szeredi .show_options = fuse_show_options, 531d8a5ba45SMiklos Szeredi }; 532d8a5ba45SMiklos Szeredi 5339b9a0469SMiklos Szeredi static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) 5349b9a0469SMiklos Szeredi { 5359b9a0469SMiklos Szeredi struct fuse_init_out *arg = &req->misc.init_out; 5369b9a0469SMiklos Szeredi 5379b9a0469SMiklos Szeredi if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) 5389b9a0469SMiklos Szeredi fc->conn_error = 1; 5399b9a0469SMiklos Szeredi else { 5409cd68455SMiklos Szeredi unsigned long ra_pages; 5419cd68455SMiklos Szeredi 5429cd68455SMiklos Szeredi if (arg->minor >= 6) { 5439cd68455SMiklos Szeredi ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; 5449cd68455SMiklos Szeredi if (arg->flags & FUSE_ASYNC_READ) 5459cd68455SMiklos Szeredi fc->async_read = 1; 54671421259SMiklos Szeredi if (!(arg->flags & FUSE_POSIX_LOCKS)) 54771421259SMiklos Szeredi fc->no_lock = 1; 5486ff958edSMiklos Szeredi if (arg->flags & FUSE_ATOMIC_O_TRUNC) 5496ff958edSMiklos Szeredi fc->atomic_o_trunc = 1; 55071421259SMiklos Szeredi } else { 5519cd68455SMiklos Szeredi ra_pages = fc->max_read / PAGE_CACHE_SIZE; 55271421259SMiklos Szeredi fc->no_lock = 1; 55371421259SMiklos Szeredi } 5549cd68455SMiklos Szeredi 5559cd68455SMiklos Szeredi fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); 5569b9a0469SMiklos Szeredi fc->minor = arg->minor; 5579b9a0469SMiklos Szeredi fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; 5580ec7ca41SMiklos Szeredi fc->conn_init = 1; 5599b9a0469SMiklos Szeredi } 5609b9a0469SMiklos Szeredi fuse_put_request(fc, req); 56108a53cdcSMiklos Szeredi fc->blocked = 0; 56208a53cdcSMiklos Szeredi wake_up_all(&fc->blocked_waitq); 5639b9a0469SMiklos Szeredi } 5649b9a0469SMiklos Szeredi 565ce1d5a49SMiklos Szeredi static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) 5669b9a0469SMiklos Szeredi { 5679b9a0469SMiklos Szeredi struct fuse_init_in *arg = &req->misc.init_in; 568095da6cbSMiklos Szeredi 5699b9a0469SMiklos Szeredi arg->major = FUSE_KERNEL_VERSION; 5709b9a0469SMiklos Szeredi arg->minor = FUSE_KERNEL_MINOR_VERSION; 5719cd68455SMiklos Szeredi arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; 572d0186b25SMiklos Szeredi arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC; 5739b9a0469SMiklos Szeredi req->in.h.opcode = FUSE_INIT; 5749b9a0469SMiklos Szeredi req->in.numargs = 1; 5759b9a0469SMiklos Szeredi req->in.args[0].size = sizeof(*arg); 5769b9a0469SMiklos Szeredi req->in.args[0].value = arg; 5779b9a0469SMiklos Szeredi req->out.numargs = 1; 5789b9a0469SMiklos Szeredi /* Variable length arguement used for backward compatibility 5799b9a0469SMiklos Szeredi with interface version < 7.5. Rest of init_out is zeroed 5809b9a0469SMiklos Szeredi by do_get_request(), so a short reply is not a problem */ 5819b9a0469SMiklos Szeredi req->out.argvar = 1; 5829b9a0469SMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_init_out); 5839b9a0469SMiklos Szeredi req->out.args[0].value = &req->misc.init_out; 5849b9a0469SMiklos Szeredi req->end = process_init_reply; 5859b9a0469SMiklos Szeredi request_send_background(fc, req); 5869b9a0469SMiklos Szeredi } 5879b9a0469SMiklos Szeredi 588d8a5ba45SMiklos Szeredi static int fuse_fill_super(struct super_block *sb, void *data, int silent) 589d8a5ba45SMiklos Szeredi { 590d8a5ba45SMiklos Szeredi struct fuse_conn *fc; 591d8a5ba45SMiklos Szeredi struct inode *root; 592d8a5ba45SMiklos Szeredi struct fuse_mount_data d; 593d8a5ba45SMiklos Szeredi struct file *file; 594f543f253SMiklos Szeredi struct dentry *root_dentry; 595ce1d5a49SMiklos Szeredi struct fuse_req *init_req; 596d8a5ba45SMiklos Szeredi int err; 597d8091614SMiklos Szeredi int is_bdev = sb->s_bdev != NULL; 598d8a5ba45SMiklos Szeredi 59971421259SMiklos Szeredi if (sb->s_flags & MS_MANDLOCK) 60071421259SMiklos Szeredi return -EINVAL; 60171421259SMiklos Szeredi 602d8091614SMiklos Szeredi if (!parse_fuse_opt((char *) data, &d, is_bdev)) 603d8a5ba45SMiklos Szeredi return -EINVAL; 604d8a5ba45SMiklos Szeredi 605d8091614SMiklos Szeredi if (is_bdev) { 606875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 607d8091614SMiklos Szeredi if (!sb_set_blocksize(sb, d.blksize)) 608d8091614SMiklos Szeredi return -EINVAL; 609875d95ecSMiklos Szeredi #endif 610d8091614SMiklos Szeredi } else { 611d8a5ba45SMiklos Szeredi sb->s_blocksize = PAGE_CACHE_SIZE; 612d8a5ba45SMiklos Szeredi sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 613d8091614SMiklos Szeredi } 614d8a5ba45SMiklos Szeredi sb->s_magic = FUSE_SUPER_MAGIC; 615d8a5ba45SMiklos Szeredi sb->s_op = &fuse_super_operations; 616d8a5ba45SMiklos Szeredi sb->s_maxbytes = MAX_LFS_FILESIZE; 617d8a5ba45SMiklos Szeredi 618d8a5ba45SMiklos Szeredi file = fget(d.fd); 619d8a5ba45SMiklos Szeredi if (!file) 620d8a5ba45SMiklos Szeredi return -EINVAL; 621d8a5ba45SMiklos Szeredi 6220720b315SMiklos Szeredi if (file->f_op != &fuse_dev_operations) 6230720b315SMiklos Szeredi return -EINVAL; 6240720b315SMiklos Szeredi 625*b6f2fcbcSMiklos Szeredi fc = new_conn(sb); 6260720b315SMiklos Szeredi if (!fc) 6270720b315SMiklos Szeredi return -ENOMEM; 628d8a5ba45SMiklos Szeredi 6291e9a4ed9SMiklos Szeredi fc->flags = d.flags; 630d8a5ba45SMiklos Szeredi fc->user_id = d.user_id; 63187729a55SMiklos Szeredi fc->group_id = d.group_id; 632db50b96cSMiklos Szeredi fc->max_read = d.max_read; 633d8a5ba45SMiklos Szeredi 634f543f253SMiklos Szeredi /* Used by get_root_inode() */ 635f543f253SMiklos Szeredi sb->s_fs_info = fc; 636f543f253SMiklos Szeredi 637d8a5ba45SMiklos Szeredi err = -ENOMEM; 638d8a5ba45SMiklos Szeredi root = get_root_inode(sb, d.rootmode); 639f543f253SMiklos Szeredi if (!root) 640d8a5ba45SMiklos Szeredi goto err; 641d8a5ba45SMiklos Szeredi 642f543f253SMiklos Szeredi root_dentry = d_alloc_root(root); 643f543f253SMiklos Szeredi if (!root_dentry) { 644d8a5ba45SMiklos Szeredi iput(root); 645d8a5ba45SMiklos Szeredi goto err; 646d8a5ba45SMiklos Szeredi } 647f543f253SMiklos Szeredi 648ce1d5a49SMiklos Szeredi init_req = fuse_request_alloc(); 649ce1d5a49SMiklos Szeredi if (!init_req) 650ce1d5a49SMiklos Szeredi goto err_put_root; 651ce1d5a49SMiklos Szeredi 6520ec7ca41SMiklos Szeredi if (is_bdev) { 6530ec7ca41SMiklos Szeredi fc->destroy_req = fuse_request_alloc(); 6540ec7ca41SMiklos Szeredi if (!fc->destroy_req) 6550ec7ca41SMiklos Szeredi goto err_put_root; 6560ec7ca41SMiklos Szeredi } 6570ec7ca41SMiklos Szeredi 658bafa9654SMiklos Szeredi mutex_lock(&fuse_mutex); 6598aa09a50SMiklos Szeredi err = -EINVAL; 6608aa09a50SMiklos Szeredi if (file->private_data) 661bafa9654SMiklos Szeredi goto err_unlock; 6628aa09a50SMiklos Szeredi 663bafa9654SMiklos Szeredi err = fuse_ctl_add_conn(fc); 664bafa9654SMiklos Szeredi if (err) 665bafa9654SMiklos Szeredi goto err_unlock; 666bafa9654SMiklos Szeredi 667bafa9654SMiklos Szeredi list_add_tail(&fc->entry, &fuse_conn_list); 668f543f253SMiklos Szeredi sb->s_root = root_dentry; 669f543f253SMiklos Szeredi fc->connected = 1; 670bafa9654SMiklos Szeredi file->private_data = fuse_conn_get(fc); 671bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 6720720b315SMiklos Szeredi /* 6730720b315SMiklos Szeredi * atomic_dec_and_test() in fput() provides the necessary 6740720b315SMiklos Szeredi * memory barrier for file->private_data to be visible on all 6750720b315SMiklos Szeredi * CPUs after this 6760720b315SMiklos Szeredi */ 6770720b315SMiklos Szeredi fput(file); 678f543f253SMiklos Szeredi 679ce1d5a49SMiklos Szeredi fuse_send_init(fc, init_req); 680f543f253SMiklos Szeredi 681d8a5ba45SMiklos Szeredi return 0; 682d8a5ba45SMiklos Szeredi 683bafa9654SMiklos Szeredi err_unlock: 684bafa9654SMiklos Szeredi mutex_unlock(&fuse_mutex); 685ce1d5a49SMiklos Szeredi fuse_request_free(init_req); 686f543f253SMiklos Szeredi err_put_root: 687f543f253SMiklos Szeredi dput(root_dentry); 688d8a5ba45SMiklos Szeredi err: 6890720b315SMiklos Szeredi fput(file); 690bafa9654SMiklos Szeredi fuse_conn_put(fc); 691d8a5ba45SMiklos Szeredi return err; 692d8a5ba45SMiklos Szeredi } 693d8a5ba45SMiklos Szeredi 694454e2398SDavid Howells static int fuse_get_sb(struct file_system_type *fs_type, 695d8a5ba45SMiklos Szeredi int flags, const char *dev_name, 696454e2398SDavid Howells void *raw_data, struct vfsmount *mnt) 697d8a5ba45SMiklos Szeredi { 698454e2398SDavid Howells return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); 699d8a5ba45SMiklos Szeredi } 700d8a5ba45SMiklos Szeredi 701875d95ecSMiklos Szeredi static struct file_system_type fuse_fs_type = { 702875d95ecSMiklos Szeredi .owner = THIS_MODULE, 703875d95ecSMiklos Szeredi .name = "fuse", 70479c0b2dfSMiklos Szeredi .fs_flags = FS_HAS_SUBTYPE, 705875d95ecSMiklos Szeredi .get_sb = fuse_get_sb, 706875d95ecSMiklos Szeredi .kill_sb = kill_anon_super, 707875d95ecSMiklos Szeredi }; 708875d95ecSMiklos Szeredi 709875d95ecSMiklos Szeredi #ifdef CONFIG_BLOCK 710d6392f87SMiklos Szeredi static int fuse_get_sb_blk(struct file_system_type *fs_type, 711d6392f87SMiklos Szeredi int flags, const char *dev_name, 712d6392f87SMiklos Szeredi void *raw_data, struct vfsmount *mnt) 713d6392f87SMiklos Szeredi { 714d6392f87SMiklos Szeredi return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, 715d6392f87SMiklos Szeredi mnt); 716d6392f87SMiklos Szeredi } 717d6392f87SMiklos Szeredi 718d6392f87SMiklos Szeredi static struct file_system_type fuseblk_fs_type = { 719d6392f87SMiklos Szeredi .owner = THIS_MODULE, 720d6392f87SMiklos Szeredi .name = "fuseblk", 721d6392f87SMiklos Szeredi .get_sb = fuse_get_sb_blk, 722d6392f87SMiklos Szeredi .kill_sb = kill_block_super, 723edad01e2SAlexey Dobriyan .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, 724d6392f87SMiklos Szeredi }; 725d6392f87SMiklos Szeredi 726875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 727875d95ecSMiklos Szeredi { 728875d95ecSMiklos Szeredi return register_filesystem(&fuseblk_fs_type); 729875d95ecSMiklos Szeredi } 730875d95ecSMiklos Szeredi 731875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 732875d95ecSMiklos Szeredi { 733875d95ecSMiklos Szeredi unregister_filesystem(&fuseblk_fs_type); 734875d95ecSMiklos Szeredi } 735875d95ecSMiklos Szeredi #else 736875d95ecSMiklos Szeredi static inline int register_fuseblk(void) 737875d95ecSMiklos Szeredi { 738875d95ecSMiklos Szeredi return 0; 739875d95ecSMiklos Szeredi } 740875d95ecSMiklos Szeredi 741875d95ecSMiklos Szeredi static inline void unregister_fuseblk(void) 742875d95ecSMiklos Szeredi { 743875d95ecSMiklos Szeredi } 744875d95ecSMiklos Szeredi #endif 745875d95ecSMiklos Szeredi 7464ba9b9d0SChristoph Lameter static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo) 747d8a5ba45SMiklos Szeredi { 748d8a5ba45SMiklos Szeredi struct inode * inode = foo; 749d8a5ba45SMiklos Szeredi 750d8a5ba45SMiklos Szeredi inode_init_once(inode); 751d8a5ba45SMiklos Szeredi } 752d8a5ba45SMiklos Szeredi 753d8a5ba45SMiklos Szeredi static int __init fuse_fs_init(void) 754d8a5ba45SMiklos Szeredi { 755d8a5ba45SMiklos Szeredi int err; 756d8a5ba45SMiklos Szeredi 757d8a5ba45SMiklos Szeredi err = register_filesystem(&fuse_fs_type); 758d8a5ba45SMiklos Szeredi if (err) 759d6392f87SMiklos Szeredi goto out; 760d6392f87SMiklos Szeredi 761875d95ecSMiklos Szeredi err = register_fuseblk(); 762d6392f87SMiklos Szeredi if (err) 763d6392f87SMiklos Szeredi goto out_unreg; 764d6392f87SMiklos Szeredi 765d8a5ba45SMiklos Szeredi fuse_inode_cachep = kmem_cache_create("fuse_inode", 766d8a5ba45SMiklos Szeredi sizeof(struct fuse_inode), 767d8a5ba45SMiklos Szeredi 0, SLAB_HWCACHE_ALIGN, 76820c2df83SPaul Mundt fuse_inode_init_once); 769d8a5ba45SMiklos Szeredi err = -ENOMEM; 770d6392f87SMiklos Szeredi if (!fuse_inode_cachep) 771d6392f87SMiklos Szeredi goto out_unreg2; 772d8a5ba45SMiklos Szeredi 773d6392f87SMiklos Szeredi return 0; 774d6392f87SMiklos Szeredi 775d6392f87SMiklos Szeredi out_unreg2: 776875d95ecSMiklos Szeredi unregister_fuseblk(); 777d6392f87SMiklos Szeredi out_unreg: 778d6392f87SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 779d6392f87SMiklos Szeredi out: 780d8a5ba45SMiklos Szeredi return err; 781d8a5ba45SMiklos Szeredi } 782d8a5ba45SMiklos Szeredi 783d8a5ba45SMiklos Szeredi static void fuse_fs_cleanup(void) 784d8a5ba45SMiklos Szeredi { 785d8a5ba45SMiklos Szeredi unregister_filesystem(&fuse_fs_type); 786875d95ecSMiklos Szeredi unregister_fuseblk(); 787d8a5ba45SMiklos Szeredi kmem_cache_destroy(fuse_inode_cachep); 788d8a5ba45SMiklos Szeredi } 789d8a5ba45SMiklos Szeredi 7905c89e17eSGreg Kroah-Hartman static struct kobject *fuse_kobj; 7915c89e17eSGreg Kroah-Hartman static struct kobject *connections_kobj; 7925c89e17eSGreg Kroah-Hartman 793f543f253SMiklos Szeredi static int fuse_sysfs_init(void) 794f543f253SMiklos Szeredi { 795f543f253SMiklos Szeredi int err; 796f543f253SMiklos Szeredi 79700d26666SGreg Kroah-Hartman fuse_kobj = kobject_create_and_add("fuse", fs_kobj); 7985c89e17eSGreg Kroah-Hartman if (!fuse_kobj) { 7995c89e17eSGreg Kroah-Hartman err = -ENOMEM; 800f543f253SMiklos Szeredi goto out_err; 8015c89e17eSGreg Kroah-Hartman } 802f543f253SMiklos Szeredi 8035c89e17eSGreg Kroah-Hartman connections_kobj = kobject_create_and_add("connections", fuse_kobj); 8045c89e17eSGreg Kroah-Hartman if (!connections_kobj) { 8055c89e17eSGreg Kroah-Hartman err = -ENOMEM; 806f543f253SMiklos Szeredi goto out_fuse_unregister; 8075c89e17eSGreg Kroah-Hartman } 808f543f253SMiklos Szeredi 809f543f253SMiklos Szeredi return 0; 810f543f253SMiklos Szeredi 811f543f253SMiklos Szeredi out_fuse_unregister: 812197b12d6SGreg Kroah-Hartman kobject_put(fuse_kobj); 813f543f253SMiklos Szeredi out_err: 814f543f253SMiklos Szeredi return err; 815f543f253SMiklos Szeredi } 816f543f253SMiklos Szeredi 817f543f253SMiklos Szeredi static void fuse_sysfs_cleanup(void) 818f543f253SMiklos Szeredi { 819197b12d6SGreg Kroah-Hartman kobject_put(connections_kobj); 820197b12d6SGreg Kroah-Hartman kobject_put(fuse_kobj); 821f543f253SMiklos Szeredi } 822f543f253SMiklos Szeredi 823d8a5ba45SMiklos Szeredi static int __init fuse_init(void) 824d8a5ba45SMiklos Szeredi { 825d8a5ba45SMiklos Szeredi int res; 826d8a5ba45SMiklos Szeredi 827d8a5ba45SMiklos Szeredi printk("fuse init (API version %i.%i)\n", 828d8a5ba45SMiklos Szeredi FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 829d8a5ba45SMiklos Szeredi 830bafa9654SMiklos Szeredi INIT_LIST_HEAD(&fuse_conn_list); 831d8a5ba45SMiklos Szeredi res = fuse_fs_init(); 832d8a5ba45SMiklos Szeredi if (res) 833d8a5ba45SMiklos Szeredi goto err; 834d8a5ba45SMiklos Szeredi 835334f485dSMiklos Szeredi res = fuse_dev_init(); 836334f485dSMiklos Szeredi if (res) 837334f485dSMiklos Szeredi goto err_fs_cleanup; 838334f485dSMiklos Szeredi 839f543f253SMiklos Szeredi res = fuse_sysfs_init(); 840f543f253SMiklos Szeredi if (res) 841f543f253SMiklos Szeredi goto err_dev_cleanup; 842f543f253SMiklos Szeredi 843bafa9654SMiklos Szeredi res = fuse_ctl_init(); 844bafa9654SMiklos Szeredi if (res) 845bafa9654SMiklos Szeredi goto err_sysfs_cleanup; 846bafa9654SMiklos Szeredi 847d8a5ba45SMiklos Szeredi return 0; 848d8a5ba45SMiklos Szeredi 849bafa9654SMiklos Szeredi err_sysfs_cleanup: 850bafa9654SMiklos Szeredi fuse_sysfs_cleanup(); 851f543f253SMiklos Szeredi err_dev_cleanup: 852f543f253SMiklos Szeredi fuse_dev_cleanup(); 853334f485dSMiklos Szeredi err_fs_cleanup: 854334f485dSMiklos Szeredi fuse_fs_cleanup(); 855d8a5ba45SMiklos Szeredi err: 856d8a5ba45SMiklos Szeredi return res; 857d8a5ba45SMiklos Szeredi } 858d8a5ba45SMiklos Szeredi 859d8a5ba45SMiklos Szeredi static void __exit fuse_exit(void) 860d8a5ba45SMiklos Szeredi { 861d8a5ba45SMiklos Szeredi printk(KERN_DEBUG "fuse exit\n"); 862d8a5ba45SMiklos Szeredi 863bafa9654SMiklos Szeredi fuse_ctl_cleanup(); 864f543f253SMiklos Szeredi fuse_sysfs_cleanup(); 865d8a5ba45SMiklos Szeredi fuse_fs_cleanup(); 866334f485dSMiklos Szeredi fuse_dev_cleanup(); 867d8a5ba45SMiklos Szeredi } 868d8a5ba45SMiklos Szeredi 869d8a5ba45SMiklos Szeredi module_init(fuse_init); 870d8a5ba45SMiklos Szeredi module_exit(fuse_exit); 871