Skip to content

Commit e32905e

Browse files
mjkravetztorvalds
authored andcommitted
userfaultfd: hugetlbfs: fix new flag usage in error path
In commit d6995da ("hugetlb: use page.private for hugetlb specific page flags") the use of PagePrivate to indicate a reservation count should be restored at free time was changed to the hugetlb specific flag HPageRestoreReserve. Changes to a userfaultfd error path as well as a VM_BUG_ON() in remove_inode_hugepages() were overlooked. Users could see incorrect hugetlb reserve counts if they experience an error with a UFFDIO_COPY operation. Specifically, this would be the result of an unlikely copy_huge_page_from_user error. There is not an increased chance of hitting the VM_BUG_ON. Link: https://lkml.kernel.org/r/[email protected] Fixes: d6995da ("hugetlb: use page.private for hugetlb specific page flags") Signed-off-by: Mike Kravetz <[email protected]> Reviewed-by: Mina Almasry <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Muchun Song <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Miaohe Lin <[email protected]> Cc: Mina Almasry <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1b6d639 commit e32905e

File tree

2 files changed

+15
-15
lines changed

2 files changed

+15
-15
lines changed

fs/hugetlbfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
529529
* the subpool and global reserve usage count can need
530530
* to be adjusted.
531531
*/
532-
VM_BUG_ON(PagePrivate(page));
532+
VM_BUG_ON(HPageRestoreReserve(page));
533533
remove_huge_page(page);
534534
freed++;
535535
if (!truncate_op) {

mm/userfaultfd.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -360,38 +360,38 @@ static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
360360
* If a reservation for the page existed in the reservation
361361
* map of a private mapping, the map was modified to indicate
362362
* the reservation was consumed when the page was allocated.
363-
* We clear the PagePrivate flag now so that the global
363+
* We clear the HPageRestoreReserve flag now so that the global
364364
* reserve count will not be incremented in free_huge_page.
365365
* The reservation map will still indicate the reservation
366366
* was consumed and possibly prevent later page allocation.
367367
* This is better than leaking a global reservation. If no
368-
* reservation existed, it is still safe to clear PagePrivate
369-
* as no adjustments to reservation counts were made during
370-
* allocation.
368+
* reservation existed, it is still safe to clear
369+
* HPageRestoreReserve as no adjustments to reservation counts
370+
* were made during allocation.
371371
*
372372
* The reservation map for shared mappings indicates which
373373
* pages have reservations. When a huge page is allocated
374374
* for an address with a reservation, no change is made to
375-
* the reserve map. In this case PagePrivate will be set
376-
* to indicate that the global reservation count should be
375+
* the reserve map. In this case HPageRestoreReserve will be
376+
* set to indicate that the global reservation count should be
377377
* incremented when the page is freed. This is the desired
378378
* behavior. However, when a huge page is allocated for an
379379
* address without a reservation a reservation entry is added
380-
* to the reservation map, and PagePrivate will not be set.
381-
* When the page is freed, the global reserve count will NOT
382-
* be incremented and it will appear as though we have leaked
383-
* reserved page. In this case, set PagePrivate so that the
384-
* global reserve count will be incremented to match the
385-
* reservation map entry which was created.
380+
* to the reservation map, and HPageRestoreReserve will not be
381+
* set. When the page is freed, the global reserve count will
382+
* NOT be incremented and it will appear as though we have
383+
* leaked reserved page. In this case, set HPageRestoreReserve
384+
* so that the global reserve count will be incremented to
385+
* match the reservation map entry which was created.
386386
*
387387
* Note that vm_alloc_shared is based on the flags of the vma
388388
* for which the page was originally allocated. dst_vma could
389389
* be different or NULL on error.
390390
*/
391391
if (vm_alloc_shared)
392-
SetPagePrivate(page);
392+
SetHPageRestoreReserve(page);
393393
else
394-
ClearPagePrivate(page);
394+
ClearHPageRestoreReserve(page);
395395
put_page(page);
396396
}
397397
BUG_ON(copied < 0);

0 commit comments

Comments
 (0)