diff options
| -rw-r--r-- | fs/aio.c | 116 | ||||
| -rw-r--r-- | include/linux/aio.h | 1 |
2 files changed, 15 insertions, 102 deletions
| @@ -510,108 +510,27 @@ void exit_aio(struct mm_struct *mm) | |||
| 510 | * This prevents races between the aio code path referencing the | 510 | * This prevents races between the aio code path referencing the |
| 511 | * req (after submitting it) and aio_complete() freeing the req. | 511 | * req (after submitting it) and aio_complete() freeing the req. |
| 512 | */ | 512 | */ |
| 513 | static struct kiocb *__aio_get_req(struct kioctx *ctx) | 513 | static inline struct kiocb *aio_get_req(struct kioctx *ctx) |
| 514 | { | 514 | { |
| 515 | struct kiocb *req = NULL; | 515 | struct kiocb *req; |
| 516 | |||
| 517 | if (atomic_read(&ctx->reqs_active) >= ctx->ring_info.nr) | ||
| 518 | return NULL; | ||
| 519 | |||
| 520 | if (atomic_inc_return(&ctx->reqs_active) > ctx->ring_info.nr - 1) | ||
| 521 | goto out_put; | ||
| 516 | 522 | ||
| 517 | req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL|__GFP_ZERO); | 523 | req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL|__GFP_ZERO); |
| 518 | if (unlikely(!req)) | 524 | if (unlikely(!req)) |
| 519 | return NULL; | 525 | goto out_put; |
| 520 | 526 | ||
| 521 | atomic_set(&req->ki_users, 2); | 527 | atomic_set(&req->ki_users, 2); |
| 522 | req->ki_ctx = ctx; | 528 | req->ki_ctx = ctx; |
| 523 | 529 | ||
| 524 | return req; | 530 | return req; |
| 525 | } | 531 | out_put: |
| 526 | 532 | atomic_dec(&ctx->reqs_active); | |
| 527 | /* | 533 | return NULL; |
| 528 | * struct kiocb's are allocated in batches to reduce the number of | ||
| 529 | * times the ctx lock is acquired and released. | ||
| 530 | */ | ||
| 531 | #define KIOCB_BATCH_SIZE 32L | ||
| 532 | struct kiocb_batch { | ||
| 533 | struct list_head head; | ||
| 534 | long count; /* number of requests left to allocate */ | ||
| 535 | }; | ||
| 536 | |||
| 537 | static void kiocb_batch_init(struct kiocb_batch *batch, long total) | ||
| 538 | { | ||
| 539 | INIT_LIST_HEAD(&batch->head); | ||
| 540 | batch->count = total; | ||
| 541 | } | ||
| 542 | |||
| 543 | static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch) | ||
| 544 | { | ||
| 545 | struct kiocb *req, *n; | ||
| 546 | |||
| 547 | if (list_empty(&batch->head)) | ||
| 548 | return; | ||
| 549 | |||
| 550 | spin_lock_irq(&ctx->ctx_lock); | ||
| 551 | list_for_each_entry_safe(req, n, &batch->head, ki_batch) { | ||
| 552 | list_del(&req->ki_batch); | ||
| 553 | kmem_cache_free(kiocb_cachep, req); | ||
| 554 | atomic_dec(&ctx->reqs_active); | ||
| 555 | } | ||
| 556 | spin_unlock_irq(&ctx->ctx_lock); | ||
| 557 | } | ||
| 558 | |||
| 559 | /* | ||
| 560 | * Allocate a batch of kiocbs. This avoids taking and dropping the | ||
| 561 | * context lock a lot during setup. | ||
| 562 | */ | ||
| 563 | static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch) | ||
| 564 | { | ||
| 565 | unsigned short allocated, to_alloc; | ||
| 566 | long avail; | ||
| 567 | struct kiocb *req, *n; | ||
| 568 | |||
| 569 | to_alloc = min(batch->count, KIOCB_BATCH_SIZE); | ||
| 570 | for (allocated = 0; allocated < to_alloc; allocated++) { | ||
| 571 | req = __aio_get_req(ctx); | ||
| 572 | if (!req) | ||
| 573 | /* allocation failed, go with what we've got */ | ||
| 574 | break; | ||
| 575 | list_add(&req->ki_batch, &batch->head); | ||
| 576 | } | ||
| 577 | |||
| 578 | if (allocated == 0) | ||
| 579 | goto out; | ||
| 580 | |||
| 581 | spin_lock_irq(&ctx->ctx_lock); | ||
| 582 | |||
| 583 | avail = ctx->ring_info.nr - atomic_read(&ctx->reqs_active) - 1; | ||
| 584 | BUG_ON(avail < 0); | ||
| 585 | if (avail < allocated) { | ||
| 586 | /* Trim back the number of requests. */ | ||
| 587 | list_for_each_entry_safe(req, n, &batch->head, ki_batch) { | ||
| 588 | list_del(&req->ki_batch); | ||
| 589 | kmem_cache_free(kiocb_cachep, req); | ||
| 590 | if (--allocated <= avail) | ||
| 591 | break; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | |||
| 595 | batch->count -= allocated; | ||
| 596 | atomic_add(allocated, &ctx->reqs_active); | ||
| 597 | |||
| 598 | spin_unlock_irq(&ctx->ctx_lock); | ||
| 599 | |||
| 600 | out: | ||
| 601 | return allocated; | ||
| 602 | } | ||
| 603 | |||
| 604 | static inline struct kiocb *aio_get_req(struct kioctx *ctx, | ||
| 605 | struct kiocb_batch *batch) | ||
| 606 | { | ||
| 607 | struct kiocb *req; | ||
| 608 | |||
| 609 | if (list_empty(&batch->head)) | ||
| 610 | if (kiocb_batch_refill(ctx, batch) == 0) | ||
| 611 | return NULL; | ||
| 612 | req = list_first_entry(&batch->head, struct kiocb, ki_batch); | ||
| 613 | list_del(&req->ki_batch); | ||
| 614 | return req; | ||
| 615 | } | 534 | } |
| 616 | 535 | ||
| 617 | static void kiocb_free(struct kiocb *req) | 536 | static void kiocb_free(struct kiocb *req) |
| @@ -1198,8 +1117,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) | |||
| 1198 | } | 1117 | } |
| 1199 | 1118 | ||
| 1200 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | 1119 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, |
| 1201 | struct iocb *iocb, struct kiocb_batch *batch, | 1120 | struct iocb *iocb, bool compat) |
| 1202 | bool compat) | ||
| 1203 | { | 1121 | { |
| 1204 | struct kiocb *req; | 1122 | struct kiocb *req; |
| 1205 | ssize_t ret; | 1123 | ssize_t ret; |
| @@ -1220,7 +1138,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
| 1220 | return -EINVAL; | 1138 | return -EINVAL; |
| 1221 | } | 1139 | } |
| 1222 | 1140 | ||
| 1223 | req = aio_get_req(ctx, batch); /* returns with 2 references to req */ | 1141 | req = aio_get_req(ctx); /* returns with 2 references to req */ |
| 1224 | if (unlikely(!req)) | 1142 | if (unlikely(!req)) |
| 1225 | return -EAGAIN; | 1143 | return -EAGAIN; |
| 1226 | 1144 | ||
| @@ -1293,7 +1211,6 @@ long do_io_submit(aio_context_t ctx_id, long nr, | |||
| 1293 | long ret = 0; | 1211 | long ret = 0; |
| 1294 | int i = 0; | 1212 | int i = 0; |
| 1295 | struct blk_plug plug; | 1213 | struct blk_plug plug; |
| 1296 | struct kiocb_batch batch; | ||
| 1297 | 1214 | ||
| 1298 | if (unlikely(nr < 0)) | 1215 | if (unlikely(nr < 0)) |
| 1299 | return -EINVAL; | 1216 | return -EINVAL; |
| @@ -1310,8 +1227,6 @@ long do_io_submit(aio_context_t ctx_id, long nr, | |||
| 1310 | return -EINVAL; | 1227 | return -EINVAL; |
| 1311 | } | 1228 | } |
| 1312 | 1229 | ||
| 1313 | kiocb_batch_init(&batch, nr); | ||
| 1314 | |||
| 1315 | blk_start_plug(&plug); | 1230 | blk_start_plug(&plug); |
| 1316 | 1231 | ||
| 1317 | /* | 1232 | /* |
| @@ -1332,13 +1247,12 @@ long do_io_submit(aio_context_t ctx_id, long nr, | |||
| 1332 | break; | 1247 | break; |
| 1333 | } | 1248 | } |
| 1334 | 1249 | ||
| 1335 | ret = io_submit_one(ctx, user_iocb, &tmp, &batch, compat); | 1250 | ret = io_submit_one(ctx, user_iocb, &tmp, compat); |
| 1336 | if (ret) | 1251 | if (ret) |
| 1337 | break; | 1252 | break; |
| 1338 | } | 1253 | } |
| 1339 | blk_finish_plug(&plug); | 1254 | blk_finish_plug(&plug); |
| 1340 | 1255 | ||
| 1341 | kiocb_batch_free(ctx, &batch); | ||
| 1342 | put_ioctx(ctx); | 1256 | put_ioctx(ctx); |
| 1343 | return i ? i : ret; | 1257 | return i ? i : ret; |
| 1344 | } | 1258 | } |
diff --git a/include/linux/aio.h b/include/linux/aio.h index d2a00038ec77..f0a8481af99b 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
| @@ -85,7 +85,6 @@ struct kiocb { | |||
| 85 | 85 | ||
| 86 | struct list_head ki_list; /* the aio core uses this | 86 | struct list_head ki_list; /* the aio core uses this |
| 87 | * for cancellation */ | 87 | * for cancellation */ |
| 88 | struct list_head ki_batch; /* batch allocation */ | ||
| 89 | 88 | ||
| 90 | /* | 89 | /* |
| 91 | * If the aio_resfd field of the userspace iocb is not zero, | 90 | * If the aio_resfd field of the userspace iocb is not zero, |
