diff options
| -rw-r--r-- | fs/aio.c | 58 |
1 files changed, 23 insertions, 35 deletions
| @@ -362,7 +362,7 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
| 362 | struct aio_ring *ring; | 362 | struct aio_ring *ring; |
| 363 | unsigned nr_events = ctx->max_reqs; | 363 | unsigned nr_events = ctx->max_reqs; |
| 364 | struct mm_struct *mm = current->mm; | 364 | struct mm_struct *mm = current->mm; |
| 365 | unsigned long size, populate; | 365 | unsigned long size, unused; |
| 366 | int nr_pages; | 366 | int nr_pages; |
| 367 | int i; | 367 | int i; |
| 368 | struct file *file; | 368 | struct file *file; |
| @@ -383,6 +383,20 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
| 383 | return -EAGAIN; | 383 | return -EAGAIN; |
| 384 | } | 384 | } |
| 385 | 385 | ||
| 386 | ctx->aio_ring_file = file; | ||
| 387 | nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) | ||
| 388 | / sizeof(struct io_event); | ||
| 389 | |||
| 390 | ctx->ring_pages = ctx->internal_pages; | ||
| 391 | if (nr_pages > AIO_RING_PAGES) { | ||
| 392 | ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *), | ||
| 393 | GFP_KERNEL); | ||
| 394 | if (!ctx->ring_pages) { | ||
| 395 | put_aio_ring_file(ctx); | ||
| 396 | return -ENOMEM; | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 386 | for (i = 0; i < nr_pages; i++) { | 400 | for (i = 0; i < nr_pages; i++) { |
| 387 | struct page *page; | 401 | struct page *page; |
| 388 | page = find_or_create_page(file->f_inode->i_mapping, | 402 | page = find_or_create_page(file->f_inode->i_mapping, |
| @@ -394,19 +408,14 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
| 394 | SetPageUptodate(page); | 408 | SetPageUptodate(page); |
| 395 | SetPageDirty(page); | 409 | SetPageDirty(page); |
| 396 | unlock_page(page); | 410 | unlock_page(page); |
| 411 | |||
| 412 | ctx->ring_pages[i] = page; | ||
| 397 | } | 413 | } |
| 398 | ctx->aio_ring_file = file; | 414 | ctx->nr_pages = i; |
| 399 | nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) | ||
| 400 | / sizeof(struct io_event); | ||
| 401 | 415 | ||
| 402 | ctx->ring_pages = ctx->internal_pages; | 416 | if (unlikely(i != nr_pages)) { |
| 403 | if (nr_pages > AIO_RING_PAGES) { | 417 | aio_free_ring(ctx); |
| 404 | ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *), | 418 | return -EAGAIN; |
| 405 | GFP_KERNEL); | ||
| 406 | if (!ctx->ring_pages) { | ||
| 407 | put_aio_ring_file(ctx); | ||
| 408 | return -ENOMEM; | ||
| 409 | } | ||
| 410 | } | 419 | } |
| 411 | 420 | ||
| 412 | ctx->mmap_size = nr_pages * PAGE_SIZE; | 421 | ctx->mmap_size = nr_pages * PAGE_SIZE; |
| @@ -415,9 +424,9 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
| 415 | down_write(&mm->mmap_sem); | 424 | down_write(&mm->mmap_sem); |
| 416 | ctx->mmap_base = do_mmap_pgoff(ctx->aio_ring_file, 0, ctx->mmap_size, | 425 | ctx->mmap_base = do_mmap_pgoff(ctx->aio_ring_file, 0, ctx->mmap_size, |
| 417 | PROT_READ | PROT_WRITE, | 426 | PROT_READ | PROT_WRITE, |
| 418 | MAP_SHARED | MAP_POPULATE, 0, &populate); | 427 | MAP_SHARED, 0, &unused); |
| 428 | up_write(&mm->mmap_sem); | ||
| 419 | if (IS_ERR((void *)ctx->mmap_base)) { | 429 | if (IS_ERR((void *)ctx->mmap_base)) { |
| 420 | up_write(&mm->mmap_sem); | ||
| 421 | ctx->mmap_size = 0; | 430 | ctx->mmap_size = 0; |
| 422 | aio_free_ring(ctx); | 431 | aio_free_ring(ctx); |
| 423 | return -EAGAIN; | 432 | return -EAGAIN; |
| @@ -425,27 +434,6 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
| 425 | 434 | ||
| 426 | pr_debug("mmap address: 0x%08lx\n", ctx->mmap_base); | 435 | pr_debug("mmap address: 0x%08lx\n", ctx->mmap_base); |
| 427 | 436 | ||
| 428 | /* We must do this while still holding mmap_sem for write, as we | ||
| 429 | * need to be protected against userspace attempting to mremap() | ||
| 430 | * or munmap() the ring buffer. | ||
| 431 | */ | ||
| 432 | ctx->nr_pages = get_user_pages(current, mm, ctx->mmap_base, nr_pages, | ||
| 433 | 1, 0, ctx->ring_pages, NULL); | ||
| 434 | |||
| 435 | /* Dropping the reference here is safe as the page cache will hold | ||
| 436 | * onto the pages for us. It is also required so that page migration | ||
| 437 | * can unmap the pages and get the right reference count. | ||
| 438 | */ | ||
| 439 | for (i = 0; i < ctx->nr_pages; i++) | ||
| 440 | put_page(ctx->ring_pages[i]); | ||
| 441 | |||
| 442 | up_write(&mm->mmap_sem); | ||
| 443 | |||
| 444 | if (unlikely(ctx->nr_pages != nr_pages)) { | ||
| 445 | aio_free_ring(ctx); | ||
| 446 | return -EAGAIN; | ||
| 447 | } | ||
| 448 | |||
| 449 | ctx->user_id = ctx->mmap_base; | 437 | ctx->user_id = ctx->mmap_base; |
| 450 | ctx->nr_events = nr_events; /* trusted copy */ | 438 | ctx->nr_events = nr_events; /* trusted copy */ |
| 451 | 439 | ||
