From 985de582849dfc25ccbf2ef6ea923f984ad7fd89 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Thu, 30 Apr 2020 10:27:06 +0800 Subject: [PATCH] LU-13493 llite: check if page truncated in ll_write_begin() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit See following function flows: CPU0 CPU1 |->grab_cache_page_nowait |->find_get_page |->__find_get_page (page unlocked) |->truncate page |->trylock_page —->page might has been truncated after this. So it is possible that page might has been truncated after grab_cache_page_nowait() return even page lock is held. We need check wheather vmpage->mapping change in ll_write_begin() otherwise, we will have truncated page with NULL mapping, which will trigger assertions in vvp_set_pagevec_dirty(). This patch also fix assertion string doesn't end in newline. Change-Id: I46e14f560378a39d8ae1353d60cc49c0f0b241c0 Signed-off-by: Wang Shilong Reviewed-on: https://review.whamcloud.com/38425 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Reviewed-by: Oleg Drokin --- lustre/llite/rw26.c | 15 ++++++++++++--- lustre/llite/vvp_io.c | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lustre/llite/rw26.c b/lustre/llite/rw26.c index 6e889a1..2dc2f16 100644 --- a/lustre/llite/rw26.c +++ b/lustre/llite/rw26.c @@ -598,11 +598,11 @@ out: return result; } -static int ll_tiny_write_begin(struct page *vmpage) +static int ll_tiny_write_begin(struct page *vmpage, struct address_space *mapping) { /* Page must be present, up to date, dirty, and not in writeback. */ if (!vmpage || !PageUptodate(vmpage) || !PageDirty(vmpage) || - PageWriteback(vmpage)) + PageWriteback(vmpage) || vmpage->mapping != mapping) return -ENODATA; return 0; @@ -630,7 +630,7 @@ static int ll_write_begin(struct file *file, struct address_space *mapping, lcc = ll_cl_find(file); if (lcc == NULL) { vmpage = grab_cache_page_nowait(mapping, index); - result = ll_tiny_write_begin(vmpage); + result = ll_tiny_write_begin(vmpage, mapping); GOTO(out, result); } @@ -689,6 +689,15 @@ again: } } + /* page was truncated */ + if (mapping != vmpage->mapping) { + CDEBUG(D_VFSTRACE, "page: %lu was truncated\n", index); + unlock_page(vmpage); + put_page(vmpage); + vmpage = NULL; + goto again; + } + page = cl_page_find(env, clob, vmpage->index, vmpage, CPT_CACHEABLE); if (IS_ERR(page)) GOTO(out, result = PTR_ERR(page)); diff --git a/lustre/llite/vvp_io.c b/lustre/llite/vvp_io.c index 6ae1463..55e21fa 100644 --- a/lustre/llite/vvp_io.c +++ b/lustre/llite/vvp_io.c @@ -992,7 +992,7 @@ void vvp_set_pagevec_dirty(struct pagevec *pvec) ClearPageReclaim(pvec->pages[i]); LASSERTF(page->mapping, - "mapping must be set. page %p, page->private (cl_page) %p", + "mapping must be set. page %p, page->private (cl_page) %p\n", page, (void *) page->private); /* Rest of code derived from __set_page_dirty_nobuffers */ -- 1.8.3.1