xref: /linux/io_uring/filetable.c (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/errno.h>
4 #include <linux/file.h>
5 #include <linux/mm.h>
6 #include <linux/slab.h>
7 #include <linux/nospec.h>
8 #include <linux/io_uring.h>
9 
10 #include <uapi/linux/io_uring.h>
11 
12 #include "io_uring.h"
13 #include "rsrc.h"
14 #include "filetable.h"
15 
16 static int io_file_bitmap_get(struct io_ring_ctx *ctx)
17 {
18 	struct io_file_table *table = &ctx->file_table;
19 	unsigned long nr = ctx->file_alloc_end;
20 	int ret;
21 
22 	if (!table->bitmap)
23 		return -ENFILE;
24 
25 	if (table->alloc_hint < ctx->file_alloc_start ||
26 	    table->alloc_hint >= ctx->file_alloc_end)
27 		table->alloc_hint = ctx->file_alloc_start;
28 
29 	do {
30 		ret = find_next_zero_bit(table->bitmap, nr, table->alloc_hint);
31 		if (ret != nr)
32 			return ret;
33 
34 		if (table->alloc_hint == ctx->file_alloc_start)
35 			break;
36 		nr = table->alloc_hint;
37 		table->alloc_hint = ctx->file_alloc_start;
38 	} while (1);
39 
40 	return -ENFILE;
41 }
42 
43 bool io_alloc_file_tables(struct io_ring_ctx *ctx, struct io_file_table *table,
44 			  unsigned nr_files)
45 {
46 	if (io_rsrc_data_alloc(&table->data, nr_files))
47 		return false;
48 	table->bitmap = bitmap_zalloc(nr_files, GFP_KERNEL_ACCOUNT);
49 	if (table->bitmap)
50 		return true;
51 	io_rsrc_data_free(ctx, &table->data);
52 	return false;
53 }
54 
55 void io_free_file_tables(struct io_ring_ctx *ctx, struct io_file_table *table)
56 {
57 	io_rsrc_data_free(ctx, &table->data);
58 	bitmap_free(table->bitmap);
59 	table->bitmap = NULL;
60 }
61 
62 static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
63 				 u32 slot_index)
64 	__must_hold(&ctx->uring_lock)
65 {
66 	struct io_rsrc_node *node;
67 
68 	if (io_is_uring_fops(file))
69 		return -EBADF;
70 	if (!ctx->file_table.data.nr)
71 		return -ENXIO;
72 	if (slot_index >= ctx->file_table.data.nr)
73 		return -EINVAL;
74 
75 	node = io_rsrc_node_alloc(ctx, IORING_RSRC_FILE);
76 	if (!node)
77 		return -ENOMEM;
78 
79 	if (!io_reset_rsrc_node(ctx, &ctx->file_table.data, slot_index))
80 		io_file_bitmap_set(&ctx->file_table, slot_index);
81 
82 	ctx->file_table.data.nodes[slot_index] = node;
83 	io_fixed_file_set(node, file);
84 	return 0;
85 }
86 
87 int __io_fixed_fd_install(struct io_ring_ctx *ctx, struct file *file,
88 			  unsigned int file_slot)
89 {
90 	bool alloc_slot = file_slot == IORING_FILE_INDEX_ALLOC;
91 	int ret;
92 
93 	if (alloc_slot) {
94 		ret = io_file_bitmap_get(ctx);
95 		if (unlikely(ret < 0))
96 			return ret;
97 		file_slot = ret;
98 	} else {
99 		file_slot--;
100 	}
101 
102 	ret = io_install_fixed_file(ctx, file, file_slot);
103 	if (!ret && alloc_slot)
104 		ret = file_slot;
105 	return ret;
106 }
107 /*
108  * Note when io_fixed_fd_install() returns error value, it will ensure
109  * fput() is called correspondingly.
110  */
111 int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,
112 			struct file *file, unsigned int file_slot)
113 {
114 	struct io_ring_ctx *ctx = req->ctx;
115 	int ret;
116 
117 	io_ring_submit_lock(ctx, issue_flags);
118 	ret = __io_fixed_fd_install(ctx, file, file_slot);
119 	io_ring_submit_unlock(ctx, issue_flags);
120 
121 	if (unlikely(ret < 0))
122 		fput(file);
123 	return ret;
124 }
125 
126 int io_fixed_fd_remove(struct io_ring_ctx *ctx, unsigned int offset)
127 {
128 	struct io_rsrc_node *node;
129 
130 	if (unlikely(!ctx->file_table.data.nr))
131 		return -ENXIO;
132 	if (offset >= ctx->file_table.data.nr)
133 		return -EINVAL;
134 
135 	node = io_rsrc_node_lookup(&ctx->file_table.data, offset);
136 	if (!node)
137 		return -EBADF;
138 	io_reset_rsrc_node(ctx, &ctx->file_table.data, offset);
139 	io_file_bitmap_clear(&ctx->file_table, offset);
140 	return 0;
141 }
142 
143 int io_register_file_alloc_range(struct io_ring_ctx *ctx,
144 				 struct io_uring_file_index_range __user *arg)
145 {
146 	struct io_uring_file_index_range range;
147 	u32 end;
148 
149 	if (copy_from_user(&range, arg, sizeof(range)))
150 		return -EFAULT;
151 	if (check_add_overflow(range.off, range.len, &end))
152 		return -EOVERFLOW;
153 	if (range.resv || end > ctx->file_table.data.nr)
154 		return -EINVAL;
155 
156 	io_file_table_set_alloc_range(ctx, range.off, range.len);
157 	return 0;
158 }
159