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 | 315 | #define IOCB_SYNC (1 << 5) |
| 316 | 316 | #define IOCB_WRITE (1 << 6) |
| 317 | 317 | #define IOCB_NOWAIT (1 << 7) |
| 318 | +/* iocb->ki_waitq is valid */ | |
| 319 | +#define IOCB_WAITQ (1 << 8) | |
| 318 | 320 | |
| 319 | 321 | struct kiocb { |
| 320 | 322 | struct file *ki_filp; |
| @@ -328,7 +330,10 @@ struct kiocb { · 7 unmodified lines | ||
| 328 | 330 | int ki_flags; |
| 329 | 331 | u16 ki_hint; |
| 330 | 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 | 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 | 536 | extern void __lock_page(struct page *page); |
| 537 | 537 | extern int __lock_page_killable(struct page *page); |
| 538 | +extern int __lock_page_async(struct page *page, struct wait_page_queue *wait); | |
| 538 | 539 | extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm, |
| 539 | 540 | unsigned int flags); |
| 540 | 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 | 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 | 592 | * lock_page_or_retry - Lock the page, unless this would block and the |
| 576 | 593 | * caller indicated that it can handle a retry. |