Skip to content

Commit 9ee5d17

Browse files
Shameer Kolothumakpm00
authored andcommitted
mm/hugetlb: fix incorrect error return from hugetlb_reserve_pages()
The function hugetlb_reserve_pages() returns the number of pages added to the reservation map on success and a negative error code on failure (e.g. -EINVAL, -ENOMEM). However, in some error paths, it may return -1 directly. For example, a failure at: if (hugetlb_acct_memory(h, gbl_reserve) < 0) goto out_put_pages; results in returning -1 (since add = -1), which may be misinterpreted in userspace as -EPERM. Fix this by explicitly capturing and propagating the return values from helper functions, and using -EINVAL for all other failure cases. Link: https://lkml.kernel.org/r/20251125171350.86441-1-skolothumtho@nvidia.com Fixes: 986f5f2 ("mm/hugetlb: make hugetlb_reserve_pages() return nr of entries updated") Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Reviewed-by: Joshua Hahn <joshua.hahnjy@gmail.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Acked-by: Oscar Salvador <osalvador@suse.de> Cc: Matthew R. Ochs <mochs@nvidia.com> Cc: Muchun Song <muchun.song@linux.dev> Cc: Nicolin Chen <nicolinc@nvidia.com> Cc: Vivek Kasireddy <vivek.kasireddy@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 40a4af5 commit 9ee5d17

1 file changed

Lines changed: 18 additions & 7 deletions

File tree

mm/hugetlb.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6579,6 +6579,7 @@ long hugetlb_reserve_pages(struct inode *inode,
65796579
struct resv_map *resv_map;
65806580
struct hugetlb_cgroup *h_cg = NULL;
65816581
long gbl_reserve, regions_needed = 0;
6582+
int err;
65826583

65836584
/* This should never happen */
65846585
if (from > to) {
@@ -6612,20 +6613,26 @@ long hugetlb_reserve_pages(struct inode *inode,
66126613
} else {
66136614
/* Private mapping. */
66146615
resv_map = resv_map_alloc();
6615-
if (!resv_map)
6616+
if (!resv_map) {
6617+
err = -ENOMEM;
66166618
goto out_err;
6619+
}
66176620

66186621
chg = to - from;
66196622

66206623
set_vma_desc_resv_map(desc, resv_map);
66216624
set_vma_desc_resv_flags(desc, HPAGE_RESV_OWNER);
66226625
}
66236626

6624-
if (chg < 0)
6627+
if (chg < 0) {
6628+
/* region_chg() above can return -ENOMEM */
6629+
err = (chg == -ENOMEM) ? -ENOMEM : -EINVAL;
66256630
goto out_err;
6631+
}
66266632

6627-
if (hugetlb_cgroup_charge_cgroup_rsvd(hstate_index(h),
6628-
chg * pages_per_huge_page(h), &h_cg) < 0)
6633+
err = hugetlb_cgroup_charge_cgroup_rsvd(hstate_index(h),
6634+
chg * pages_per_huge_page(h), &h_cg);
6635+
if (err < 0)
66296636
goto out_err;
66306637

66316638
if (desc && !(desc->vm_flags & VM_MAYSHARE) && h_cg) {
@@ -6641,14 +6648,17 @@ long hugetlb_reserve_pages(struct inode *inode,
66416648
* reservations already in place (gbl_reserve).
66426649
*/
66436650
gbl_reserve = hugepage_subpool_get_pages(spool, chg);
6644-
if (gbl_reserve < 0)
6651+
if (gbl_reserve < 0) {
6652+
err = gbl_reserve;
66456653
goto out_uncharge_cgroup;
6654+
}
66466655

66476656
/*
66486657
* Check enough hugepages are available for the reservation.
66496658
* Hand the pages back to the subpool if there are not
66506659
*/
6651-
if (hugetlb_acct_memory(h, gbl_reserve) < 0)
6660+
err = hugetlb_acct_memory(h, gbl_reserve);
6661+
if (err < 0)
66526662
goto out_put_pages;
66536663

66546664
/*
@@ -6667,6 +6677,7 @@ long hugetlb_reserve_pages(struct inode *inode,
66676677

66686678
if (unlikely(add < 0)) {
66696679
hugetlb_acct_memory(h, -gbl_reserve);
6680+
err = add;
66706681
goto out_put_pages;
66716682
} else if (unlikely(chg > add)) {
66726683
/*
@@ -6726,7 +6737,7 @@ long hugetlb_reserve_pages(struct inode *inode,
67266737
kref_put(&resv_map->refs, resv_map_release);
67276738
set_vma_desc_resv_map(desc, NULL);
67286739
}
6729-
return chg < 0 ? chg : add < 0 ? add : -EINVAL;
6740+
return err;
67306741
}
67316742

67326743
long hugetlb_unreserve_pages(struct inode *inode, long start, long end,

0 commit comments

Comments
 (0)