]>
Commit | Line | Data |
---|---|---|
db3ec075 GKH |
1 | From stable-bounces@linux.kernel.org Thu Feb 8 14:22:41 2007 |
2 | From: "Ken Chen" <kenchen@google.com> | |
3 | Date: Thu, 08 Feb 2007 14:20:27 -0800 | |
4 | Subject: hugetlb: preserve hugetlb pte dirty state | |
5 | To: torvalds@linux-foundation.org | |
6 | Cc: nish.aravamudan@gmail.com, wli@holomorphy.com, kenchen@google.com, agl@us.ibm.com, hugh@veritas.com, akpm@linux-foundation.org, stable@kernel.org, david@gibson.dropbear.id.au | |
7 | Message-ID: <200702082220.l18MKRLR028479@shell0.pdx.osdl.net> | |
8 | ||
9 | ||
10 | From: "Ken Chen" <kenchen@google.com> | |
11 | ||
12 | __unmap_hugepage_range() is buggy that it does not preserve dirty state of | |
13 | huge_pte when unmapping hugepage range. It causes data corruption in the | |
14 | event of dop_caches being used by sys admin. For example, an application | |
15 | creates a hugetlb file, modify pages, then unmap it. While leaving the | |
16 | hugetlb file alive, comes along sys admin doing a "echo 3 > | |
17 | /proc/sys/vm/drop_caches". | |
18 | ||
19 | drop_pagecache_sb() will happily free all pages that aren't marked dirty if | |
20 | there are no active mapping. Later when application remaps the hugetlb | |
21 | file back and all data are gone, triggering catastrophic flip over on | |
22 | application. | |
23 | ||
24 | Not only that, the internal resv_huge_pages count will also get all messed | |
25 | up. Fix it up by marking page dirty appropriately. | |
26 | ||
27 | Signed-off-by: Ken Chen <kenchen@google.com> | |
28 | Cc: "Nish Aravamudan" <nish.aravamudan@gmail.com> | |
29 | Cc: Adam Litke <agl@us.ibm.com> | |
30 | Cc: David Gibson <david@gibson.dropbear.id.au> | |
80c5cd04 | 31 | Acked-by: William Irwin <bill.irwin@oracle.com> |
db3ec075 GKH |
32 | Cc: Hugh Dickins <hugh@veritas.com> |
33 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
34 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
35 | ||
36 | --- | |
37 | fs/hugetlbfs/inode.c | 5 ++++- | |
38 | mm/hugetlb.c | 2 ++ | |
39 | 2 files changed, 6 insertions(+), 1 deletion(-) | |
40 | ||
41 | --- linux-2.6.20.1.orig/fs/hugetlbfs/inode.c | |
42 | +++ linux-2.6.20.1/fs/hugetlbfs/inode.c | |
43 | @@ -449,10 +449,13 @@ static int hugetlbfs_symlink(struct inod | |
44 | } | |
45 | ||
46 | /* | |
47 | - * For direct-IO reads into hugetlb pages | |
48 | + * mark the head page dirty | |
49 | */ | |
50 | static int hugetlbfs_set_page_dirty(struct page *page) | |
51 | { | |
52 | + struct page *head = (struct page *)page_private(page); | |
53 | + | |
54 | + SetPageDirty(head); | |
55 | return 0; | |
56 | } | |
57 | ||
58 | --- linux-2.6.20.1.orig/mm/hugetlb.c | |
59 | +++ linux-2.6.20.1/mm/hugetlb.c | |
60 | @@ -389,6 +389,8 @@ void __unmap_hugepage_range(struct vm_ar | |
61 | continue; | |
62 | ||
63 | page = pte_page(pte); | |
64 | + if (pte_dirty(pte)) | |
65 | + set_page_dirty(page); | |
66 | list_add(&page->lru, &page_list); | |
67 | } | |
68 | spin_unlock(&mm->page_table_lock); |