Skip to content

Commit 212fcf3

Browse files
jgunthorpejoergroedel
authored andcommitted
iommu/pages: Move from struct page to struct ioptdesc and folio
This brings the iommu page table allocator into the modern world of having its own private page descriptor and not re-using fields from struct page for its own purpose. It follows the basic pattern of struct ptdesc which did this transformation for the CPU page table allocator. Currently iommu-pages is pretty basic so this isn't a huge benefit, however I see a coming need for features that CPU allocator has, like sub PAGE_SIZE allocations, and RCU freeing. This provides the base infrastructure to implement those cleanly. Remove numa_node_id() calls from the inlines and instead use NUMA_NO_NODE which will get switched to numa_mem_id(), which seems to be the right ID to use for memory allocations. Reviewed-by: Lu Baolu <[email protected]> Tested-by: Nicolin Chen <[email protected]> Tested-by: Alejandro Jimenez <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 27bc9f7 commit 212fcf3

File tree

2 files changed

+78
-19
lines changed

2 files changed

+78
-19
lines changed

drivers/iommu/iommu-pages.c

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@
77
#include <linux/gfp.h>
88
#include <linux/mm.h>
99

10+
#define IOPTDESC_MATCH(pg_elm, elm) \
11+
static_assert(offsetof(struct page, pg_elm) == \
12+
offsetof(struct ioptdesc, elm))
13+
IOPTDESC_MATCH(flags, __page_flags);
14+
IOPTDESC_MATCH(lru, iopt_freelist_elm); /* Ensure bit 0 is clear */
15+
IOPTDESC_MATCH(mapping, __page_mapping);
16+
IOPTDESC_MATCH(private, _private);
17+
IOPTDESC_MATCH(page_type, __page_type);
18+
IOPTDESC_MATCH(_refcount, __page_refcount);
19+
#ifdef CONFIG_MEMCG
20+
IOPTDESC_MATCH(memcg_data, memcg_data);
21+
#endif
22+
#undef IOPTDESC_MATCH
23+
static_assert(sizeof(struct ioptdesc) <= sizeof(struct page));
24+
1025
/**
1126
* iommu_alloc_pages_node - Allocate a zeroed page of a given order from
1227
* specific NUMA node
@@ -20,10 +35,17 @@
2035
void *iommu_alloc_pages_node(int nid, gfp_t gfp, unsigned int order)
2136
{
2237
const unsigned long pgcnt = 1UL << order;
23-
struct page *page;
38+
struct folio *folio;
2439

25-
page = alloc_pages_node(nid, gfp | __GFP_ZERO | __GFP_COMP, order);
26-
if (unlikely(!page))
40+
/*
41+
* __folio_alloc_node() does not handle NUMA_NO_NODE like
42+
* alloc_pages_node() did.
43+
*/
44+
if (nid == NUMA_NO_NODE)
45+
nid = numa_mem_id();
46+
47+
folio = __folio_alloc_node(gfp | __GFP_ZERO, order, nid);
48+
if (unlikely(!folio))
2749
return NULL;
2850

2951
/*
@@ -35,21 +57,21 @@ void *iommu_alloc_pages_node(int nid, gfp_t gfp, unsigned int order)
3557
* This is necessary for the proper accounting as IOMMU state can be
3658
* rather large, i.e. multiple gigabytes in size.
3759
*/
38-
mod_node_page_state(page_pgdat(page), NR_IOMMU_PAGES, pgcnt);
39-
mod_lruvec_page_state(page, NR_SECONDARY_PAGETABLE, pgcnt);
60+
mod_node_page_state(folio_pgdat(folio), NR_IOMMU_PAGES, pgcnt);
61+
lruvec_stat_mod_folio(folio, NR_SECONDARY_PAGETABLE, pgcnt);
4062

41-
return page_address(page);
63+
return folio_address(folio);
4264
}
4365
EXPORT_SYMBOL_GPL(iommu_alloc_pages_node);
4466

45-
static void __iommu_free_page(struct page *page)
67+
static void __iommu_free_desc(struct ioptdesc *iopt)
4668
{
47-
unsigned int order = folio_order(page_folio(page));
48-
const unsigned long pgcnt = 1UL << order;
69+
struct folio *folio = ioptdesc_folio(iopt);
70+
const unsigned long pgcnt = 1UL << folio_order(folio);
4971

50-
mod_node_page_state(page_pgdat(page), NR_IOMMU_PAGES, -pgcnt);
51-
mod_lruvec_page_state(page, NR_SECONDARY_PAGETABLE, -pgcnt);
52-
put_page(page);
72+
mod_node_page_state(folio_pgdat(folio), NR_IOMMU_PAGES, -pgcnt);
73+
lruvec_stat_mod_folio(folio, NR_SECONDARY_PAGETABLE, -pgcnt);
74+
folio_put(folio);
5375
}
5476

5577
/**
@@ -62,7 +84,7 @@ void iommu_free_pages(void *virt)
6284
{
6385
if (!virt)
6486
return;
65-
__iommu_free_page(virt_to_page(virt));
87+
__iommu_free_desc(virt_to_ioptdesc(virt));
6688
}
6789
EXPORT_SYMBOL_GPL(iommu_free_pages);
6890

@@ -74,9 +96,9 @@ EXPORT_SYMBOL_GPL(iommu_free_pages);
7496
*/
7597
void iommu_put_pages_list(struct iommu_pages_list *list)
7698
{
77-
struct page *p, *tmp;
99+
struct ioptdesc *iopt, *tmp;
78100

79-
list_for_each_entry_safe(p, tmp, &list->pages, lru)
80-
__iommu_free_page(p);
101+
list_for_each_entry_safe(iopt, tmp, &list->pages, iopt_freelist_elm)
102+
__iommu_free_desc(iopt);
81103
}
82104
EXPORT_SYMBOL_GPL(iommu_put_pages_list);

drivers/iommu/iommu-pages.h

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,43 @@
99

1010
#include <linux/iommu.h>
1111

12+
/**
13+
* struct ioptdesc - Memory descriptor for IOMMU page tables
14+
* @iopt_freelist_elm: List element for a struct iommu_pages_list
15+
*
16+
* This struct overlays struct page for now. Do not modify without a good
17+
* understanding of the issues.
18+
*/
19+
struct ioptdesc {
20+
unsigned long __page_flags;
21+
22+
struct list_head iopt_freelist_elm;
23+
unsigned long __page_mapping;
24+
pgoff_t __index;
25+
void *_private;
26+
27+
unsigned int __page_type;
28+
atomic_t __page_refcount;
29+
#ifdef CONFIG_MEMCG
30+
unsigned long memcg_data;
31+
#endif
32+
};
33+
34+
static inline struct ioptdesc *folio_ioptdesc(struct folio *folio)
35+
{
36+
return (struct ioptdesc *)folio;
37+
}
38+
39+
static inline struct folio *ioptdesc_folio(struct ioptdesc *iopt)
40+
{
41+
return (struct folio *)iopt;
42+
}
43+
44+
static inline struct ioptdesc *virt_to_ioptdesc(void *virt)
45+
{
46+
return folio_ioptdesc(virt_to_folio(virt));
47+
}
48+
1249
void *iommu_alloc_pages_node(int nid, gfp_t gfp, unsigned int order);
1350
void iommu_free_pages(void *virt);
1451
void iommu_put_pages_list(struct iommu_pages_list *list);
@@ -21,7 +58,7 @@ void iommu_put_pages_list(struct iommu_pages_list *list);
2158
static inline void iommu_pages_list_add(struct iommu_pages_list *list,
2259
void *virt)
2360
{
24-
list_add_tail(&virt_to_page(virt)->lru, &list->pages);
61+
list_add_tail(&virt_to_ioptdesc(virt)->iopt_freelist_elm, &list->pages);
2562
}
2663

2764
/**
@@ -56,7 +93,7 @@ static inline bool iommu_pages_list_empty(struct iommu_pages_list *list)
5693
*/
5794
static inline void *iommu_alloc_pages(gfp_t gfp, int order)
5895
{
59-
return iommu_alloc_pages_node(numa_node_id(), gfp, order);
96+
return iommu_alloc_pages_node(NUMA_NO_NODE, gfp, order);
6097
}
6198

6299
/**
@@ -79,7 +116,7 @@ static inline void *iommu_alloc_page_node(int nid, gfp_t gfp)
79116
*/
80117
static inline void *iommu_alloc_page(gfp_t gfp)
81118
{
82-
return iommu_alloc_pages_node(numa_node_id(), gfp, 0);
119+
return iommu_alloc_pages_node(NUMA_NO_NODE, gfp, 0);
83120
}
84121

85122
#endif /* __IOMMU_PAGES_H */

0 commit comments

Comments
 (0)