static char *read_link(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req = fuse_get_req_nopages(fc); char *link; if (IS_ERR(req)) return ERR_CAST(req); link = (char *) __get_free_page(GFP_KERNEL); if (!link) { link = ERR_PTR(-ENOMEM); goto out; } req->in.h.opcode = FUSE_READLINK; req->in.h.nodeid = get_node_id(inode); req->out.argvar = 1; req->out.numargs = 1; req->out.args[0].size = PAGE_SIZE - 1; req->out.args[0].value = link; fuse_request_send(fc, req); if (req->out.h.error) { free_page((unsigned long) link); link = ERR_PTR(req->out.h.error); } else link[req->out.args[0].size] = '\0'; out: fuse_put_request(fc, req); fuse_invalidate_atime(inode); return link; }
static const char *fuse_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); char *link; ssize_t ret; if (!dentry) return ERR_PTR(-ECHILD); link = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!link) return ERR_PTR(-ENOMEM); args.in.h.opcode = FUSE_READLINK; args.in.h.nodeid = get_node_id(inode); args.out.argvar = 1; args.out.numargs = 1; args.out.args[0].size = PAGE_SIZE - 1; args.out.args[0].value = link; ret = fuse_simple_request(fc, &args); if (ret < 0) { kfree(link); link = ERR_PTR(ret); } else { link[ret] = '\0'; set_delayed_call(done, kfree_link, link); } fuse_invalidate_atime(inode); return link; }
static const char *fuse_follow_link(struct dentry *dentry, void **cookie) { struct inode *inode = d_inode(dentry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); char *link; ssize_t ret; link = (char *) __get_free_page(GFP_KERNEL); if (!link) return ERR_PTR(-ENOMEM); args.in.h.opcode = FUSE_READLINK; args.in.h.nodeid = get_node_id(inode); args.out.argvar = 1; args.out.numargs = 1; args.out.args[0].size = PAGE_SIZE - 1; args.out.args[0].value = link; ret = fuse_simple_request(fc, &args); if (ret < 0) { free_page((unsigned long) link); link = ERR_PTR(ret); } else { link[ret] = '\0'; *cookie = link; } fuse_invalidate_atime(inode); return link; }
static int fuse_readdir(struct file *file, struct dir_context *ctx) { int plus, err; size_t nbytes; struct page *page; struct inode *inode = file_inode(file); struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; u64 attr_version = 0; if (is_bad_inode(inode)) return -EIO; req = fuse_get_req(fc, 1); if (IS_ERR(req)) return PTR_ERR(req); page = alloc_page(GFP_KERNEL); if (!page) { fuse_put_request(fc, req); return -ENOMEM; } plus = fuse_use_readdirplus(inode, ctx); req->out.argpages = 1; req->num_pages = 1; req->pages[0] = page; req->page_descs[0].length = PAGE_SIZE; if (plus) { attr_version = fuse_get_attr_version(fc); fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, FUSE_READDIRPLUS); } else { fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, FUSE_READDIR); } fuse_lock_inode(inode); fuse_request_send(fc, req); fuse_unlock_inode(inode); nbytes = req->out.args[0].size; err = req->out.h.error; fuse_put_request(fc, req); if (!err) { if (plus) { err = parse_dirplusfile(page_address(page), nbytes, file, ctx, attr_version); } else { err = parse_dirfile(page_address(page), nbytes, file, ctx); } } __free_page(page); fuse_invalidate_atime(inode); return err; }
static int fuse_readlink_page(struct inode *inode, struct page *page) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; int err; req = fuse_get_req(fc, 1); if (IS_ERR(req)) return PTR_ERR(req); req->out.page_zeroing = 1; req->out.argpages = 1; req->num_pages = 1; req->pages[0] = page; req->page_descs[0].length = PAGE_SIZE - 1; req->in.h.opcode = FUSE_READLINK; req->in.h.nodeid = get_node_id(inode); req->out.argvar = 1; req->out.numargs = 1; req->out.args[0].size = PAGE_SIZE - 1; fuse_request_send(fc, req); err = req->out.h.error; if (!err) { char *link = page_address(page); size_t len = req->out.args[0].size; BUG_ON(len >= PAGE_SIZE); link[len] = '\0'; } fuse_put_request(fc, req); fuse_invalidate_atime(inode); return err; }