* Returns negative for error, or number of bytes used in the buffer on success */
| 236 | * Returns negative for error, or number of bytes used in the buffer on success |
| 237 | */ |
| 238 | static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p, |
| 239 | struct io_uring_sq *sq, struct io_uring_cq *cq, |
| 240 | void *buf, size_t buf_size) |
| 241 | { |
| 242 | unsigned long page_size = get_page_size(); |
| 243 | unsigned sq_entries, cq_entries; |
| 244 | size_t sqes_size = 0, ring_mem, sqes_mem; |
| 245 | unsigned long mem_used = 0; |
| 246 | void *ptr; |
| 247 | int ret; |
| 248 | |
| 249 | ret = get_sq_cq_entries(entries, p, &sq_entries, &cq_entries); |
| 250 | if (ret) |
| 251 | return ret; |
| 252 | |
| 253 | sqes_mem = params_sqes_size(p, sq_entries); |
| 254 | sqes_mem = (sqes_mem + page_size - 1) & ~(page_size - 1); |
| 255 | |
| 256 | ring_mem = KRING_SIZE; |
| 257 | ring_mem += params_cq_size(p, cq_entries); |
| 258 | if (!(p->flags & IORING_SETUP_NO_SQARRAY)) |
| 259 | ring_mem += sq_entries * sizeof(unsigned); |
| 260 | mem_used = sqes_mem + ring_mem; |
| 261 | mem_used = (mem_used + page_size - 1) & ~(page_size - 1); |
| 262 | |
| 263 | /* |
| 264 | * A maxed-out number of CQ entries with IORING_SETUP_CQE32 fills a 2MB |
| 265 | * huge page by itself, so the SQ entries won't fit in the same huge |
| 266 | * page. For SQEs, that shouldn't be possible given KERN_MAX_ENTRIES, |
| 267 | * but check that too to future-proof (e.g. against different huge page |
| 268 | * sizes). Bail out early so we don't overrun. |
| 269 | */ |
| 270 | if (!buf && (sqes_mem > huge_page_size || ring_mem > huge_page_size)) |
| 271 | return -ENOMEM; |
| 272 | |
| 273 | if (buf) { |
| 274 | if (mem_used > buf_size) |
| 275 | return -ENOMEM; |
| 276 | ptr = buf; |
| 277 | } else { |
| 278 | int map_hugetlb = 0; |
| 279 | if (sqes_mem <= page_size) |
| 280 | buf_size = page_size; |
| 281 | else { |
| 282 | buf_size = huge_page_size; |
| 283 | map_hugetlb = MAP_HUGETLB | MAP_HUGE_2MB; |
| 284 | } |
| 285 | sqes_size = buf_size; |
| 286 | ptr = __sys_mmap(NULL, sqes_size, PROT_READ|PROT_WRITE, |
| 287 | MAP_SHARED|MAP_ANONYMOUS|map_hugetlb, |
| 288 | -1, 0); |
| 289 | if (IS_ERR(ptr)) |
| 290 | return PTR_ERR(ptr); |
| 291 | } |
| 292 | |
| 293 | sq->sqes = ptr; |
| 294 | sq->sqes_sz = (unsigned int) sqes_size; |
| 295 | if (mem_used <= buf_size) { |
no test coverage detected