diff --git a/fs/fuse/compound.c b/fs/fuse/compound.c index dc76dbe01bcaf0..0f1e4c073d8b4e 100644 --- a/fs/fuse/compound.c +++ b/fs/fuse/compound.c @@ -11,31 +11,20 @@ #include "fuse_i.h" /* - * Compound request + * Compound request builder and state tracker and args pointer storage */ -struct fuse_compound_req -{ +struct fuse_compound_req { struct fuse_mount *fm; struct fuse_compound_in compound_header; struct fuse_compound_out result_header; - size_t total_size; - char *buffer; - size_t buffer_pos; - size_t buffer_size; - - size_t total_expected_out_size; - - /* Operation results for error tracking */ + /* Per-operation error codes */ int op_errors[FUSE_MAX_COMPOUND_OPS]; + /* Original fuse_args for response parsing */ struct fuse_args *op_args[FUSE_MAX_COMPOUND_OPS]; - - /* Parsing state to avoid double processing */ - bool parsed; }; -struct fuse_compound_req *fuse_compound_alloc(struct fuse_mount *fm, - uint32_t flags) +struct fuse_compound_req *fuse_compound_alloc(struct fuse_mount *fm, u32 flags) { struct fuse_compound_req *compound; @@ -45,309 +34,117 @@ struct fuse_compound_req *fuse_compound_alloc(struct fuse_mount *fm, compound->fm = fm; compound->compound_header.flags = flags; - compound->buffer_size = PAGE_SIZE; - compound->buffer = kvmalloc(compound->buffer_size, GFP_KERNEL); - if (!compound->buffer) { - kfree(compound); - return ERR_PTR(-ENOMEM); - } + return compound; } -/* - * Free compound request resources - */ void fuse_compound_free(struct fuse_compound_req *compound) { - if (compound) { - kvfree(compound->buffer); - kfree(compound); - } -} - -/* - * Validate compound request structure before sending it out. - * Returns 0 on success, negative error code on failure. - */ -static int fuse_compound_validate_header(struct fuse_compound_req *compound) -{ - struct fuse_compound_in *in_header = &compound->compound_header; - size_t offset = 0; - int i; - - if (compound->buffer_pos > compound->buffer_size) - return -EINVAL; - - if (!compound || !compound->buffer) - return -EINVAL; - - if (compound->buffer_pos < sizeof(struct fuse_in_header)) - return -EINVAL; - - if (in_header->count == 0 || in_header->count > FUSE_MAX_COMPOUND_OPS) - return -EINVAL; - - for (i = 0; i < in_header->count; i++) { - const struct fuse_in_header *op_hdr; - - if (offset + sizeof(struct fuse_in_header) > compound->buffer_pos) { - pr_info_ratelimited("FUSE: compound operation %d header extends beyond buffer (offset %zu + header size %zu > buffer pos %zu)\n", - i, offset, sizeof(struct fuse_in_header), compound->buffer_pos); - return -EINVAL; - } - - op_hdr = (const struct fuse_in_header *)(compound->buffer + offset); - - if (op_hdr->len < sizeof(struct fuse_in_header)) { - pr_info_ratelimited("FUSE: compound operation %d has invalid length %u (minimum %zu bytes)\n", - i, op_hdr->len, sizeof(struct fuse_in_header)); - return -EINVAL; - } - - if (offset + op_hdr->len > compound->buffer_pos) { - pr_info_ratelimited("FUSE: compound operation %d extends beyond buffer (offset %zu + length %u > buffer pos %zu)\n", - i, offset, op_hdr->len, compound->buffer_pos); - return -EINVAL; - } - - if (op_hdr->opcode == 0 || op_hdr->opcode == FUSE_COMPOUND) { - pr_info_ratelimited("FUSE: compound operation %d has invalid opcode %u (cannot be 0 or FUSE_COMPOUND)\n", - i, op_hdr->opcode); - return -EINVAL; - } - - if (op_hdr->nodeid == 0) { - pr_info_ratelimited("FUSE: compound operation %d has invalid node ID 0\n", i); - return -EINVAL; - } - - offset += op_hdr->len; - } - - if (offset != compound->buffer_pos) { - pr_info_ratelimited("FUSE: compound buffer size mismatch (calculated %zu bytes, actual %zu bytes)\n", - offset, compound->buffer_pos); - return -EINVAL; - } + if (!compound) + return; - return 0; + kfree(compound); } -/* - * Adds a single operation to the compound request. The operation is serialized - * into the request buffer with its own fuse_in_header. - * - * For operations with page-based payloads (in_pages=true), the page data is - * ignored at the moment. - * - * Returns 0 on success, negative error code on failure. - */ int fuse_compound_add(struct fuse_compound_req *compound, struct fuse_args *args) { - struct fuse_in_header *hdr; - size_t args_size = 0; - size_t needed_size; - size_t expected_out_size = 0; - size_t page_payload_size = 0; - int i; - - if (!compound || compound->compound_header.count >= FUSE_MAX_COMPOUND_OPS) + if (!compound || + compound->compound_header.count >= FUSE_MAX_COMPOUND_OPS) return -EINVAL; - /* Calculate input size - handle page-based arguments separately */ - for (i = 0; i < args->in_numargs; i++) { - /* Last argument with in_pages flag gets data from pages */ - if (unlikely(i == args->in_numargs - 1 && args->in_pages)) { - /* the data handling is not supported at the moment */ - page_payload_size = args->in_args[i].size; - args_size += page_payload_size; - } else { - args_size += args->in_args[i].size; - } - } - - /* Calculate expected output size */ - for (i = 0; i < args->out_numargs; i++) - expected_out_size += args->out_args[i].size; - - needed_size = sizeof(struct fuse_in_header) + args_size; - - /* Expand buffer if needed */ - if (compound->buffer_pos + needed_size > compound->buffer_size) { - size_t new_size = max(compound->buffer_size * 2, - compound->buffer_pos + needed_size); - new_size = round_up(new_size, PAGE_SIZE); - char *new_buffer = kvrealloc(compound->buffer, - compound->buffer_size, - new_size, GFP_KERNEL); - if (!new_buffer) - return -ENOMEM; - compound->buffer = new_buffer; - compound->buffer_size = new_size; - } - - /* Build request header */ - hdr = (struct fuse_in_header *)(compound->buffer + compound->buffer_pos); - memset(hdr, 0, sizeof(*hdr)); - hdr->len = needed_size; - hdr->opcode = args->opcode; - hdr->nodeid = args->nodeid; - hdr->uid = from_kuid(compound->fm->fc->user_ns, current_fsuid()); - hdr->gid = from_kgid(compound->fm->fc->user_ns, current_fsgid()); - hdr->pid = pid_nr_ns(task_pid(current), compound->fm->fc->pid_ns); - hdr->unique = fuse_get_unique(&compound->fm->fc->iq); - compound->buffer_pos += sizeof(*hdr); - - if (args->in_pages) { - /* we have external payload, - * this is not supported at the moment */ + if (args->in_pages) return -EINVAL; - } - - /* Copy operation arguments */ - for (i = 0; i < args->in_numargs; i++) { - memcpy(compound->buffer + compound->buffer_pos, - args->in_args[i].value, args->in_args[i].size); - compound->buffer_pos += args->in_args[i].size; - } - - compound->total_expected_out_size += expected_out_size; - /* Store args for response parsing */ compound->op_args[compound->compound_header.count] = args; - compound->compound_header.count++; - compound->total_size += needed_size; - return 0; } -/* - * Copy response data to fuse_args structure - * - * Returns 0 on success, negative error code on failure. - */ -static void *fuse_copy_response_data(struct fuse_args *args, char *response_data) +static void *fuse_copy_response_data(struct fuse_args *args, + char *response_data) { size_t copied = 0; - int arg_idx; + int i; - for (arg_idx = 0; arg_idx < args->out_numargs; arg_idx++) { - struct fuse_arg current_arg = args->out_args[arg_idx]; + for (i = 0; i < args->out_numargs; i++) { + struct fuse_arg current_arg = args->out_args[i]; + size_t arg_size; - /* Last argument with out_pages: copy to pages */ - if (arg_idx == args->out_numargs - 1 && args->out_pages) { - /* external payload (in the last out arg) - * is not supported at the moment - */ + /* + * Last argument with out_pages: copy to pages + * External payload (in the last out arg) is not supported + * at the moment + */ + if (i == args->out_numargs - 1 && args->out_pages) return response_data; - } else { - size_t arg_size = current_arg.size; - if (current_arg.value && arg_size > 0) { - memcpy(current_arg.value, - (char *)response_data + copied, - arg_size); - copied += arg_size; - } + + arg_size = current_arg.size; + + if (current_arg.value && arg_size > 0) { + memcpy(current_arg.value, + (char *)response_data + copied, arg_size); + copied += arg_size; } } - return (char*)response_data + copied; + return (char *)response_data + copied; } -int fuse_compound_get_error(struct fuse_compound_req * compound, - int op_idx) +int fuse_compound_get_error(struct fuse_compound_req *compound, int op_idx) { return compound->op_errors[op_idx]; } -/* - * Parse compound response - * - * Parses the compound response and populates the original - * fuse_args structures with the response data. This function is idempotent - * and can be called multiple times safely. - * - * For operations with page-based output (out_pages=true), the response data - * is ignored at the moment. - * - * Returns 0 on success, negative error code on failure. - */ -static int fuse_compound_parse_resp(struct fuse_compound_req *compound, - uint32_t count, void *response, size_t response_size) +static void *fuse_compound_parse_one_op(struct fuse_compound_req *compound, + int op_index, void *op_out_data, + void *response_end) { - int i; - int res = 0; + struct fuse_out_header *op_hdr = op_out_data; + struct fuse_args *args = compound->op_args[op_index]; - /* double parsing prevention will be important - * for large responses most likely out pages. - */ - if (compound->parsed) { - return 0; - } + if (op_hdr->len < sizeof(struct fuse_out_header)) + return NULL; - void *op_out_data = response; - void *response_end = (char *)response + response_size; + /* Check if the entire operation response fits in the buffer */ + if ((char *)op_out_data + op_hdr->len > (char *)response_end) + return NULL; - /* Basic validation */ - if (!response || response_size < sizeof(struct fuse_out_header)) { - return -EIO; - } + if (op_hdr->error != 0) + compound->op_errors[op_index] = op_hdr->error; - /* Parse each operation response */ - for (i = 0; - i < count && i < compound->result_header.count; i++) { - struct fuse_out_header *op_hdr = op_out_data; - struct fuse_args *args = compound->op_args[i]; + if (args && op_hdr->len > sizeof(struct fuse_out_header)) + return fuse_copy_response_data(args, op_out_data + + sizeof(struct fuse_out_header)); - /* Validate header length */ - if (op_hdr->len < sizeof(struct fuse_out_header)) { - return -EIO; - } + /* No response data, just advance past the header */ + return (char *)op_out_data + op_hdr->len; +} - /* Check if the entire operation response fits in the buffer */ - if ((char *)op_out_data + op_hdr->len > (char *)response_end) { - return -EIO; - } +static int fuse_compound_parse_resp(struct fuse_compound_req *compound, + u32 count, void *response, + size_t response_size) +{ + void *op_out_data = response; + void *response_end = (char *)response + response_size; + int i; - if (op_hdr->error != 0) { - compound->op_errors[i] = op_hdr->error; - } + if (!response || response_size < sizeof(struct fuse_out_header)) + return -EIO; - /* Copy response data */ - if (args && op_hdr->len > sizeof(struct fuse_out_header)) { - op_out_data = fuse_copy_response_data(args, - op_out_data + sizeof(struct fuse_out_header)); - } else { - /* No response data, just advance past the header */ - op_out_data = (char *)op_out_data + op_hdr->len; - } + for (i = 0; i < count && i < compound->result_header.count; i++) { + op_out_data = fuse_compound_parse_one_op(compound, i, + op_out_data, + response_end); + if (!op_out_data) + return -EIO; } - compound->parsed = true; - return res; + return 0; } -/* - * Send compound request to userspace - * - * Sends the compound request out and parses the response. - * - * -> in_arg[0] -> fuse_compound_in (containing mainly count and flags) - * -> in_arg[1] -> payload - * (containing the serialized requests created by fuse_compound_add) - * - * On success, the response data is copied to the original fuse_args - * structures for each operation. - * - * Returns 0 on success, or the first error code from any operation. - * Returns negative error code if the request itself fails. - */ ssize_t fuse_compound_send(struct fuse_compound_req *compound) { - size_t expected_response_size; - ssize_t ret; struct fuse_args args = { .opcode = FUSE_COMPOUND, .nodeid = 0, @@ -355,9 +152,18 @@ ssize_t fuse_compound_send(struct fuse_compound_req *compound) .out_numargs = 2, .out_argvar = true, }; + size_t resp_buffer_size; + size_t actual_response_size; + size_t buffer_pos; + size_t total_expected_out_size; + void *buffer = NULL; + void *resp_payload; + ssize_t ret; + int i; if (!compound) { - pr_info_ratelimited("FUSE: compound request is NULL in fuse_compound_send\n"); + pr_info_ratelimited("FUSE: compound request is NULL in %s\n", + __func__); return -EINVAL; } @@ -366,55 +172,99 @@ ssize_t fuse_compound_send(struct fuse_compound_req *compound) return -EINVAL; } - /* Calculate response buffer size */ - expected_response_size = - compound->total_expected_out_size; - size_t total_buffer_size = expected_response_size + - (compound->compound_header.count * sizeof(struct fuse_out_header)); + buffer_pos = 0; + total_expected_out_size = 0; + + for (i = 0; i < compound->compound_header.count; i++) { + struct fuse_args *op_args = compound->op_args[i]; + size_t needed_size = sizeof(struct fuse_in_header); + int j; + + for (j = 0; j < op_args->in_numargs; j++) + needed_size += op_args->in_args[j].size; + + buffer_pos += needed_size; - void *resp_payload = kvmalloc(total_buffer_size, GFP_KERNEL | __GFP_ZERO); + for (j = 0; j < op_args->out_numargs; j++) + total_expected_out_size += op_args->out_args[j].size; + } - if (!resp_payload) + buffer = kvmalloc(buffer_pos, GFP_KERNEL); + if (!buffer) return -ENOMEM; - /* tell the fuse server how much memory we have allocated */ - compound->compound_header.result_size = expected_response_size; + + buffer_pos = 0; + for (i = 0; i < compound->compound_header.count; i++) { + struct fuse_args *op_args = compound->op_args[i]; + struct fuse_in_header *hdr; + size_t needed_size = sizeof(struct fuse_in_header); + int j; + + for (j = 0; j < op_args->in_numargs; j++) + needed_size += op_args->in_args[j].size; + + hdr = (struct fuse_in_header *)(buffer + buffer_pos); + memset(hdr, 0, sizeof(*hdr)); + hdr->len = needed_size; + hdr->opcode = op_args->opcode; + hdr->nodeid = op_args->nodeid; + hdr->uid = from_kuid(compound->fm->fc->user_ns, + current_fsuid()); + hdr->gid = from_kgid(compound->fm->fc->user_ns, + current_fsgid()); + hdr->pid = pid_nr_ns(task_pid(current), + compound->fm->fc->pid_ns); + buffer_pos += sizeof(*hdr); + + for (j = 0; j < op_args->in_numargs; j++) { + memcpy(buffer + buffer_pos, op_args->in_args[j].value, + op_args->in_args[j].size); + buffer_pos += op_args->in_args[j].size; + } + } + + resp_buffer_size = total_expected_out_size + + (compound->compound_header.count * + sizeof(struct fuse_out_header)); + + resp_payload = kvmalloc(resp_buffer_size, GFP_KERNEL | __GFP_ZERO); + if (!resp_payload) { + ret = -ENOMEM; + goto out_free_buffer; + } + + compound->compound_header.result_size = total_expected_out_size; args.in_args[0].size = sizeof(compound->compound_header); args.in_args[0].value = &compound->compound_header; - args.in_args[1].size = compound->buffer_pos; - args.in_args[1].value = compound->buffer; + args.in_args[1].size = buffer_pos; + args.in_args[1].value = buffer; args.out_args[0].size = sizeof(compound->result_header); args.out_args[0].value = &compound->result_header; - args.out_args[1].size = total_buffer_size; + args.out_args[1].size = resp_buffer_size; args.out_args[1].value = resp_payload; - /* Validate request */ - ret = fuse_compound_validate_header(compound); - if (ret) + ret = fuse_simple_request(compound->fm, &args); + if (ret < 0) goto out; - ret = fuse_compound_request(compound->fm, &args); - if (ret == -ENOSYS) { - goto out; - } - - size_t actual_response_size = args.out_args[1].size; + actual_response_size = args.out_args[1].size; - /* Validate response size */ if (actual_response_size < sizeof(struct fuse_compound_out)) { pr_info_ratelimited("FUSE: compound response too small (%zu bytes, minimum %zu bytes)\n", - actual_response_size, sizeof(struct fuse_compound_out)); + actual_response_size, + sizeof(struct fuse_compound_out)); ret = -EINVAL; goto out; } - /* Parse response using actual size */ - ret = fuse_compound_parse_resp(compound, - compound->result_header.count, - ((char *)resp_payload), - actual_response_size); + ret = fuse_compound_parse_resp(compound, compound->result_header.count, + (char *)resp_payload, + actual_response_size); out: kvfree(resp_payload); +out_free_buffer: + kvfree(buffer); return ret; } diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 597fb0d33ef7b2..db8046716077fa 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1265,14 +1265,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, inarg.getattr_flags |= FUSE_GETATTR_FH; inarg.fh = ff->fh; } - args.opcode = FUSE_GETATTR; - args.nodeid = get_node_id(inode); - args.in_numargs = 1; - args.in_args[0].size = sizeof(inarg); - args.in_args[0].value = &inarg; - args.out_numargs = 1; - args.out_args[0].size = sizeof(outarg); - args.out_args[0].value = &outarg; + fuse_getattr_args_fill(&args, get_node_id(inode), &inarg, &outarg); err = fuse_simple_request(fm, &args); if (!err) { if (fuse_invalid_attr(&outarg.attr) || diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 92fd31afe947df..9fca8462017b02 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -22,6 +22,39 @@ #include #include +/* + * Helper function to initialize fuse_args for OPEN/OPENDIR operations + */ +void fuse_open_args_fill(struct fuse_args *args, u64 nodeid, int opcode, + struct fuse_open_in *inarg, struct fuse_open_out *outarg) +{ + args->opcode = opcode; + args->nodeid = nodeid; + args->in_numargs = 1; + args->in_args[0].size = sizeof(*inarg); + args->in_args[0].value = inarg; + args->out_numargs = 1; + args->out_args[0].size = sizeof(*outarg); + args->out_args[0].value = outarg; +} + +/* + * Helper function to initialize fuse_args for GETATTR operations + */ +void fuse_getattr_args_fill(struct fuse_args *args, u64 nodeid, + struct fuse_getattr_in *inarg, + struct fuse_attr_out *outarg) +{ + args->opcode = FUSE_GETATTR; + args->nodeid = nodeid; + args->in_numargs = 1; + args->in_args[0].size = sizeof(*inarg); + args->in_args[0].value = inarg; + args->out_numargs = 1; + args->out_args[0].size = sizeof(*outarg); + args->out_args[0].value = outarg; +} + static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, unsigned int open_flags, int opcode, struct fuse_open_out *outargp) @@ -39,14 +72,7 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID; } - args.opcode = opcode; - args.nodeid = nodeid; - args.in_numargs = 1; - args.in_args[0].size = sizeof(inarg); - args.in_args[0].value = &inarg; - args.out_numargs = 1; - args.out_args[0].size = sizeof(*outargp); - args.out_args[0].value = outargp; + fuse_open_args_fill(&args, nodeid, opcode, &inarg, outargp); return fuse_simple_request(fm, &args); } @@ -132,53 +158,38 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) } } -static int fuse_compound_open_getattr(struct fuse_mount *fm, u64 nodeid, int flags, - int opcode, struct fuse_file *ff, struct fuse_attr_out *out_attr) +static int fuse_compound_open_getattr(struct fuse_mount *fm, u64 nodeid, + int flags, int opcode, + struct fuse_file *ff, + struct fuse_attr_out *outattrp, + struct fuse_open_out *outopenp) { struct fuse_compound_req *compound; - struct fuse_args open_args = {}, getattr_args = {}; + struct fuse_args open_args = {}; + struct fuse_args getattr_args = {}; struct fuse_open_in open_in = {}; struct fuse_getattr_in getattr_in = {}; - struct fuse_open_out open_out; - struct fuse_attr_out attr_out; int err; - /* Build compound request with flag to execute in the given order */ compound = fuse_compound_alloc(fm, 0); if (IS_ERR(compound)) return PTR_ERR(compound); - /* Add OPEN */ open_in.flags = flags & ~(O_CREAT | O_EXCL | O_NOCTTY); if (!fm->fc->atomic_o_trunc) open_in.flags &= ~O_TRUNC; if (fm->fc->handle_killpriv_v2 && - (open_in.flags & O_TRUNC) && !capable(CAP_FSETID)) { + (open_in.flags & O_TRUNC) && !capable(CAP_FSETID)) open_in.open_flags |= FUSE_OPEN_KILL_SUIDGID; - } - open_args.opcode = opcode; - open_args.nodeid = nodeid; - open_args.in_numargs = 1; - open_args.in_args[0].size = sizeof(open_in); - open_args.in_args[0].value = &open_in; - open_args.out_numargs = 1; - open_args.out_args[0].size = sizeof(struct fuse_open_out); - open_args.out_args[0].value = &open_out; + + fuse_open_args_fill(&open_args, nodeid, opcode, &open_in, outopenp); err = fuse_compound_add(compound, &open_args); if (err) goto out; - /* Add GETATTR */ - getattr_args.opcode = FUSE_GETATTR; - getattr_args.nodeid = nodeid; - getattr_args.in_numargs = 1; - getattr_args.in_args[0].size = sizeof(getattr_in); - getattr_args.in_args[0].value = &getattr_in; - getattr_args.out_numargs = 1; - getattr_args.out_args[0].size = sizeof(struct fuse_attr_out); - getattr_args.out_args[0].value = &attr_out; + fuse_getattr_args_fill(&getattr_args, nodeid, &getattr_in, outattrp); err = fuse_compound_add(compound, &getattr_args); if (err) @@ -188,11 +199,16 @@ static int fuse_compound_open_getattr(struct fuse_mount *fm, u64 nodeid, int fla if (err) goto out; - ff->fh = open_out.fh; - ff->open_flags = open_out.open_flags; + err = fuse_compound_get_error(compound, 0); + if (err) + goto out; + + err = fuse_compound_get_error(compound, 1); + if (err) + goto out; - if (out_attr) - *out_attr = attr_out; + ff->fh = outopenp->fh; + ff->open_flags = outopenp->open_flags; out: fuse_compound_free(compound); @@ -221,16 +237,18 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, if (inode && fc->compound_open_getattr) { struct fuse_attr_out attr_outarg; + err = fuse_compound_open_getattr(fm, nodeid, open_flags, - opcode, ff, &attr_outarg); + opcode, ff, + &attr_outarg, &outarg); if (!err) - fuse_change_attributes(inode, &attr_outarg.attr, NULL, + fuse_change_attributes(inode, &attr_outarg.attr, + NULL, ATTR_TIMEOUT(&attr_outarg), fuse_get_attr_version(fc)); } if (err == -ENOSYS) { err = fuse_send_open(fm, nodeid, open_flags, opcode, &outarg); - if (!err) { ff->fh = outarg.fh; ff->open_flags = outarg.open_flags; @@ -238,7 +256,7 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, } if (err) { - if(err != -ENOSYS) { + if (err != -ENOSYS) { /* err is not ENOSYS */ fuse_file_free(ff); return ERR_PTR(err); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index c4f644e3d51bd4..cd35eb05fc951b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1122,6 +1122,14 @@ struct fuse_io_args { void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos, size_t count, int opcode); +/* + * Helper functions to initialize fuse_args for common operations + */ +void fuse_open_args_fill(struct fuse_args *args, u64 nodeid, int opcode, + struct fuse_open_in *inarg, struct fuse_open_out *outarg); +void fuse_getattr_args_fill(struct fuse_args *args, u64 nodeid, + struct fuse_getattr_in *inarg, + struct fuse_attr_out *outarg); struct fuse_file *fuse_file_alloc(struct fuse_mount *fm, bool release); void fuse_file_free(struct fuse_file *ff); @@ -1468,7 +1476,8 @@ void fuse_file_io_release(struct fuse_file *ff, struct inode *inode); /* file.c */ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, struct inode *inode, - unsigned int open_flags, bool isdir); + unsigned int open_flags, + bool isdir); void fuse_file_release(struct inode *inode, struct fuse_file *ff, unsigned int open_flags, fl_owner_t id, bool isdir);