Message ID | 20181203200850.6460-3-mike.kravetz@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | hugetlbfs: use i_mmap_rwsem for better synchronization | expand |
Hi, [This is an automated email] This commit has been processed because it contains a "Fixes:" tag, fixing commit: ebed4bfc8da8 [PATCH] hugetlb: fix absurd HugePages_Rsvd. The bot has tested the following trees: v4.19.6, v4.14.85, v4.9.142, v4.4.166, v3.18.128. v4.19.6: Build OK! v4.14.85: Build OK! v4.9.142: Build OK! v4.4.166: Failed to apply! Possible dependencies: Unable to calculate v3.18.128: Failed to apply! Possible dependencies: 1bfad99ab425 ("hugetlbfs: hugetlb_vmtruncate_list() needs to take a range to delete") 1c5ecae3a93f ("hugetlbfs: add minimum size accounting to subpools") 1dd308a7b49d ("mm/hugetlb: document the reserve map/region tracking routines") 5e9113731a3c ("mm/hugetlb: add cache of descriptors to resv_map for region_add") 83cde9e8ba95 ("mm: use new helper functions around the i_mmap_mutex") b5cec28d36f5 ("hugetlbfs: truncate_hugepages() takes a range of pages") c672c7f29f2f ("mm/hugetlb: expose hugetlb fault mutex for use by fallocate") cf3ad20bfead ("mm/hugetlb: compute/return the number of regions added by region_add()") feba16e25a57 ("mm/hugetlb: add region_del() to delete a specific range of entries") How should we proceed with this patch? -- Thanks, Sasha
On 12/4/18 1:38 AM, Mike Kravetz wrote: > hugetlbfs page faults can race with truncate and hole punch operations. > Current code in the page fault path attempts to handle this by 'backing > out' operations if we encounter the race. One obvious omission in the > current code is removing a page newly added to the page cache. This is > pretty straight forward to address, but there is a more subtle and > difficult issue of backing out hugetlb reservations. To handle this > correctly, the 'reservation state' before page allocation needs to be > noted so that it can be properly backed out. There are four distinct > possibilities for reservation state: shared/reserved, shared/no-resv, > private/reserved and private/no-resv. Backing out a reservation may > require memory allocation which could fail so that needs to be taken > into account as well. > > Instead of writing the required complicated code for this rare > occurrence, just eliminate the race. i_mmap_rwsem is now held in read > mode for the duration of page fault processing. Hold i_mmap_rwsem > longer in truncation and hold punch code to cover the call to > remove_inode_hugepages. > > Cc: <stable@vger.kernel.org> > Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") > Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> > --- > fs/hugetlbfs/inode.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c > index 32920a10100e..3244147fc42b 100644 > --- a/fs/hugetlbfs/inode.c > +++ b/fs/hugetlbfs/inode.c > @@ -505,8 +505,8 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) > i_mmap_lock_write(mapping); > if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)) > hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); > - i_mmap_unlock_write(mapping); > remove_inode_hugepages(inode, offset, LLONG_MAX); > + i_mmap_unlock_write(mapping); > return 0; > } We used to do remove_inode_hugepages() mutex_lock(&hugetlb_fault_mutex_table[hash]); i_mmap_lock_write(mapping); hugetlb_vmdelete_list(&mapping->i_mmap, i_mmap_unlock_write(mapping); did we change the lock ordering with this patch? > > @@ -540,8 +540,8 @@ static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) > hugetlb_vmdelete_list(&mapping->i_mmap, > hole_start >> PAGE_SHIFT, > hole_end >> PAGE_SHIFT); > - i_mmap_unlock_write(mapping); > remove_inode_hugepages(inode, hole_start, hole_end); > + i_mmap_unlock_write(mapping); > inode_unlock(inode); > } > -aneesh
On 12/17/18 2:25 AM, Aneesh Kumar K.V wrote: > On 12/4/18 1:38 AM, Mike Kravetz wrote: >> hugetlbfs page faults can race with truncate and hole punch operations. >> Current code in the page fault path attempts to handle this by 'backing >> out' operations if we encounter the race. One obvious omission in the >> current code is removing a page newly added to the page cache. This is >> pretty straight forward to address, but there is a more subtle and >> difficult issue of backing out hugetlb reservations. To handle this >> correctly, the 'reservation state' before page allocation needs to be >> noted so that it can be properly backed out. There are four distinct >> possibilities for reservation state: shared/reserved, shared/no-resv, >> private/reserved and private/no-resv. Backing out a reservation may >> require memory allocation which could fail so that needs to be taken >> into account as well. >> >> Instead of writing the required complicated code for this rare >> occurrence, just eliminate the race. i_mmap_rwsem is now held in read >> mode for the duration of page fault processing. Hold i_mmap_rwsem >> longer in truncation and hold punch code to cover the call to >> remove_inode_hugepages. >> >> Cc: <stable@vger.kernel.org> >> Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") >> Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> >> --- >> fs/hugetlbfs/inode.c | 4 ++-- >> 1 file changed, 2 insertions(+), 2 deletions(-) >> >> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c >> index 32920a10100e..3244147fc42b 100644 >> --- a/fs/hugetlbfs/inode.c >> +++ b/fs/hugetlbfs/inode.c >> @@ -505,8 +505,8 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t >> offset) >> i_mmap_lock_write(mapping); >> if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)) >> hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); >> - i_mmap_unlock_write(mapping); >> remove_inode_hugepages(inode, offset, LLONG_MAX); >> + i_mmap_unlock_write(mapping); >> return 0; >> } > > > We used to do remove_inode_hugepages() > > mutex_lock(&hugetlb_fault_mutex_table[hash]); > i_mmap_lock_write(mapping); > hugetlb_vmdelete_list(&mapping->i_mmap, > i_mmap_unlock_write(mapping); > > did we change the lock ordering with this patch? Thanks for taking a look. Yes, we did take locks in that order in the 'if (unlikely(page_mapped(page)))' case within remove_inode_hugepages. That ordering was important as the fault_mutex prevented faults while unmapping the page in all potential mappings. With the change above, we will be holding i_mmap_rwsem in write mode while calling remove_inode_hugepages. The page fault code (modified in previous patch) acquires i_mmap_rwsem in read mode. Therefore, no page faults can occur and, that 'if (unlikely(page_mapped(page)))' case within remove_inode_hugepages will never happen. The now dead code is removed in the subsequent patch. As you suggested in a comment to the subsequent patch, it would be better to combine the patches and remove the dead code when it becomes dead. I will work on that. Actually some of the code in patch 3 applies to patch 1 and some applies to patch 2. So, it will not be simply combining patch 2 and 3.
On 12/17/18 10:42 AM, Mike Kravetz wrote: > On 12/17/18 2:25 AM, Aneesh Kumar K.V wrote: >> On 12/4/18 1:38 AM, Mike Kravetz wrote: >>> <snip> >>> Instead of writing the required complicated code for this rare >>> occurrence, just eliminate the race. i_mmap_rwsem is now held in read >>> mode for the duration of page fault processing. Hold i_mmap_rwsem >>> longer in truncation and hold punch code to cover the call to >>> remove_inode_hugepages. >>> >>> Cc: <stable@vger.kernel.org> >>> Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") >>> Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> >>> --- >>> fs/hugetlbfs/inode.c | 4 ++-- >>> 1 file changed, 2 insertions(+), 2 deletions(-) >>> >>> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c >>> index 32920a10100e..3244147fc42b 100644 >>> --- a/fs/hugetlbfs/inode.c >>> +++ b/fs/hugetlbfs/inode.c >>> @@ -505,8 +505,8 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t >>> offset) >>> i_mmap_lock_write(mapping); >>> if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)) >>> hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); >>> - i_mmap_unlock_write(mapping); >>> remove_inode_hugepages(inode, offset, LLONG_MAX); >>> + i_mmap_unlock_write(mapping); >>> return 0; >>> } >> >> >> We used to do remove_inode_hugepages() >> >> mutex_lock(&hugetlb_fault_mutex_table[hash]); >> i_mmap_lock_write(mapping); >> hugetlb_vmdelete_list(&mapping->i_mmap, >> i_mmap_unlock_write(mapping); >> >> did we change the lock ordering with this patch? > > Thanks for taking a look. > > Yes, we did take locks in that order in the 'if (unlikely(page_mapped(page)))' > case within remove_inode_hugepages. That ordering was important as the > fault_mutex prevented faults while unmapping the page in all potential > mappings. > > With the change above, we will be holding i_mmap_rwsem in write mode while > calling remove_inode_hugepages. The page fault code (modified in previous > patch) acquires i_mmap_rwsem in read mode. Therefore, no page faults can > occur and, that 'if (unlikely(page_mapped(page)))' case within > remove_inode_hugepages will never happen. The now dead code is removed in > the subsequent patch. > > As you suggested in a comment to the subsequent patch, it would be better to > combine the patches and remove the dead code when it becomes dead. I will > work on that. Actually some of the code in patch 3 applies to patch 1 and > some applies to patch 2. So, it will not be simply combining patch 2 and 3. On second thought, the cleanups in patch 3 only apply to patch 2. So, just combining those two patches with a slightly updated commit message as below makes the most sense. Hoping to get more comments on the overall direction and locking changes of this and the previous patch. From: Mike Kravetz <mike.kravetz@oracle.com> hugetlbfs: Use i_mmap_rwsem to fix page fault/truncate race hugetlbfs page faults can race with truncate and hole punch operations. Current code in the page fault path attempts to handle this by 'backing out' operations if we encounter the race. One obvious omission in the current code is removing a page newly added to the page cache. This is pretty straight forward to address, but there is a more subtle and difficult issue of backing out hugetlb reservations. To handle this correctly, the 'reservation state' before page allocation needs to be noted so that it can be properly backed out. There are four distinct possibilities for reservation state: shared/reserved, shared/no-resv, private/reserved and private/no-resv. Backing out a reservation may require memory allocation which could fail so that needs to be taken into account as well. Instead of writing the required complicated code for this rare occurrence, just eliminate the race. i_mmap_rwsem is now held in read mode for the duration of page fault processing. Hold i_mmap_rwsem longer in truncation and hold punch code to cover the call to remove_inode_hugepages. With this modification, code in remove_inode_hugepages checking for races becomes 'dead' as it can not longer happen. Remove the dead code and expand comments to explain reasoning. Similarly, checks for races with truncation in the page fault path can be simplified and removed. Cc: <stable@vger.kernel.org> Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> --- fs/hugetlbfs/inode.c | 50 +++++++++++++++----------------------------- mm/hugetlb.c | 21 +++++++++---------- 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 32920a10100e..a9c00c6ef80d 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -383,17 +383,16 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end) * truncation is indicated by end of range being LLONG_MAX * In this case, we first scan the range and release found pages. * After releasing pages, hugetlb_unreserve_pages cleans up region/reserv - * maps and global counts. Page faults can not race with truncation - * in this routine. hugetlb_no_page() prevents page faults in the - * truncated range. It checks i_size before allocation, and again after - * with the page table lock for the page held. The same lock must be - * acquired to unmap a page. + * maps and global counts. * hole punch is indicated if end is not LLONG_MAX * In the hole punch case we scan the range and release found pages. * Only when releasing a page is the associated region/reserv map * deleted. The region/reserv map for ranges without associated - * pages are not modified. Page faults can race with hole punch. - * This is indicated if we find a mapped page. + * pages are not modified. + * + * Callers of this routine must hold the i_mmap_rwsem in write mode to prevent + * races with page faults. + * * Note: If the passed end of range value is beyond the end of file, but * not LLONG_MAX this routine still performs a hole punch operation. */ @@ -423,32 +422,14 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart, for (i = 0; i < pagevec_count(&pvec); ++i) { struct page *page = pvec.pages[i]; - u32 hash; index = page->index; - hash = hugetlb_fault_mutex_hash(h, current->mm, - &pseudo_vma, - mapping, index, 0); - mutex_lock(&hugetlb_fault_mutex_table[hash]); - /* - * If page is mapped, it was faulted in after being - * unmapped in caller. Unmap (again) now after taking - * the fault mutex. The mutex will prevent faults - * until we finish removing the page. - * - * This race can only happen in the hole punch case. - * Getting here in a truncate operation is a bug. + * A mapped page is impossible as callers should unmap + * all references before calling. And, i_mmap_rwsem + * prevents the creation of additional mappings. */ - if (unlikely(page_mapped(page))) { - BUG_ON(truncate_op); - - i_mmap_lock_write(mapping); - hugetlb_vmdelete_list(&mapping->i_mmap, - index * pages_per_huge_page(h), - (index + 1) * pages_per_huge_page(h)); - i_mmap_unlock_write(mapping); - } + VM_BUG_ON(page_mapped(page)); lock_page(page); /* @@ -470,7 +451,6 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart, } unlock_page(page); - mutex_unlock(&hugetlb_fault_mutex_table[hash]); } huge_pagevec_release(&pvec); cond_resched(); @@ -505,8 +485,8 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) i_mmap_lock_write(mapping); if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)) hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); - i_mmap_unlock_write(mapping); remove_inode_hugepages(inode, offset, LLONG_MAX); + i_mmap_unlock_write(mapping); return 0; } @@ -540,8 +520,8 @@ static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) hugetlb_vmdelete_list(&mapping->i_mmap, hole_start >> PAGE_SHIFT, hole_end >> PAGE_SHIFT); - i_mmap_unlock_write(mapping); remove_inode_hugepages(inode, hole_start, hole_end); + i_mmap_unlock_write(mapping); inode_unlock(inode); } @@ -624,7 +604,11 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, /* addr is the offset within the file (zero based) */ addr = index * hpage_size; - /* mutex taken here, fault path and hole punch */ + /* + * fault mutex taken here, protects against fault path + * and hole punch. inode_lock previously taken protects + * against truncation. + */ hash = hugetlb_fault_mutex_hash(h, mm, &pseudo_vma, mapping, index, addr); mutex_lock(&hugetlb_fault_mutex_table[hash]); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ab4c77b8c72c..25a0cd2f8b39 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3760,16 +3760,16 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, } /* - * Use page lock to guard against racing truncation - * before we get page_table_lock. + * We can not race with truncation due to holding i_mmap_rwsem. + * Check once here for faults beyond end of file. */ + size = i_size_read(mapping->host) >> huge_page_shift(h); + if (idx >= size) + goto out; + retry: page = find_lock_page(mapping, idx); if (!page) { - size = i_size_read(mapping->host) >> huge_page_shift(h); - if (idx >= size) - goto out; - /* * Check for page in userfault range */ @@ -3859,9 +3859,6 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, } ptl = huge_pte_lock(h, mm, ptep); - size = i_size_read(mapping->host) >> huge_page_shift(h); - if (idx >= size) - goto backout; ret = 0; if (!huge_pte_none(huge_ptep_get(ptep))) @@ -3964,8 +3961,10 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, /* * Acquire i_mmap_rwsem before calling huge_pte_alloc and hold - * until finished with ptep. This prevents huge_pmd_unshare from - * being called elsewhere and making the ptep no longer valid. + * until finished with ptep. This serves two purposes: + * 1) It prevents huge_pmd_unshare from being called elsewhere + * and making the ptep no longer valid. + * 2) It synchronizes us with file truncation. * * ptep could have already be assigned via huge_pte_offset. That * is OK, as huge_pte_alloc will return the same value unless
On Mon, 17 Dec 2018 16:17:52 -0800 Mike Kravetz <mike.kravetz@oracle.com> wrote: > ... > > > As you suggested in a comment to the subsequent patch, it would be better to > > combine the patches and remove the dead code when it becomes dead. I will > > work on that. Actually some of the code in patch 3 applies to patch 1 and > > some applies to patch 2. So, it will not be simply combining patch 2 and 3. > > On second thought, the cleanups in patch 3 only apply to patch 2. So, just > combining those two patches with a slightly updated commit message as below > makes the most sense. All confused. I dropped the current version, let's try again. This: > Hoping to get more comments on the overall direction and locking changes > of this and the previous patch. and this: > Cc: <stable@vger.kernel.org> > Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") make for a hot combination. Could people please prioritize review of this code? Perhaps a refresh and resend is in order.
On 12/18/18 2:10 PM, Andrew Morton wrote: > On Mon, 17 Dec 2018 16:17:52 -0800 Mike Kravetz <mike.kravetz@oracle.com> wrote: > >> ... >> >>> As you suggested in a comment to the subsequent patch, it would be better to >>> combine the patches and remove the dead code when it becomes dead. I will >>> work on that. Actually some of the code in patch 3 applies to patch 1 and >>> some applies to patch 2. So, it will not be simply combining patch 2 and 3. >> >> On second thought, the cleanups in patch 3 only apply to patch 2. So, just >> combining those two patches with a slightly updated commit message as below >> makes the most sense. > > All confused. I dropped the current version, let's try again. > > This: > >> Hoping to get more comments on the overall direction and locking changes >> of this and the previous patch. > > and this: > >> Cc: <stable@vger.kernel.org> >> Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") > > make for a hot combination. Could people please prioritize review of > this code? > > Perhaps a refresh and resend is in order. Will send out a new version shortly. No functional changes. Only changes to the way the patches are structured. I guess fixing in stable could be open for discussion. These issues have been around for more than 10 years. I am not aware of anyone hitting them in actual real world usage. The problems were only "found" through code inspection while working other issues in the same code. However, after discovering the issues it was pretty easy to write user space code to expose them.
Hi, [This is an automated email] This commit has been processed because it contains a "Fixes:" tag, fixing commit: ebed4bfc8da8 [PATCH] hugetlb: fix absurd HugePages_Rsvd. The bot has tested the following trees: v5.1.9, v4.19.50, v4.14.125, v4.9.181, v4.4.181. v4.19.50: Build OK! v4.14.125: Build OK! v4.9.181: Build OK! v4.4.181: Failed to apply! Possible dependencies: 0070e28d97e7 ("radix_tree: loop based on shift count, not height") 00f47b581105 ("radix-tree: rewrite radix_tree_tag_clear") 0e749e54244e ("dax: increase granularity of dax_clear_blocks() operations") 1366c37ed84b ("radix tree test harness") 29f3ad7d8380 ("fs: Provide function to unmap metadata for a range of blocks") 334fd34d76f2 ("vfs: Add page_cache_seek_hole_data helper") 339e6353046d ("radix_tree: tag all internal tree nodes as indirect pointers") 4aae8d1c051e ("mm/hugetlbfs: unmap pages if page fault raced with hole punch") 52db400fcd50 ("pmem, dax: clean up clear_pmem()") 72e2936c04f7 ("mm: remove unnecessary condition in remove_inode_hugepages") 7fc9e4722435 ("fs: Introduce filemap_range_has_page()") 83929372f629 ("filemap: prepare find and delete operations for huge pages") ac401cc78242 ("dax: New fault locking") b2e0d1625e19 ("dax: fix lifetime of in-kernel dax mappings with dax_map_atomic()") d604c324524b ("radix-tree: introduce radix_tree_replace_clear_tags()") d72dc8a25afc ("mm: make pagevec_lookup() update index") e4b274915863 ("DAX: move RADIX_DAX_ definitions to dax.c") e61452365372 ("radix_tree: add support for multi-order entries") f9fe48bece3a ("dax: support dirty DAX entries in radix tree") How should we proceed with this patch? -- Thanks, Sasha
On 6/14/19 2:56 PM, Sasha Levin wrote: > Hi, > > [This is an automated email] > > This commit has been processed because it contains a "Fixes:" tag, > fixing commit: ebed4bfc8da8 [PATCH] hugetlb: fix absurd HugePages_Rsvd. <snip> > > How should we proceed with this patch? > I hope you do nothing with this as the patch is not upstream.
On Fri, Jun 14, 2019 at 04:33:53PM -0700, Mike Kravetz wrote: >On 6/14/19 2:56 PM, Sasha Levin wrote: >> Hi, >> >> [This is an automated email] >> >> This commit has been processed because it contains a "Fixes:" tag, >> fixing commit: ebed4bfc8da8 [PATCH] hugetlb: fix absurd HugePages_Rsvd. ><snip> >> >> How should we proceed with this patch? >> > >I hope you do nothing with this as the patch is not upstream. We do not, it's just a way to get more responses before people moved on to dealing with other work. -- Thanks, Sasha
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 32920a10100e..3244147fc42b 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -505,8 +505,8 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) i_mmap_lock_write(mapping); if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)) hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); - i_mmap_unlock_write(mapping); remove_inode_hugepages(inode, offset, LLONG_MAX); + i_mmap_unlock_write(mapping); return 0; } @@ -540,8 +540,8 @@ static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) hugetlb_vmdelete_list(&mapping->i_mmap, hole_start >> PAGE_SHIFT, hole_end >> PAGE_SHIFT); - i_mmap_unlock_write(mapping); remove_inode_hugepages(inode, hole_start, hole_end); + i_mmap_unlock_write(mapping); inode_unlock(inode); }
hugetlbfs page faults can race with truncate and hole punch operations. Current code in the page fault path attempts to handle this by 'backing out' operations if we encounter the race. One obvious omission in the current code is removing a page newly added to the page cache. This is pretty straight forward to address, but there is a more subtle and difficult issue of backing out hugetlb reservations. To handle this correctly, the 'reservation state' before page allocation needs to be noted so that it can be properly backed out. There are four distinct possibilities for reservation state: shared/reserved, shared/no-resv, private/reserved and private/no-resv. Backing out a reservation may require memory allocation which could fail so that needs to be taken into account as well. Instead of writing the required complicated code for this rare occurrence, just eliminate the race. i_mmap_rwsem is now held in read mode for the duration of page fault processing. Hold i_mmap_rwsem longer in truncation and hold punch code to cover the call to remove_inode_hugepages. Cc: <stable@vger.kernel.org> Fixes: ebed4bfc8da8 ("hugetlb: fix absurd HugePages_Rsvd") Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> --- fs/hugetlbfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)