aboutsummaryrefslogtreecommitdiffstats
path: root/mm/filemap.c
diff options
context:
space:
mode:
authorMatthew Wilcox (Oracle) <willy@infradead.org>2021-12-23 15:17:28 -0500
committerMatthew Wilcox (Oracle) <willy@infradead.org>2022-01-04 13:15:34 -0500
commit81f4c03b7de75727be438f8f3e1683e0b0d1556a (patch)
treeaa866030a3dcaf61694940672bc37946b324adaf /mm/filemap.c
parent539a3322f208db478db88c4a76239476defce6b1 (diff)
downloadlinux-81f4c03b7de75727be438f8f3e1683e0b0d1556a.tar.gz
filemap: Drop the refcount while waiting for page lock
Commit bd8a1f3655a7 ("mm/filemap: support readpage splitting a page") changed the read_iter path to drop the refcount while waiting for the page lock. However, it missed the same pattern in read_mapping_page() and friends. Use the same pattern in do_read_cache_folio() that is used in filemap_update_page(). Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Diffstat (limited to 'mm/filemap.c')
-rw-r--r--mm/filemap.c43
1 files changed, 5 insertions, 38 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index f98e084ffb31bb..38f16acb893689 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3460,45 +3460,12 @@ filler:
if (folio_test_uptodate(folio))
goto out;
- /*
- * Page is not up to date and may be locked due to one of the following
- * case a: Page is being filled and the page lock is held
- * case b: Read/write error clearing the page uptodate status
- * case c: Truncation in progress (page locked)
- * case d: Reclaim in progress
- *
- * Case a, the page will be up to date when the page is unlocked.
- * There is no need to serialise on the page lock here as the page
- * is pinned so the lock gives no additional protection. Even if the
- * page is truncated, the data is still valid if PageUptodate as
- * it's a race vs truncate race.
- * Case b, the page will not be up to date
- * Case c, the page may be truncated but in itself, the data may still
- * be valid after IO completes as it's a read vs truncate race. The
- * operation must restart if the page is not uptodate on unlock but
- * otherwise serialising on page lock to stabilise the mapping gives
- * no additional guarantees to the caller as the page lock is
- * released before return.
- * Case d, similar to truncation. If reclaim holds the page lock, it
- * will be a race with remove_mapping that determines if the mapping
- * is valid on unlock but otherwise the data is valid and there is
- * no need to serialise with page lock.
- *
- * As the page lock gives no additional guarantee, we optimistically
- * wait on the page to be unlocked and check if it's up to date and
- * use the page if it is. Otherwise, the page lock is required to
- * distinguish between the different cases. The motivation is that we
- * avoid spurious serialisations and wakeups when multiple processes
- * wait on the same page for IO to complete.
- */
- folio_wait_locked(folio);
- if (folio_test_uptodate(folio))
- goto out;
-
- /* Distinguish between all the cases under the safety of the lock */
- folio_lock(folio);
+ if (!folio_trylock(folio)) {
+ folio_put_wait_locked(folio, TASK_UNINTERRUPTIBLE);
+ goto repeat;
+ }
- /* Case c or d, restart the operation */
+ /* Folio was truncated from mapping */
if (!folio->mapping) {
folio_unlock(folio);
folio_put(folio);