Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159// SPDX-License-Identifier: GPL-2.0#include <linux/kernel.h>#include <linux/errno.h>#include <linux/file.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/nospec.h>#include <linux/io_uring.h>
#include <uapi/linux/io_uring.h>
#include "io_uring.h"#include "rsrc.h"#include "filetable.h"
static int io_file_bitmap_get(struct io_ring_ctx *ctx){ struct io_file_table *table = &ctx->file_table; unsigned long nr = ctx->file_alloc_end; int ret;
if (!table->bitmap) return -ENFILE;
if (table->alloc_hint < ctx->file_alloc_start || table->alloc_hint >= ctx->file_alloc_end) table->alloc_hint = ctx->file_alloc_start;
do { ret = find_next_zero_bit(table->bitmap, nr, table->alloc_hint); if (ret != nr) return ret;
if (table->alloc_hint == ctx->file_alloc_start) break; nr = table->alloc_hint; table->alloc_hint = ctx->file_alloc_start; } while (1);
return -ENFILE;}
bool io_alloc_file_tables(struct io_ring_ctx *ctx, struct io_file_table *table, unsigned nr_files){ if (io_rsrc_data_alloc(&table->data, nr_files)) return false; table->bitmap = bitmap_zalloc(nr_files, GFP_KERNEL_ACCOUNT); if (table->bitmap) return true; io_rsrc_data_free(ctx, &table->data); return false;}
void io_free_file_tables(struct io_ring_ctx *ctx, struct io_file_table *table){ io_rsrc_data_free(ctx, &table->data); bitmap_free(table->bitmap); table->bitmap = NULL;}
static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file, u32 slot_index) __must_hold(&ctx->uring_lock){ struct io_rsrc_node *node;
if (io_is_uring_fops(file)) return -EBADF; if (!ctx->file_table.data.nr) return -ENXIO; if (slot_index >= ctx->file_table.data.nr) return -EINVAL;
node = io_rsrc_node_alloc(ctx, IORING_RSRC_FILE); if (!node) return -ENOMEM;
if (!io_reset_rsrc_node(ctx, &ctx->file_table.data, slot_index)) io_file_bitmap_set(&ctx->file_table, slot_index);
ctx->file_table.data.nodes[slot_index] = node; io_fixed_file_set(node, file); return 0;}
int __io_fixed_fd_install(struct io_ring_ctx *ctx, struct file *file, unsigned int file_slot){ bool alloc_slot = file_slot == IORING_FILE_INDEX_ALLOC; int ret;
if (alloc_slot) { ret = io_file_bitmap_get(ctx); if (unlikely(ret < 0)) return ret; file_slot = ret; } else { file_slot--; }
ret = io_install_fixed_file(ctx, file, file_slot); if (!ret && alloc_slot) ret = file_slot; return ret;}/* * Note when io_fixed_fd_install() returns error value, it will ensure * fput() is called correspondingly. */int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags, struct file *file, unsigned int file_slot){ struct io_ring_ctx *ctx = req->ctx; int ret;
io_ring_submit_lock(ctx, issue_flags); ret = __io_fixed_fd_install(ctx, file, file_slot); io_ring_submit_unlock(ctx, issue_flags);
if (unlikely(ret < 0)) fput(file); return ret;}
int io_fixed_fd_remove(struct io_ring_ctx *ctx, unsigned int offset){ struct io_rsrc_node *node;
if (unlikely(!ctx->file_table.data.nr)) return -ENXIO; if (offset >= ctx->file_table.data.nr) return -EINVAL;
node = io_rsrc_node_lookup(&ctx->file_table.data, offset); if (!node) return -EBADF; io_reset_rsrc_node(ctx, &ctx->file_table.data, offset); io_file_bitmap_clear(&ctx->file_table, offset); return 0;}
int io_register_file_alloc_range(struct io_ring_ctx *ctx, struct io_uring_file_index_range __user *arg){ struct io_uring_file_index_range range; u32 end;
if (copy_from_user(&range, arg, sizeof(range))) return -EFAULT; if (check_add_overflow(range.off, range.len, &end)) return -EOVERFLOW; if (range.resv || end > ctx->file_table.data.nr) return -EINVAL;
io_file_table_set_alloc_range(ctx, range.off, range.len); return 0;}