Normally waiting for a page to become unlocked, or locking the page, requires waiting for IO to complete. Add support for lock_page_async() and wait_on_page_locked_async(), which are callback based instead. This allows a caller to get notified when a page becomes unlocked, rather than wait for it. We add a new iocb field, ki_waitq, to pass in the necessary data for this to happen. We can unionize this with ki_cookie, since that is only used for polled IO. Polled IO can never co-exist with async callbacks, as it is (by definition) polled completions. struct wait_page_key is made public, and we define struct wait_page_async as the interface between the caller and the core.
Showing the changes to include/linux (2 of 3 files). Show all
Unified · Split
| @@ -315,6 +315,8 @@ enum rw_hint { · 314 unmodified lines | |||
| 315 | #define IOCB_SYNC (1 << 5) | 315 | #define IOCB_SYNC (1 << 5) |
| 316 | #define IOCB_WRITE (1 << 6) | 316 | #define IOCB_WRITE (1 << 6) |
| 317 | #define IOCB_NOWAIT (1 << 7) | 317 | #define IOCB_NOWAIT (1 << 7) |
| 318 | /* iocb->ki_waitq is valid */ | ||
| 319 | #define IOCB_WAITQ (1 << 8) | ||
| 318 | 320 | ||
| 319 | struct kiocb { | 321 | struct kiocb { |
| 320 | struct file *ki_filp; | 322 | struct file *ki_filp; |
| @@ -328,7 +330,10 @@ struct kiocb { · 7 unmodified lines | |||
| 328 | int ki_flags; | 330 | int ki_flags; |
| 329 | u16 ki_hint; | 331 | u16 ki_hint; |
| 330 | u16 ki_ioprio; /* See linux/ioprio.h */ | 332 | u16 ki_ioprio; /* See linux/ioprio.h */ |
| 331 | unsigned int ki_cookie; /* for ->iopoll */ | 333 | union { |
| 334 | unsigned int ki_cookie; /* for ->iopoll */ | ||
| 335 | struct wait_page_queue *ki_waitq; /* for async buffered IO */ | ||
| 336 | }; | ||
| 332 | 337 | ||
| 333 | randomized_struct_fields_end | 338 | randomized_struct_fields_end |
| 334 | }; | 339 | }; |
| @@ -535,6 +535,7 @@ static inline int wake_page_match(struct wait_page_queue *wait_page, · 534 unmodified lines | |||
| 535 | 535 | ||
| 536 | extern void __lock_page(struct page *page); | 536 | extern void __lock_page(struct page *page); |
| 537 | extern int __lock_page_killable(struct page *page); | 537 | extern int __lock_page_killable(struct page *page); |
| 538 | extern int __lock_page_async(struct page *page, struct wait_page_queue *wait); | ||
| 538 | extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm, | 539 | extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm, |
| 539 | unsigned int flags); | 540 | unsigned int flags); |
| 540 | extern void unlock_page(struct page *page); | 541 | extern void unlock_page(struct page *page); |
| @@ -571,6 +572,22 @@ static inline int lock_page_killable(struct page *page) · 30 unmodified lines | |||
| 571 | return 0; | 572 | return 0; |
| 572 | } | 573 | } |
| 573 | 574 | ||
| 575 | /* | ||
| 576 | * lock_page_async - Lock the page, unless this would block. If the page | ||
| 577 | * is already locked, then queue a callback when the page becomes unlocked. | ||
| 578 | * This callback can then retry the operation. | ||
| 579 | * | ||
| 580 | * Returns 0 if the page is locked successfully, or -EIOCBQUEUED if the page | ||
| 581 | * was already locked and the callback defined in 'wait' was queued. | ||
| 582 | */ | ||
| 583 | static inline int lock_page_async(struct page *page, | ||
| 584 | struct wait_page_queue *wait) | ||
| 585 | { | ||
| 586 | if (!trylock_page(page)) | ||
| 587 | return __lock_page_async(page, wait); | ||
| 588 | return 0; | ||
| 589 | } | ||
| 590 | |||
| 574 | /* | 591 | /* |
| 575 | * lock_page_or_retry - Lock the page, unless this would block and the | 592 | * lock_page_or_retry - Lock the page, unless this would block and the |
| 576 | * caller indicated that it can handle a retry. | 593 | * caller indicated that it can handle a retry. |