struct io_rsrc_data {
unsigned int nr;
+ unsigned int last_index;
+ struct io_rsrc_node *last_node;
struct io_rsrc_node **nodes;
};
old_node = io_rsrc_node_lookup(&ctx->file_table.data, &slot_index);
if (old_node)
- io_put_rsrc_node(old_node);
+ io_reset_rsrc_node(&ctx->file_table.data, slot_index);
else
io_file_bitmap_set(&ctx->file_table, slot_index);
node = io_rsrc_node_lookup(&ctx->file_table.data, &offset);
if (!node)
return -EBADF;
- io_put_rsrc_node(node);
- ctx->file_table.data.nodes[offset] = NULL;
+ io_reset_rsrc_node(&ctx->file_table.data, offset);
io_file_bitmap_clear(&ctx->file_table, offset);
return 0;
}
GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (data->nodes) {
data->nr = nr;
+ data->last_index = -1U;
return 0;
}
return -ENOMEM;
index = up->offset + done;
node = io_rsrc_node_lookup(&ctx->file_table.data, &index);
if (node) {
- io_put_rsrc_node(node);
- ctx->file_table.data.nodes[index] = NULL;
+ io_reset_rsrc_node(&ctx->file_table.data, index);
io_file_bitmap_clear(&ctx->file_table, index);
}
if (fd != -1) {
break;
}
if (ctx->buf_table.nodes[i])
- io_put_rsrc_node(ctx->buf_table.nodes[i]);
+ io_reset_rsrc_node(&ctx->buf_table, i);
ctx->buf_table.nodes[i] = node;
if (tag)
switch (node->type) {
case IORING_RSRC_FILE:
+ io_rsrc_cache_clear(&ctx->file_table.data, node);
if (io_slot_file(node))
fput(io_slot_file(node));
break;
case IORING_RSRC_BUFFER:
+ io_rsrc_cache_clear(&ctx->buf_table, node);
if (node->buf)
io_buffer_unmap(node->ctx, node);
break;
int *index)
{
if (*index < data->nr) {
- *index = array_index_nospec(*index, data->nr);
- return data->nodes[*index];
+ if (*index != data->last_index) {
+ *index = array_index_nospec(*index, data->nr);
+ if (data->nodes[*index]) {
+ data->last_index = *index;
+ data->last_node = data->nodes[*index];
+ }
+ }
+ return data->last_node;
}
return NULL;
}
+static inline void io_rsrc_cache_clear(struct io_rsrc_data *data,
+ struct io_rsrc_node *node)
+{
+ if (data->last_node == node) {
+ data->last_node = NULL;
+ data->last_index = -1U;
+ }
+}
+
static inline void io_put_rsrc_node(struct io_rsrc_node *node)
{
if (node != &empty_node && !--node->refs)
io_free_rsrc_node(node);
}
+static inline void io_reset_rsrc_node(struct io_rsrc_data *data, int index)
+{
+ struct io_rsrc_node *node = data->nodes[index];
+
+ if (node) {
+ io_rsrc_cache_clear(data, node);
+ io_put_rsrc_node(node);
+ data->nodes[index] = NULL;
+ }
+}
+
static inline void io_req_put_rsrc_nodes(struct io_kiocb *req)
{
if (req->rsrc_nodes[IORING_RSRC_FILE] != rsrc_empty_node) {