|
12 | 12 |
|
13 | 13 | #include "memmap.h" |
14 | 14 | #include "kbuf.h" |
| 15 | +#include "rsrc.h" |
15 | 16 |
|
16 | 17 | static void *io_mem_alloc_compound(struct page **pages, int nr_pages, |
17 | 18 | size_t size, gfp_t gfp) |
@@ -194,6 +195,72 @@ void *__io_uaddr_map(struct page ***pages, unsigned short *npages, |
194 | 195 | return ERR_PTR(-ENOMEM); |
195 | 196 | } |
196 | 197 |
|
| 198 | +void io_free_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr) |
| 199 | +{ |
| 200 | + if (mr->pages) { |
| 201 | + unpin_user_pages(mr->pages, mr->nr_pages); |
| 202 | + kvfree(mr->pages); |
| 203 | + } |
| 204 | + if (mr->vmap_ptr) |
| 205 | + vunmap(mr->vmap_ptr); |
| 206 | + if (mr->nr_pages && ctx->user) |
| 207 | + __io_unaccount_mem(ctx->user, mr->nr_pages); |
| 208 | + |
| 209 | + memset(mr, 0, sizeof(*mr)); |
| 210 | +} |
| 211 | + |
| 212 | +int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr, |
| 213 | + struct io_uring_region_desc *reg) |
| 214 | +{ |
| 215 | + int pages_accounted = 0; |
| 216 | + struct page **pages; |
| 217 | + int nr_pages, ret; |
| 218 | + void *vptr; |
| 219 | + u64 end; |
| 220 | + |
| 221 | + if (WARN_ON_ONCE(mr->pages || mr->vmap_ptr || mr->nr_pages)) |
| 222 | + return -EFAULT; |
| 223 | + if (memchr_inv(®->__resv, 0, sizeof(reg->__resv))) |
| 224 | + return -EINVAL; |
| 225 | + if (reg->flags != IORING_MEM_REGION_TYPE_USER) |
| 226 | + return -EINVAL; |
| 227 | + if (!reg->user_addr) |
| 228 | + return -EFAULT; |
| 229 | + if (!reg->size || reg->mmap_offset || reg->id) |
| 230 | + return -EINVAL; |
| 231 | + if ((reg->size >> PAGE_SHIFT) > INT_MAX) |
| 232 | + return E2BIG; |
| 233 | + if ((reg->user_addr | reg->size) & ~PAGE_MASK) |
| 234 | + return -EINVAL; |
| 235 | + if (check_add_overflow(reg->user_addr, reg->size, &end)) |
| 236 | + return -EOVERFLOW; |
| 237 | + |
| 238 | + pages = io_pin_pages(reg->user_addr, reg->size, &nr_pages); |
| 239 | + if (IS_ERR(pages)) |
| 240 | + return PTR_ERR(pages); |
| 241 | + |
| 242 | + if (ctx->user) { |
| 243 | + ret = __io_account_mem(ctx->user, nr_pages); |
| 244 | + if (ret) |
| 245 | + goto out_free; |
| 246 | + pages_accounted = nr_pages; |
| 247 | + } |
| 248 | + |
| 249 | + vptr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); |
| 250 | + if (!vptr) |
| 251 | + goto out_free; |
| 252 | + |
| 253 | + mr->pages = pages; |
| 254 | + mr->vmap_ptr = vptr; |
| 255 | + mr->nr_pages = nr_pages; |
| 256 | + return 0; |
| 257 | +out_free: |
| 258 | + if (pages_accounted) |
| 259 | + __io_unaccount_mem(ctx->user, pages_accounted); |
| 260 | + io_pages_free(&pages, nr_pages); |
| 261 | + return ret; |
| 262 | +} |
| 263 | + |
197 | 264 | static void *io_uring_validate_mmap_request(struct file *file, loff_t pgoff, |
198 | 265 | size_t sz) |
199 | 266 | { |
|
0 commit comments