mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 11:03:43 +02:00
hugetlb: create remove_inode_single_folio to remove single file folio
Create the new routine remove_inode_single_folio that will remove a single folio from a file. This is refactored code from remove_inode_hugepages. It checks for the uncommon case in which the folio is still mapped and unmaps. No functional change. This refactoring will be put to use and expanded upon in a subsequent patches. Link: https://lkml.kernel.org/r/20220914221810.95771-5-mike.kravetz@oracle.com Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> Reviewed-by: Miaohe Lin <linmiaohe@huawei.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Cc: Axel Rasmussen <axelrasmussen@google.com> Cc: David Hildenbrand <david@redhat.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: James Houghton <jthoughton@google.com> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Mina Almasry <almasrymina@google.com> Cc: Muchun Song <songmuchun@bytedance.com> Cc: Naoya Horiguchi <naoya.horiguchi@linux.dev> Cc: Pasha Tatashin <pasha.tatashin@soleen.com> Cc: Peter Xu <peterx@redhat.com> Cc: Prakash Sangappa <prakash.sangappa@oracle.com> Cc: Sven Schnelle <svens@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
7e1813d48d
commit
c86272287b
|
|
@ -411,6 +411,60 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called with hugetlb fault mutex held.
|
||||||
|
* Returns true if page was actually removed, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool remove_inode_single_folio(struct hstate *h, struct inode *inode,
|
||||||
|
struct address_space *mapping,
|
||||||
|
struct folio *folio, pgoff_t index,
|
||||||
|
bool truncate_op)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If folio is mapped, it was faulted in after being
|
||||||
|
* unmapped in caller. Unmap (again) while holding
|
||||||
|
* the fault mutex. The mutex will prevent faults
|
||||||
|
* until we finish removing the folio.
|
||||||
|
*/
|
||||||
|
if (unlikely(folio_mapped(folio))) {
|
||||||
|
i_mmap_lock_write(mapping);
|
||||||
|
hugetlb_vmdelete_list(&mapping->i_mmap,
|
||||||
|
index * pages_per_huge_page(h),
|
||||||
|
(index + 1) * pages_per_huge_page(h),
|
||||||
|
ZAP_FLAG_DROP_MARKER);
|
||||||
|
i_mmap_unlock_write(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
folio_lock(folio);
|
||||||
|
/*
|
||||||
|
* After locking page, make sure mapping is the same.
|
||||||
|
* We could have raced with page fault populate and
|
||||||
|
* backout code.
|
||||||
|
*/
|
||||||
|
if (folio_mapping(folio) == mapping) {
|
||||||
|
/*
|
||||||
|
* We must remove the folio from page cache before removing
|
||||||
|
* the region/ reserve map (hugetlb_unreserve_pages). In
|
||||||
|
* rare out of memory conditions, removal of the region/reserve
|
||||||
|
* map could fail. Correspondingly, the subpool and global
|
||||||
|
* reserve usage count can need to be adjusted.
|
||||||
|
*/
|
||||||
|
VM_BUG_ON(HPageRestoreReserve(&folio->page));
|
||||||
|
hugetlb_delete_from_page_cache(&folio->page);
|
||||||
|
ret = true;
|
||||||
|
if (!truncate_op) {
|
||||||
|
if (unlikely(hugetlb_unreserve_pages(inode, index,
|
||||||
|
index + 1, 1)))
|
||||||
|
hugetlb_fix_reserve_counts(inode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
folio_unlock(folio);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove_inode_hugepages handles two distinct cases: truncation and hole
|
* remove_inode_hugepages handles two distinct cases: truncation and hole
|
||||||
* punch. There are subtle differences in operation for each case.
|
* punch. There are subtle differences in operation for each case.
|
||||||
|
|
@ -418,11 +472,10 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
|
||||||
* truncation is indicated by end of range being LLONG_MAX
|
* truncation is indicated by end of range being LLONG_MAX
|
||||||
* In this case, we first scan the range and release found pages.
|
* In this case, we first scan the range and release found pages.
|
||||||
* After releasing pages, hugetlb_unreserve_pages cleans up region/reserve
|
* After releasing pages, hugetlb_unreserve_pages cleans up region/reserve
|
||||||
* maps and global counts. Page faults can not race with truncation
|
* maps and global counts. Page faults can race with truncation.
|
||||||
* in this routine. hugetlb_no_page() prevents page faults in the
|
* During faults, hugetlb_no_page() checks i_size before page allocation,
|
||||||
* truncated range. It checks i_size before allocation, and again after
|
* and again after obtaining page table lock. It will 'back out'
|
||||||
* with the page table lock for the page held. The same lock must be
|
* allocations in the truncated range.
|
||||||
* acquired to unmap a page.
|
|
||||||
* hole punch is indicated if end is not LLONG_MAX
|
* hole punch is indicated if end is not LLONG_MAX
|
||||||
* In the hole punch case we scan the range and release found pages.
|
* In the hole punch case we scan the range and release found pages.
|
||||||
* Only when releasing a page is the associated region/reserve map
|
* Only when releasing a page is the associated region/reserve map
|
||||||
|
|
@ -456,44 +509,12 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
|
||||||
mutex_lock(&hugetlb_fault_mutex_table[hash]);
|
mutex_lock(&hugetlb_fault_mutex_table[hash]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If folio is mapped, it was faulted in after being
|
* Remove folio that was part of folio_batch.
|
||||||
* unmapped in caller. Unmap (again) now after taking
|
|
||||||
* the fault mutex. The mutex will prevent faults
|
|
||||||
* until we finish removing the folio.
|
|
||||||
*
|
|
||||||
* This race can only happen in the hole punch case.
|
|
||||||
* Getting here in a truncate operation is a bug.
|
|
||||||
*/
|
*/
|
||||||
if (unlikely(folio_mapped(folio))) {
|
if (remove_inode_single_folio(h, inode, mapping, folio,
|
||||||
BUG_ON(truncate_op);
|
index, truncate_op))
|
||||||
|
freed++;
|
||||||
|
|
||||||
i_mmap_lock_write(mapping);
|
|
||||||
hugetlb_vmdelete_list(&mapping->i_mmap,
|
|
||||||
index * pages_per_huge_page(h),
|
|
||||||
(index + 1) * pages_per_huge_page(h),
|
|
||||||
ZAP_FLAG_DROP_MARKER);
|
|
||||||
i_mmap_unlock_write(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
folio_lock(folio);
|
|
||||||
/*
|
|
||||||
* We must free the huge page and remove from page
|
|
||||||
* cache BEFORE removing the region/reserve map
|
|
||||||
* (hugetlb_unreserve_pages). In rare out of memory
|
|
||||||
* conditions, removal of the region/reserve map could
|
|
||||||
* fail. Correspondingly, the subpool and global
|
|
||||||
* reserve usage count can need to be adjusted.
|
|
||||||
*/
|
|
||||||
VM_BUG_ON(HPageRestoreReserve(&folio->page));
|
|
||||||
hugetlb_delete_from_page_cache(&folio->page);
|
|
||||||
freed++;
|
|
||||||
if (!truncate_op) {
|
|
||||||
if (unlikely(hugetlb_unreserve_pages(inode,
|
|
||||||
index, index + 1, 1)))
|
|
||||||
hugetlb_fix_reserve_counts(inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
folio_unlock(folio);
|
|
||||||
mutex_unlock(&hugetlb_fault_mutex_table[hash]);
|
mutex_unlock(&hugetlb_fault_mutex_table[hash]);
|
||||||
}
|
}
|
||||||
folio_batch_release(&fbatch);
|
folio_batch_release(&fbatch);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user