struct fuse_req *fuse_get_req(struct fuse_conn *fc) { struct fuse_req *req; sigset_t oldset; int intr; int err; atomic_inc(&fc->num_waiting); block_sigs(&oldset); intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); err = -EINTR; if (intr) goto out; err = -ENOTCONN; if (!fc->connected) goto out; req = fuse_request_alloc(); err = -ENOMEM; if (!req) goto out; fuse_req_init_context(req); req->waiting = 1; return req; out: atomic_dec(&fc->num_waiting); return ERR_PTR(err); }
static struct fuse_conn *new_conn(void) { struct fuse_conn *fc; fc = kmalloc(sizeof(*fc), GFP_KERNEL); if (fc != NULL) { int i; memset(fc, 0, sizeof(*fc)); init_waitqueue_head(&fc->waitq); INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->unused_list); INIT_LIST_HEAD(&fc->background); sema_init(&fc->outstanding_sem, 0); init_rwsem(&fc->sbput_sem); for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { struct fuse_req *req = fuse_request_alloc(); if (!req) { free_conn(fc); return NULL; } list_add(&req->list, &fc->unused_list); } #ifdef KERNEL_2_6_6_PLUS fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; #endif fc->reqctr = 0; } return fc; }
static struct inode *fuse_alloc_inode(struct super_block *sb) { struct inode *inode; struct fuse_inode *fi; inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); if (!inode) return NULL; fi = get_fuse_inode(inode); fi->i_time = 0; fi->nodeid = 0; fi->nlookup = 0; fi->attr_version = 0; fi->writectr = 0; fi->orig_ino = 0; INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->queued_writes); INIT_LIST_HEAD(&fi->writepages); init_waitqueue_head(&fi->page_waitq); fi->forget_req = fuse_request_alloc(); if (!fi->forget_req) { kmem_cache_free(fuse_inode_cachep, inode); return NULL; } return inode; }
struct fuse_file *fuse_file_alloc(void) { struct fuse_file *ff; ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); if (ff) { ff->release_req = fuse_request_alloc(); if (!ff->release_req) { kfree(ff); ff = NULL; } } return ff; }
/* * Gets a requests for a file operation, always succeeds * * This is used for sending the FLUSH request, which must get to * userspace, due to POSIX locks which may need to be unlocked. * * If allocation fails due to OOM, use the reserved request in * fuse_file. * * This is very unlikely to deadlock accidentally, since the * filesystem should not have it's own file open. If deadlock is * intentional, it can still be broken by "aborting" the filesystem. */ struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file) { struct fuse_req *req; atomic_inc(&fc->num_waiting); wait_event(fc->blocked_waitq, !fc->blocked); req = fuse_request_alloc(); if (!req) req = get_reserved_req(fc, file); fuse_req_init_context(req); req->waiting = 1; return req; }
static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, bool for_background) { struct fuse_req *req; int err; atomic_inc(&fc->num_waiting); if (fuse_block_alloc(fc, for_background)) { sigset_t oldset; int intr; block_sigs(&oldset); intr = wait_event_interruptible_exclusive(fc->blocked_waitq, !fuse_block_alloc(fc, for_background)); restore_sigs(&oldset); err = -EINTR; if (intr) goto out; } err = -ENOTCONN; if (!fc->connected) goto out; req = fuse_request_alloc(npages); err = -ENOMEM; if (!req) { if (for_background) wake_up(&fc->blocked_waitq); goto out; } fuse_req_init_context(req); req->waiting = 1; req->background = for_background; return req; out: atomic_dec(&fc->num_waiting); return ERR_PTR(err); }
static struct inode *fuse_alloc_inode(struct super_block *sb) { struct inode *inode; struct fuse_inode *fi; inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); if (!inode) return NULL; fi = get_fuse_inode(inode); fi->i_time = 0; fi->nodeid = 0; fi->nlookup = 0; fi->forget_req = fuse_request_alloc(); if (!fi->forget_req) { kmem_cache_free(fuse_inode_cachep, inode); return NULL; } return inode; }
static struct inode *fuse_alloc_inode(struct super_block *sb) { struct inode *inode; struct fuse_inode *fi; inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); if (!inode) return NULL; #ifndef KERNEL_2_6 inode->u.generic_ip = NULL; #endif fi = get_fuse_inode(inode); fi->i_time = jiffies - 1; fi->nodeid = 0; fi->nlookup = 0; fi->forget_req = fuse_request_alloc(); if (!fi->forget_req) { kmem_cache_free(fuse_inode_cachep, inode); return NULL; } return inode; }
static int fuse_fill_super(struct super_block *sb, void *data, int silent) { struct fuse_conn *fc; struct inode *root; struct fuse_mount_data d; struct file *file; struct dentry *root_dentry; struct fuse_req *init_req; int err; int is_bdev = sb->s_bdev != NULL; if (sb->s_flags & MS_MANDLOCK) return -EINVAL; if (!parse_fuse_opt((char *) data, &d, is_bdev)) return -EINVAL; if (is_bdev) { #ifdef CONFIG_BLOCK if (!sb_set_blocksize(sb, d.blksize)) return -EINVAL; #endif } else { sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; } sb->s_magic = FUSE_SUPER_MAGIC; sb->s_op = &fuse_super_operations; sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_export_op = &fuse_export_operations; file = fget(d.fd); if (!file) return -EINVAL; if (file->f_op != &fuse_dev_operations) return -EINVAL; fc = new_conn(sb); if (!fc) return -ENOMEM; fc->flags = d.flags; fc->user_id = d.user_id; fc->group_id = d.group_id; fc->max_read = max_t(unsigned, 4096, d.max_read); /* Used by get_root_inode() */ sb->s_fs_info = fc; err = -ENOMEM; root = get_root_inode(sb, d.rootmode); if (!root) goto err; root_dentry = d_alloc_root(root); if (!root_dentry) { iput(root); goto err; } init_req = fuse_request_alloc(); if (!init_req) goto err_put_root; if (is_bdev) { fc->destroy_req = fuse_request_alloc(); if (!fc->destroy_req) goto err_free_init_req; } mutex_lock(&fuse_mutex); err = -EINVAL; if (file->private_data) goto err_unlock; err = fuse_ctl_add_conn(fc); if (err) goto err_unlock; list_add_tail(&fc->entry, &fuse_conn_list); sb->s_root = root_dentry; fc->connected = 1; file->private_data = fuse_conn_get(fc); mutex_unlock(&fuse_mutex); /* * atomic_dec_and_test() in fput() provides the necessary * memory barrier for file->private_data to be visible on all * CPUs after this */ fput(file); fuse_send_init(fc, init_req); return 0; err_unlock: mutex_unlock(&fuse_mutex); err_free_init_req: fuse_request_free(init_req); err_put_root: dput(root_dentry); err: fput(file); fuse_conn_put(fc); return err; }