diff mbox series

[v2] mm: hugetlb: add hwcrp_hugepages to record memory failure on hugetlbfs

Message ID 20210623085102.2458-1-wangbin224@huawei.com (mailing list archive)
State New
Headers show
Series [v2] mm: hugetlb: add hwcrp_hugepages to record memory failure on hugetlbfs | expand

Commit Message

Bin Wang June 23, 2021, 8:51 a.m. UTC
From: Bin Wang <wangbin224@huawei.com>

In the current hugetlbfs memory failure handler, reserved huge page
counts are used to record the number of huge pages with hwposion.
There are two problems:

1. We call hugetlb_fix_reserve_counts() to change reserved counts
in hugetlbfs_error_remove_page(). But this function is only called if
hugetlb_unreserve_pages() fails, and hugetlb_unreserve_pages() fails
only if kmalloc in region_del() fails, which is almost impossible.
As a result, the reserved count is not corrected as expected when a
memory failure occurs.

2. Reserved counts is designed to display the number of hugepages
reserved at mmap() time. This means that even if we fix the first
issue, reserved counts will be confusing because we can't tell if
it's hwposion or reserved hugepage.

This patch adds hardware corrput huge pages counts to record memory
failure on hugetlbfs instead of reserved counts.

Signed-off-by: Bin Wang <wangbin224@huawei.com>
---
 fs/hugetlbfs/inode.c    |  3 +--
 include/linux/hugetlb.h |  3 +++
 mm/hugetlb.c            | 30 ++++++++++++++++++++++++++++++
 3 files changed, 34 insertions(+), 2 deletions(-)

Comments

Mike Kravetz June 25, 2021, 11:07 p.m. UTC | #1
On 6/23/21 1:51 AM, wangbin wrote:
> From: Bin Wang <wangbin224@huawei.com>
> 
> In the current hugetlbfs memory failure handler, reserved huge page
> counts are used to record the number of huge pages with hwposion.
> There are two problems:

Plese review the comments from the first patch.  Reserved huge page
counts are NOT used to record the number of huge pages with hwposion.

> 
> 1. We call hugetlb_fix_reserve_counts() to change reserved counts
> in hugetlbfs_error_remove_page(). But this function is only called if
> hugetlb_unreserve_pages() fails, and hugetlb_unreserve_pages() fails
> only if kmalloc in region_del() fails, which is almost impossible.
> As a result, the reserved count is not corrected as expected when a
> memory failure occurs.
> 
> 2. Reserved counts is designed to display the number of hugepages
> reserved at mmap() time. This means that even if we fix the first
> issue, reserved counts will be confusing because we can't tell if
> it's hwposion or reserved hugepage.
> 
> This patch adds hardware corrput huge pages counts to record memory
> failure on hugetlbfs instead of reserved counts.
> 
> Signed-off-by: Bin Wang <wangbin224@huawei.com>
> ---
>  fs/hugetlbfs/inode.c    |  3 +--
>  include/linux/hugetlb.h |  3 +++
>  mm/hugetlb.c            | 30 ++++++++++++++++++++++++++++++
>  3 files changed, 34 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 926eeb9bf4eb..ffb6e7b6756b 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -986,8 +986,7 @@ static int hugetlbfs_error_remove_page(struct address_space *mapping,
>  	pgoff_t index = page->index;
>  
>  	remove_huge_page(page);
> -	if (unlikely(hugetlb_unreserve_pages(inode, index, index + 1, 1)))
> -		hugetlb_fix_reserve_counts(inode);

As mentioned, huge page reserve counts are not used to record number of
poisioned pages.  The calls to hugetlb_unreserve_pages and possibly
hugetlb_fix_reserve_counts are necessary for reserve accounting.  They
can not be removed.

> +	hugetlb_fix_hwcrp_counts(page);

This new routine just counts memory errors on 'in use' huge pages.
I do not see a call anywhere to count memory errors on huge pages
not in use.

>  
>  	return 0;
>  }
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index f7ca1a3870ea..1d5bada80aa5 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -171,6 +171,7 @@ void putback_active_hugepage(struct page *page);
>  void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
>  void free_huge_page(struct page *page);
>  void hugetlb_fix_reserve_counts(struct inode *inode);
> +void hugetlb_fix_hwcrp_counts(struct page *page);
>  extern struct mutex *hugetlb_fault_mutex_table;
>  u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx);
>  
> @@ -602,12 +603,14 @@ struct hstate {
>  	unsigned long free_huge_pages;
>  	unsigned long resv_huge_pages;
>  	unsigned long surplus_huge_pages;
> +	unsigned long hwcrp_huge_pages;
>  	unsigned long nr_overcommit_huge_pages;
>  	struct list_head hugepage_activelist;
>  	struct list_head hugepage_freelists[MAX_NUMNODES];
>  	unsigned int nr_huge_pages_node[MAX_NUMNODES];
>  	unsigned int free_huge_pages_node[MAX_NUMNODES];
>  	unsigned int surplus_huge_pages_node[MAX_NUMNODES];
> +	unsigned int hwcrp_huge_pages_node[MAX_NUMNODES];

I understand your requirement to count the number of memory errors on
hugetlb pages.  However, we need to think carefully about we represent
that count.

Noaya, do you have opinions on where would be the best place to store
this information?  The hugetlb memory error code has the comment 'needs
work'.  Ideally, we could isolate memory errors to a single base (4K for
x86) page and free the remaining base pages to buddy.  We could also
potentially allocate a 'replacement' hugetlb page doing something like
alloc_and_dissolve_huge_page.

If we get an error on a hugetlb page and can isolate it to a base page
and replace the huge page, is it still a huge page memory error?

IMO, we should work on isolating memory errors to a base page and
replacing the huge page.  Then, the existing count of base pages with
memory errors would be sufficient?

This is something I would like to work, but I have higher priorities
right now.
Bin Wang June 28, 2021, 9:27 a.m. UTC | #2
> > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> > index 926eeb9bf4eb..ffb6e7b6756b 100644
> > --- a/fs/hugetlbfs/inode.c
> > +++ b/fs/hugetlbfs/inode.c
> > @@ -986,8 +986,7 @@ static int hugetlbfs_error_remove_page(struct address_space *mapping,
> >  	pgoff_t index = page->index;
> >  
> >  	remove_huge_page(page);
> > -	if (unlikely(hugetlb_unreserve_pages(inode, index, index + 1, 1)))
> > -		hugetlb_fix_reserve_counts(inode);
> 
> As mentioned, huge page reserve counts are not used to record number of
> poisioned pages.  The calls to hugetlb_unreserve_pages and possibly
> hugetlb_fix_reserve_counts are necessary for reserve accounting.  They
> can not be removed.

Thanks for your explanation very much. I didn't get the point of the
comments from the first patch. hugetlb_fix_reserve_counts() shouldn't
be removed and I will fix this.

> > +	hugetlb_fix_hwcrp_counts(page);
> 
> This new routine just counts memory errors on 'in use' huge pages.
> I do not see a call anywhere to count memory errors on huge pages
> not in use.

It's my oversight. I should have considered this situation. I tested
it with hwcrp_hugepages count, and this is the result:
# cat /proc/meminfo |grep -E 'HugePages_|Hard'
HardwareCorrupted:     0 kB
HugePages_Total:      64
HugePages_Free:       64
HugePages_Rsvd:        0
HugePages_Surp:        0
HugePages_Hwcrp:       0
No count changes, even the HardwareCorrupted. I'm not sure if this is
normal. This is what happens in kernel(stable master branch):
static int memory_failure_hugetlb(unsigned long pfn, int flags)
{
	...
	/* TestSetPageHWPoison return 0 */
	if (TestSetPageHWPoison(head)) {
		...
	}

	num_poisoned_pages_inc(); /* HardwareCorrupted += PAGE_SIZE */

	/* get_hwpoison_page() return 0 */
	if (!(flags & MF_COUNT_INCREASED) && !get_hwpoison_page(p, flags, 0)) {
		/*
		 * Check "filter hit" and "race with other subpage."
		 */
		lock_page(head);
		/* PageHWPoison() return 1 */
		if (PageHWPoison(head)) {
			/* (p != head && TestSetPageHWPoison(head)) is hit */
			if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
			    || (p != head && TestSetPageHWPoison(head))) {
				/* HardwareCorrupted -= PAGE_SIZE */
				num_poisoned_pages_dec();
				unlock_page(head);
				return 0;
			}
		}
		...
	}
	...
}
It seems like that memory errors on huge pages not in use hit the
"race with other subpage". I think I shouldn't add hwcrp_hugepages in
this routine. Maybe we need more conditions to distinguish this.

> >  
> >  	return 0;
> >  }
> > diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> > index f7ca1a3870ea..1d5bada80aa5 100644
> > --- a/include/linux/hugetlb.h
> > +++ b/include/linux/hugetlb.h
> > @@ -171,6 +171,7 @@ void putback_active_hugepage(struct page *page);
> >  void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
> >  void free_huge_page(struct page *page);
> >  void hugetlb_fix_reserve_counts(struct inode *inode);
> > +void hugetlb_fix_hwcrp_counts(struct page *page);
> >  extern struct mutex *hugetlb_fault_mutex_table;
> >  u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx);
> >  
> > @@ -602,12 +603,14 @@ struct hstate {
> >  	unsigned long free_huge_pages;
> >  	unsigned long resv_huge_pages;
> >  	unsigned long surplus_huge_pages;
> > +	unsigned long hwcrp_huge_pages;
> >  	unsigned long nr_overcommit_huge_pages;
> >  	struct list_head hugepage_activelist;
> >  	struct list_head hugepage_freelists[MAX_NUMNODES];
> >  	unsigned int nr_huge_pages_node[MAX_NUMNODES];
> >  	unsigned int free_huge_pages_node[MAX_NUMNODES];
> >  	unsigned int surplus_huge_pages_node[MAX_NUMNODES];
> > +	unsigned int hwcrp_huge_pages_node[MAX_NUMNODES];
> 
> I understand your requirement to count the number of memory errors on
> hugetlb pages.  However, we need to think carefully about we represent
> that count.
> 
> Noaya, do you have opinions on where would be the best place to store
> this information?  The hugetlb memory error code has the comment 'needs
> work'.  Ideally, we could isolate memory errors to a single base (4K for
> x86) page and free the remaining base pages to buddy.  We could also
> potentially allocate a 'replacement' hugetlb page doing something like
> alloc_and_dissolve_huge_page.
> 
> If we get an error on a hugetlb page and can isolate it to a base page
> and replace the huge page, is it still a huge page memory error?
> 
> IMO, we should work on isolating memory errors to a base page and
> replacing the huge page.  Then, the existing count of base pages with
> memory errors would be sufficient?
> 
> This is something I would like to work, but I have higher priorities
> right now.

Yes, splitting the huge pages and isolating a base page is ideal. And
we do this with dissolve_free_huge_page() when page_mapping() return
NULL. I think there is a reason(but I do not get it) why we don't split
huge pags in hugetlbfs_error_remove_page() or after. So I choose to 
add a new count.

--
Bin Wang
Naoya Horiguchi June 29, 2021, 8:08 a.m. UTC | #3
Hi Bin, Mike,

On Mon, Jun 28, 2021 at 05:27:52PM +0800, Bin Wang wrote:
> > > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> > > index 926eeb9bf4eb..ffb6e7b6756b 100644
> > > --- a/fs/hugetlbfs/inode.c
> > > +++ b/fs/hugetlbfs/inode.c
> > > @@ -986,8 +986,7 @@ static int hugetlbfs_error_remove_page(struct address_space *mapping,
> > >  	pgoff_t index = page->index;
> > >  
> > >  	remove_huge_page(page);
> > > -	if (unlikely(hugetlb_unreserve_pages(inode, index, index + 1, 1)))
> > > -		hugetlb_fix_reserve_counts(inode);
> > 
> > As mentioned, huge page reserve counts are not used to record number of
> > poisioned pages.  The calls to hugetlb_unreserve_pages and possibly
> > hugetlb_fix_reserve_counts are necessary for reserve accounting.  They
> > can not be removed.
> 
> Thanks for your explanation very much. I didn't get the point of the
> comments from the first patch. hugetlb_fix_reserve_counts() shouldn't
> be removed and I will fix this.
> 
> > > +	hugetlb_fix_hwcrp_counts(page);
> > 
> > This new routine just counts memory errors on 'in use' huge pages.
> > I do not see a call anywhere to count memory errors on huge pages
> > not in use.
> 
> It's my oversight. I should have considered this situation. I tested
> it with hwcrp_hugepages count, and this is the result:
> # cat /proc/meminfo |grep -E 'HugePages_|Hard'
> HardwareCorrupted:     0 kB
> HugePages_Total:      64
> HugePages_Free:       64
> HugePages_Rsvd:        0
> HugePages_Surp:        0
> HugePages_Hwcrp:       0
> No count changes, even the HardwareCorrupted. I'm not sure if this is
> normal. This is what happens in kernel(stable master branch):
> static int memory_failure_hugetlb(unsigned long pfn, int flags)
> {
> 	...
> 	/* TestSetPageHWPoison return 0 */
> 	if (TestSetPageHWPoison(head)) {
> 		...
> 	}
> 
> 	num_poisoned_pages_inc(); /* HardwareCorrupted += PAGE_SIZE */
> 
> 	/* get_hwpoison_page() return 0 */
> 	if (!(flags & MF_COUNT_INCREASED) && !get_hwpoison_page(p, flags, 0)) {
> 		/*
> 		 * Check "filter hit" and "race with other subpage."
> 		 */
> 		lock_page(head);
> 		/* PageHWPoison() return 1 */
> 		if (PageHWPoison(head)) {
> 			/* (p != head && TestSetPageHWPoison(head)) is hit */
> 			if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
> 			    || (p != head && TestSetPageHWPoison(head))) {
> 				/* HardwareCorrupted -= PAGE_SIZE */
> 				num_poisoned_pages_dec();
> 				unlock_page(head);
> 				return 0;
> 			}
> 		}
> 		...
> 	}
> 	...
> }
> It seems like that memory errors on huge pages not in use hit the
> "race with other subpage". I think I shouldn't add hwcrp_hugepages in
> this routine. Maybe we need more conditions to distinguish this.

BTW, I think that the race handled by this if-block will be no longer
necessary if mf_mutex is extended to cover unpoison_memory() by patch
"mm/hwpoison: mf_mutex for soft offline and unpoison" [1].
I'm thinking of updating patch 2/6 [2] to remove this if-block.

  [1]: https://lore.kernel.org/linux-mm/20210614021212.223326-2-nao.horiguchi@gmail.com/
  [2]: https://lore.kernel.org/linux-mm/20210614021212.223326-3-nao.horiguchi@gmail.com/

# .. so you don't have to care for the detail of this part.

> 
> > >  
> > >  	return 0;
> > >  }
> > > diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> > > index f7ca1a3870ea..1d5bada80aa5 100644
> > > --- a/include/linux/hugetlb.h
> > > +++ b/include/linux/hugetlb.h
> > > @@ -171,6 +171,7 @@ void putback_active_hugepage(struct page *page);
> > >  void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
> > >  void free_huge_page(struct page *page);
> > >  void hugetlb_fix_reserve_counts(struct inode *inode);
> > > +void hugetlb_fix_hwcrp_counts(struct page *page);
> > >  extern struct mutex *hugetlb_fault_mutex_table;
> > >  u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx);
> > >  
> > > @@ -602,12 +603,14 @@ struct hstate {
> > >  	unsigned long free_huge_pages;
> > >  	unsigned long resv_huge_pages;
> > >  	unsigned long surplus_huge_pages;
> > > +	unsigned long hwcrp_huge_pages;
> > >  	unsigned long nr_overcommit_huge_pages;
> > >  	struct list_head hugepage_activelist;
> > >  	struct list_head hugepage_freelists[MAX_NUMNODES];
> > >  	unsigned int nr_huge_pages_node[MAX_NUMNODES];
> > >  	unsigned int free_huge_pages_node[MAX_NUMNODES];
> > >  	unsigned int surplus_huge_pages_node[MAX_NUMNODES];
> > > +	unsigned int hwcrp_huge_pages_node[MAX_NUMNODES];
> > 
> > I understand your requirement to count the number of memory errors on
> > hugetlb pages.  However, we need to think carefully about we represent
> > that count.
> > 
> > Noaya, do you have opinions on where would be the best place to store
> > this information?  The hugetlb memory error code has the comment 'needs
> > work'.  Ideally, we could isolate memory errors to a single base (4K for
> > x86) page and free the remaining base pages to buddy.  We could also
> > potentially allocate a 'replacement' hugetlb page doing something like
> > alloc_and_dissolve_huge_page.

Yes, these two are the important goals of hugetlb support.

> > 
> > If we get an error on a hugetlb page and can isolate it to a base page
> > and replace the huge page, is it still a huge page memory error?

That's not counted as a huge page error, but just a base page error.

> > 
> > IMO, we should work on isolating memory errors to a base page and
> > replacing the huge page.  Then, the existing count of base pages with
> > memory errors would be sufficient?

Yes, I agree with Mike.  Adding new fields dedicated to the (maybe temporary)
counters in struct hstate seems to me an overkill.

> > 
> > This is something I would like to work, but I have higher priorities
> > right now.
> 
> Yes, splitting the huge pages and isolating a base page is ideal. And
> we do this with dissolve_free_huge_page() when page_mapping() return
> NULL. I think there is a reason(but I do not get it) why we don't split
> huge pags in hugetlbfs_error_remove_page() or after. So I choose to 
> add a new count.

Maybe the resource is the main reason of this incompleteness, I noticed this
for years and continued to say "this is in my todo list", but still don't
make it (really sorry about that...).  Anyway, if you can (I hope) solve
your problem with "/proc/kpageflag" approach, which is a recommended solution.

Thanks,
Naoya Horiguchi
Bin Wang July 11, 2021, 2:20 p.m. UTC | #4
Hi Naoya,

> > Yes, splitting the huge pages and isolating a base page is ideal. And
> > we do this with dissolve_free_huge_page() when page_mapping() return
> > NULL. I think there is a reason(but I do not get it) why we don't split
> > huge pags in hugetlbfs_error_remove_page() or after. So I choose to 
> > add a new count.
> 
> Maybe the resource is the main reason of this incompleteness, I noticed this
> for years and continued to say "this is in my todo list", but still don't
> make it (really sorry about that...).  Anyway, if you can (I hope) solve
> your problem with "/proc/kpageflag" approach, which is a recommended solution.

I do not understand the exact meaning of the "resource". I have tried to call
dissolve_free_huge_page() after hugetlbfs_error_remove_page() and it worked.
In my opinion, the error huge page has been truncated from the hugetlbfs. It
cannot be accessed and allocated again. I think it is safe to split it.

I would appreciate it if you could point out what I overlooked. And I will
try to solve it.

Thanks,
Bin Wang
diff mbox series

Patch

diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 926eeb9bf4eb..ffb6e7b6756b 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -986,8 +986,7 @@  static int hugetlbfs_error_remove_page(struct address_space *mapping,
 	pgoff_t index = page->index;
 
 	remove_huge_page(page);
-	if (unlikely(hugetlb_unreserve_pages(inode, index, index + 1, 1)))
-		hugetlb_fix_reserve_counts(inode);
+	hugetlb_fix_hwcrp_counts(page);
 
 	return 0;
 }
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index f7ca1a3870ea..1d5bada80aa5 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -171,6 +171,7 @@  void putback_active_hugepage(struct page *page);
 void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
 void free_huge_page(struct page *page);
 void hugetlb_fix_reserve_counts(struct inode *inode);
+void hugetlb_fix_hwcrp_counts(struct page *page);
 extern struct mutex *hugetlb_fault_mutex_table;
 u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx);
 
@@ -602,12 +603,14 @@  struct hstate {
 	unsigned long free_huge_pages;
 	unsigned long resv_huge_pages;
 	unsigned long surplus_huge_pages;
+	unsigned long hwcrp_huge_pages;
 	unsigned long nr_overcommit_huge_pages;
 	struct list_head hugepage_activelist;
 	struct list_head hugepage_freelists[MAX_NUMNODES];
 	unsigned int nr_huge_pages_node[MAX_NUMNODES];
 	unsigned int free_huge_pages_node[MAX_NUMNODES];
 	unsigned int surplus_huge_pages_node[MAX_NUMNODES];
+	unsigned int hwcrp_huge_pages_node[MAX_NUMNODES];
 #ifdef CONFIG_HUGETLB_PAGE_FREE_VMEMMAP
 	unsigned int nr_free_vmemmap_pages;
 #endif
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 760b5fb836b8..3e6385381db7 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -763,6 +763,15 @@  void hugetlb_fix_reserve_counts(struct inode *inode)
 		pr_warn("hugetlb: Huge Page Reserved count may go negative.\n");
 }
 
+void hugetlb_fix_hwcrp_counts(struct page *page)
+{
+	struct hstate *h = &default_hstate;
+	int nid = page_to_nid(page);
+
+	h->hwcrp_huge_pages++;
+	h->hwcrp_huge_pages_node[nid]++;
+}
+
 /*
  * Count and return the number of huge pages in the reserve map
  * that intersect with the range [f, t).
@@ -3293,12 +3302,30 @@  static ssize_t surplus_hugepages_show(struct kobject *kobj,
 }
 HSTATE_ATTR_RO(surplus_hugepages);
 
+static ssize_t hwcrp_hugepages_show(struct kobject *kobj,
+					struct kobj_attribute *attr, char *buf)
+{
+	struct hstate *h;
+	unsigned long hwcrp_huge_pages;
+	int nid;
+
+	h = kobj_to_hstate(kobj, &nid);
+	if (nid == NUMA_NO_NODE)
+		hwcrp_huge_pages = h->hwcrp_huge_pages;
+	else
+		hwcrp_huge_pages = h->hwcrp_huge_pages_node[nid];
+
+	return sysfs_emit(buf, "%lu\n", hwcrp_huge_pages);
+}
+HSTATE_ATTR_RO(hwcrp_hugepages);
+
 static struct attribute *hstate_attrs[] = {
 	&nr_hugepages_attr.attr,
 	&nr_overcommit_hugepages_attr.attr,
 	&free_hugepages_attr.attr,
 	&resv_hugepages_attr.attr,
 	&surplus_hugepages_attr.attr,
+	&hwcrp_hugepages_attr.attr,
 #ifdef CONFIG_NUMA
 	&nr_hugepages_mempolicy_attr.attr,
 #endif
@@ -3368,6 +3395,7 @@  static struct attribute *per_node_hstate_attrs[] = {
 	&nr_hugepages_attr.attr,
 	&free_hugepages_attr.attr,
 	&surplus_hugepages_attr.attr,
+	&hwcrp_hugepages_attr.attr,
 	NULL,
 };
 
@@ -3862,11 +3890,13 @@  void hugetlb_report_meminfo(struct seq_file *m)
 				   "HugePages_Free:    %5lu\n"
 				   "HugePages_Rsvd:    %5lu\n"
 				   "HugePages_Surp:    %5lu\n"
+				   "HugePages_Hwcrp:   %5lu\n"
 				   "Hugepagesize:   %8lu kB\n",
 				   count,
 				   h->free_huge_pages,
 				   h->resv_huge_pages,
 				   h->surplus_huge_pages,
+				   h->hwcrp_huge_pages,
 				   huge_page_size(h) / SZ_1K);
 	}