diff options
Diffstat (limited to 'system/xen/xsa/xsa299-4.12-0003-x86-mm-Separate-out-partial_pte-tristate-into-indivi.patch')
-rw-r--r-- | system/xen/xsa/xsa299-4.12-0003-x86-mm-Separate-out-partial_pte-tristate-into-indivi.patch | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa299-4.12-0003-x86-mm-Separate-out-partial_pte-tristate-into-indivi.patch b/system/xen/xsa/xsa299-4.12-0003-x86-mm-Separate-out-partial_pte-tristate-into-indivi.patch new file mode 100644 index 0000000000..226e5487b1 --- /dev/null +++ b/system/xen/xsa/xsa299-4.12-0003-x86-mm-Separate-out-partial_pte-tristate-into-indivi.patch @@ -0,0 +1,618 @@ +From 0f9f61e5737fdd346550ec6e30161fa99e4653fa Mon Sep 17 00:00:00 2001 +From: George Dunlap <george.dunlap@citrix.com> +Date: Thu, 10 Oct 2019 17:57:49 +0100 +Subject: [PATCH 03/11] x86/mm: Separate out partial_pte tristate into + individual flags + +At the moment, partial_pte is a tri-state that contains two distinct bits +of information: + +1. If zero, the pte at index [nr_validated_ptes] is un-validated. If + non-zero, the pte was last seen with PGT_partial set. + +2. If positive, the pte at index [nr_validated_ptes] does not hold a + general reference count. If negative, it does. + +To make future patches more clear, separate out this functionality +into two distinct, named bits: PTF_partial_set (for #1) and +PTF_partial_general_ref (for #2). + +Additionally, a number of functions which need this information also +take other flags to control behavior (such as `preemptible` and +`defer`). These are hard to read in the caller (since you only see +'true' or 'false'), and ugly when many are added together. In +preparation for adding yet another flag in a future patch, collapse +all of these into a single `flag` variable. + +NB that this does mean checking for what was previously the '-1' +condition a bit more ugly in the put_page_from_lNe functions (since +you have to check for both partial_set and general ref); but this +clause will go away in a future patch. + +Also note that the original comment had an off-by-one error: +partial_flags (like partial_pte before it) concerns +plNe[nr_validated_ptes], not plNe[nr_validated_ptes+1]. + +No functional change intended. + +This is part of XSA-299. + +Reported-by: George Dunlap <george.dunlap@citrix.com> +Signed-off-by: George Dunlap <george.dunlap@citrix.com> +Reviewed-by: Jan Beulich <jbeulich@suse.com> +--- + xen/arch/x86/mm.c | 165 ++++++++++++++++++++++++--------------- + xen/include/asm-x86/mm.h | 41 +++++++--- + 2 files changed, 128 insertions(+), 78 deletions(-) + +diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c +index a1b55c10ff..3f6f8cc9b8 100644 +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -1094,20 +1094,35 @@ get_page_from_l1e( + } + + #ifdef CONFIG_PV ++ ++/* ++ * The following flags are used to specify behavior of various get and ++ * put commands. The first two are also stored in page->partial_flags ++ * to indicate the state of the page pointed to by ++ * page->pte[page->nr_validated_entries]. See the comment in mm.h for ++ * more information. ++ */ ++#define PTF_partial_set (1 << 0) ++#define PTF_partial_general_ref (1 << 1) ++#define PTF_preemptible (1 << 2) ++#define PTF_defer (1 << 3) ++ + static int get_page_and_type_from_mfn( + mfn_t mfn, unsigned long type, struct domain *d, +- int partial, int preemptible) ++ unsigned int flags) + { + struct page_info *page = mfn_to_page(mfn); + int rc; ++ bool preemptible = flags & PTF_preemptible, ++ partial_ref = flags & PTF_partial_general_ref; + +- if ( likely(partial >= 0) && ++ if ( likely(!partial_ref) && + unlikely(!get_page_from_mfn(mfn, d)) ) + return -EINVAL; + + rc = _get_page_type(page, type, preemptible); + +- if ( unlikely(rc) && partial >= 0 && ++ if ( unlikely(rc) && !partial_ref && + (!preemptible || page != current->arch.old_guest_table) ) + put_page(page); + +@@ -1117,7 +1132,7 @@ static int get_page_and_type_from_mfn( + define_get_linear_pagetable(l2); + static int + get_page_from_l2e( +- l2_pgentry_t l2e, unsigned long pfn, struct domain *d, int partial) ++ l2_pgentry_t l2e, unsigned long pfn, struct domain *d, unsigned int flags) + { + unsigned long mfn = l2e_get_pfn(l2e); + int rc; +@@ -1129,8 +1144,9 @@ get_page_from_l2e( + return -EINVAL; + } + +- rc = get_page_and_type_from_mfn(_mfn(mfn), PGT_l1_page_table, d, +- partial, false); ++ ASSERT(!(flags & PTF_preemptible)); ++ ++ rc = get_page_and_type_from_mfn(_mfn(mfn), PGT_l1_page_table, d, flags); + if ( unlikely(rc == -EINVAL) && get_l2_linear_pagetable(l2e, pfn, d) ) + rc = 0; + +@@ -1140,7 +1156,7 @@ get_page_from_l2e( + define_get_linear_pagetable(l3); + static int + get_page_from_l3e( +- l3_pgentry_t l3e, unsigned long pfn, struct domain *d, int partial) ++ l3_pgentry_t l3e, unsigned long pfn, struct domain *d, unsigned int flags) + { + int rc; + +@@ -1152,7 +1168,7 @@ get_page_from_l3e( + } + + rc = get_page_and_type_from_mfn( +- l3e_get_mfn(l3e), PGT_l2_page_table, d, partial, 1); ++ l3e_get_mfn(l3e), PGT_l2_page_table, d, flags | PTF_preemptible); + if ( unlikely(rc == -EINVAL) && + !is_pv_32bit_domain(d) && + get_l3_linear_pagetable(l3e, pfn, d) ) +@@ -1164,7 +1180,7 @@ get_page_from_l3e( + define_get_linear_pagetable(l4); + static int + get_page_from_l4e( +- l4_pgentry_t l4e, unsigned long pfn, struct domain *d, int partial) ++ l4_pgentry_t l4e, unsigned long pfn, struct domain *d, unsigned int flags) + { + int rc; + +@@ -1176,7 +1192,7 @@ get_page_from_l4e( + } + + rc = get_page_and_type_from_mfn( +- l4e_get_mfn(l4e), PGT_l3_page_table, d, partial, 1); ++ l4e_get_mfn(l4e), PGT_l3_page_table, d, flags | PTF_preemptible); + if ( unlikely(rc == -EINVAL) && get_l4_linear_pagetable(l4e, pfn, d) ) + rc = 0; + +@@ -1277,7 +1293,7 @@ static void put_data_page(struct page_info *page, bool writeable) + * Note also that this automatically deals correctly with linear p.t.'s. + */ + static int put_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn, +- int partial, bool defer) ++ unsigned int flags) + { + int rc = 0; + +@@ -1300,12 +1316,13 @@ static int put_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn, + struct page_info *pg = l2e_get_page(l2e); + struct page_info *ptpg = mfn_to_page(_mfn(pfn)); + +- if ( unlikely(partial > 0) ) ++ if ( (flags & (PTF_partial_set | PTF_partial_general_ref)) == ++ PTF_partial_set ) + { +- ASSERT(!defer); ++ ASSERT(!(flags & PTF_defer)); + rc = _put_page_type(pg, true, ptpg); + } +- else if ( defer ) ++ else if ( flags & PTF_defer ) + { + current->arch.old_guest_ptpg = ptpg; + current->arch.old_guest_table = pg; +@@ -1322,7 +1339,7 @@ static int put_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn, + } + + static int put_page_from_l3e(l3_pgentry_t l3e, unsigned long pfn, +- int partial, bool defer) ++ unsigned int flags) + { + struct page_info *pg; + int rc; +@@ -1345,13 +1362,14 @@ static int put_page_from_l3e(l3_pgentry_t l3e, unsigned long pfn, + + pg = l3e_get_page(l3e); + +- if ( unlikely(partial > 0) ) ++ if ( (flags & (PTF_partial_set | PTF_partial_general_ref)) == ++ PTF_partial_set ) + { +- ASSERT(!defer); ++ ASSERT(!(flags & PTF_defer)); + return _put_page_type(pg, true, mfn_to_page(_mfn(pfn))); + } + +- if ( defer ) ++ if ( flags & PTF_defer ) + { + current->arch.old_guest_ptpg = mfn_to_page(_mfn(pfn)); + current->arch.old_guest_table = pg; +@@ -1366,7 +1384,7 @@ static int put_page_from_l3e(l3_pgentry_t l3e, unsigned long pfn, + } + + static int put_page_from_l4e(l4_pgentry_t l4e, unsigned long pfn, +- int partial, bool defer) ++ unsigned int flags) + { + int rc = 1; + +@@ -1375,13 +1393,14 @@ static int put_page_from_l4e(l4_pgentry_t l4e, unsigned long pfn, + { + struct page_info *pg = l4e_get_page(l4e); + +- if ( unlikely(partial > 0) ) ++ if ( (flags & (PTF_partial_set | PTF_partial_general_ref)) == ++ PTF_partial_set ) + { +- ASSERT(!defer); ++ ASSERT(!(flags & PTF_defer)); + return _put_page_type(pg, true, mfn_to_page(_mfn(pfn))); + } + +- if ( defer ) ++ if ( flags & PTF_defer ) + { + current->arch.old_guest_ptpg = mfn_to_page(_mfn(pfn)); + current->arch.old_guest_table = pg; +@@ -1492,12 +1511,13 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) + unsigned long pfn = mfn_x(page_to_mfn(page)); + l2_pgentry_t *pl2e; + unsigned int i; +- int rc = 0, partial = page->partial_pte; ++ int rc = 0; ++ unsigned int partial_flags = page->partial_flags; + + pl2e = map_domain_page(_mfn(pfn)); + + for ( i = page->nr_validated_ptes; i < L2_PAGETABLE_ENTRIES; +- i++, partial = 0 ) ++ i++, partial_flags = 0 ) + { + l2_pgentry_t l2e; + +@@ -1520,17 +1540,18 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) + rc = -EINTR; + } + else +- rc = get_page_from_l2e(l2e, pfn, d, partial); ++ rc = get_page_from_l2e(l2e, pfn, d, partial_flags); + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; +- page->partial_pte = partial ?: 1; ++ /* Set 'set', retain 'general ref' */ ++ page->partial_flags = partial_flags | PTF_partial_set; + } + else if ( rc == -EINTR && i ) + { + page->nr_validated_ptes = i; +- page->partial_pte = 0; ++ page->partial_flags = 0; + rc = -ERESTART; + } + else if ( rc < 0 && rc != -EINTR ) +@@ -1539,7 +1560,7 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) + if ( i ) + { + page->nr_validated_ptes = i; +- page->partial_pte = 0; ++ page->partial_flags = 0; + current->arch.old_guest_ptpg = NULL; + current->arch.old_guest_table = page; + } +@@ -1563,7 +1584,8 @@ static int alloc_l3_table(struct page_info *page) + unsigned long pfn = mfn_x(page_to_mfn(page)); + l3_pgentry_t *pl3e; + unsigned int i; +- int rc = 0, partial = page->partial_pte; ++ int rc = 0; ++ unsigned int partial_flags = page->partial_flags; + + pl3e = map_domain_page(_mfn(pfn)); + +@@ -1578,7 +1600,7 @@ static int alloc_l3_table(struct page_info *page) + memset(pl3e + 4, 0, (L3_PAGETABLE_ENTRIES - 4) * sizeof(*pl3e)); + + for ( i = page->nr_validated_ptes; i < L3_PAGETABLE_ENTRIES; +- i++, partial = 0 ) ++ i++, partial_flags = 0 ) + { + l3_pgentry_t l3e = pl3e[i]; + +@@ -1597,7 +1619,8 @@ static int alloc_l3_table(struct page_info *page) + else + rc = get_page_and_type_from_mfn( + l3e_get_mfn(l3e), +- PGT_l2_page_table | PGT_pae_xen_l2, d, partial, 1); ++ PGT_l2_page_table | PGT_pae_xen_l2, d, ++ partial_flags | PTF_preemptible); + } + else if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) + { +@@ -1606,17 +1629,18 @@ static int alloc_l3_table(struct page_info *page) + rc = -EINTR; + } + else +- rc = get_page_from_l3e(l3e, pfn, d, partial); ++ rc = get_page_from_l3e(l3e, pfn, d, partial_flags); + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; +- page->partial_pte = partial ?: 1; ++ /* Set 'set', leave 'general ref' set if this entry was set */ ++ page->partial_flags = partial_flags | PTF_partial_set; + } + else if ( rc == -EINTR && i ) + { + page->nr_validated_ptes = i; +- page->partial_pte = 0; ++ page->partial_flags = 0; + rc = -ERESTART; + } + if ( rc < 0 ) +@@ -1633,7 +1657,7 @@ static int alloc_l3_table(struct page_info *page) + if ( i ) + { + page->nr_validated_ptes = i; +- page->partial_pte = 0; ++ page->partial_flags = 0; + current->arch.old_guest_ptpg = NULL; + current->arch.old_guest_table = page; + } +@@ -1767,10 +1791,11 @@ static int alloc_l4_table(struct page_info *page) + unsigned long pfn = mfn_x(page_to_mfn(page)); + l4_pgentry_t *pl4e = map_domain_page(_mfn(pfn)); + unsigned int i; +- int rc = 0, partial = page->partial_pte; ++ int rc = 0; ++ unsigned int partial_flags = page->partial_flags; + + for ( i = page->nr_validated_ptes; i < L4_PAGETABLE_ENTRIES; +- i++, partial = 0 ) ++ i++, partial_flags = 0 ) + { + l4_pgentry_t l4e; + +@@ -1786,12 +1811,13 @@ static int alloc_l4_table(struct page_info *page) + rc = -EINTR; + } + else +- rc = get_page_from_l4e(l4e, pfn, d, partial); ++ rc = get_page_from_l4e(l4e, pfn, d, partial_flags); + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; +- page->partial_pte = partial ?: 1; ++ /* Set 'set', leave 'general ref' set if this entry was set */ ++ page->partial_flags = partial_flags | PTF_partial_set; + } + else if ( rc < 0 ) + { +@@ -1801,7 +1827,7 @@ static int alloc_l4_table(struct page_info *page) + if ( i ) + { + page->nr_validated_ptes = i; +- page->partial_pte = 0; ++ page->partial_flags = 0; + if ( rc == -EINTR ) + rc = -ERESTART; + else +@@ -1853,19 +1879,20 @@ static int free_l2_table(struct page_info *page) + struct domain *d = page_get_owner(page); + unsigned long pfn = mfn_x(page_to_mfn(page)); + l2_pgentry_t *pl2e; +- int rc = 0, partial = page->partial_pte; +- unsigned int i = page->nr_validated_ptes - !partial; ++ int rc = 0; ++ unsigned int partial_flags = page->partial_flags, ++ i = page->nr_validated_ptes - !(partial_flags & PTF_partial_set); + + pl2e = map_domain_page(_mfn(pfn)); + + for ( ; ; ) + { + if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) ) +- rc = put_page_from_l2e(pl2e[i], pfn, partial, false); ++ rc = put_page_from_l2e(pl2e[i], pfn, partial_flags); + if ( rc < 0 ) + break; + +- partial = 0; ++ partial_flags = 0; + + if ( !i-- ) + break; +@@ -1887,12 +1914,14 @@ static int free_l2_table(struct page_info *page) + else if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; +- page->partial_pte = partial ?: -1; ++ page->partial_flags = (partial_flags & PTF_partial_set) ? ++ partial_flags : ++ (PTF_partial_set | PTF_partial_general_ref); + } + else if ( rc == -EINTR && i < L2_PAGETABLE_ENTRIES - 1 ) + { + page->nr_validated_ptes = i + 1; +- page->partial_pte = 0; ++ page->partial_flags = 0; + rc = -ERESTART; + } + +@@ -1904,18 +1933,19 @@ static int free_l3_table(struct page_info *page) + struct domain *d = page_get_owner(page); + unsigned long pfn = mfn_x(page_to_mfn(page)); + l3_pgentry_t *pl3e; +- int rc = 0, partial = page->partial_pte; +- unsigned int i = page->nr_validated_ptes - !partial; ++ int rc = 0; ++ unsigned int partial_flags = page->partial_flags, ++ i = page->nr_validated_ptes - !(partial_flags & PTF_partial_set); + + pl3e = map_domain_page(_mfn(pfn)); + + for ( ; ; ) + { +- rc = put_page_from_l3e(pl3e[i], pfn, partial, 0); ++ rc = put_page_from_l3e(pl3e[i], pfn, partial_flags); + if ( rc < 0 ) + break; + +- partial = 0; ++ partial_flags = 0; + if ( rc == 0 ) + pl3e[i] = unadjust_guest_l3e(pl3e[i], d); + +@@ -1934,12 +1964,14 @@ static int free_l3_table(struct page_info *page) + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; +- page->partial_pte = partial ?: -1; ++ page->partial_flags = (partial_flags & PTF_partial_set) ? ++ partial_flags : ++ (PTF_partial_set | PTF_partial_general_ref); + } + else if ( rc == -EINTR && i < L3_PAGETABLE_ENTRIES - 1 ) + { + page->nr_validated_ptes = i + 1; +- page->partial_pte = 0; ++ page->partial_flags = 0; + rc = -ERESTART; + } + return rc > 0 ? 0 : rc; +@@ -1950,26 +1982,29 @@ static int free_l4_table(struct page_info *page) + struct domain *d = page_get_owner(page); + unsigned long pfn = mfn_x(page_to_mfn(page)); + l4_pgentry_t *pl4e = map_domain_page(_mfn(pfn)); +- int rc = 0, partial = page->partial_pte; +- unsigned int i = page->nr_validated_ptes - !partial; ++ int rc = 0; ++ unsigned partial_flags = page->partial_flags, ++ i = page->nr_validated_ptes - !(partial_flags & PTF_partial_set); + + do { + if ( is_guest_l4_slot(d, i) ) +- rc = put_page_from_l4e(pl4e[i], pfn, partial, 0); ++ rc = put_page_from_l4e(pl4e[i], pfn, partial_flags); + if ( rc < 0 ) + break; +- partial = 0; ++ partial_flags = 0; + } while ( i-- ); + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; +- page->partial_pte = partial ?: -1; ++ page->partial_flags = (partial_flags & PTF_partial_set) ? ++ partial_flags : ++ (PTF_partial_set | PTF_partial_general_ref); + } + else if ( rc == -EINTR && i < L4_PAGETABLE_ENTRIES - 1 ) + { + page->nr_validated_ptes = i + 1; +- page->partial_pte = 0; ++ page->partial_flags = 0; + rc = -ERESTART; + } + +@@ -2247,7 +2282,7 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, + return -EBUSY; + } + +- put_page_from_l2e(ol2e, pfn, 0, true); ++ put_page_from_l2e(ol2e, pfn, PTF_defer); + + return rc; + } +@@ -2315,7 +2350,7 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, + if ( !create_pae_xen_mappings(d, pl3e) ) + BUG(); + +- put_page_from_l3e(ol3e, pfn, 0, 1); ++ put_page_from_l3e(ol3e, pfn, PTF_defer); + return rc; + } + +@@ -2378,7 +2413,7 @@ static int mod_l4_entry(l4_pgentry_t *pl4e, + return -EFAULT; + } + +- put_page_from_l4e(ol4e, pfn, 0, 1); ++ put_page_from_l4e(ol4e, pfn, PTF_defer); + return rc; + } + #endif /* CONFIG_PV */ +@@ -2649,7 +2684,7 @@ int free_page_type(struct page_info *page, unsigned long type, + if ( !(type & PGT_partial) ) + { + page->nr_validated_ptes = 1U << PAGETABLE_ORDER; +- page->partial_pte = 0; ++ page->partial_flags = 0; + } + + switch ( type & PGT_type_mask ) +@@ -2946,7 +2981,7 @@ static int _get_page_type(struct page_info *page, unsigned long type, + if ( !(x & PGT_partial) ) + { + page->nr_validated_ptes = 0; +- page->partial_pte = 0; ++ page->partial_flags = 0; + } + page->linear_pt_count = 0; + rc = alloc_page_type(page, type, preemptible); +@@ -3122,7 +3157,7 @@ int new_guest_cr3(mfn_t mfn) + return 0; + } + +- rc = get_page_and_type_from_mfn(mfn, PGT_root_page_table, d, 0, 1); ++ rc = get_page_and_type_from_mfn(mfn, PGT_root_page_table, d, PTF_preemptible); + switch ( rc ) + { + case 0: +@@ -3473,7 +3508,7 @@ long do_mmuext_op( + if ( op.arg1.mfn != 0 ) + { + rc = get_page_and_type_from_mfn( +- _mfn(op.arg1.mfn), PGT_root_page_table, currd, 0, 1); ++ _mfn(op.arg1.mfn), PGT_root_page_table, currd, PTF_preemptible); + + if ( unlikely(rc) ) + { +diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h +index 6faa563167..8406ac3c37 100644 +--- a/xen/include/asm-x86/mm.h ++++ b/xen/include/asm-x86/mm.h +@@ -228,19 +228,34 @@ struct page_info + * setting the flag must not drop that reference, whereas the instance + * clearing it will have to. + * +- * If @partial_pte is positive then PTE at @nr_validated_ptes+1 has +- * been partially validated. This implies that the general reference +- * to the page (acquired from get_page_from_lNe()) would be dropped +- * (again due to the apparent failure) and hence must be re-acquired +- * when resuming the validation, but must not be dropped when picking +- * up the page for invalidation. ++ * If partial_flags & PTF_partial_set is set, then the page at ++ * at @nr_validated_ptes had PGT_partial set as a result of an ++ * operation on the current page. (That page may or may not ++ * still have PGT_partial set.) + * +- * If @partial_pte is negative then PTE at @nr_validated_ptes+1 has +- * been partially invalidated. This is basically the opposite case of +- * above, i.e. the general reference to the page was not dropped in +- * put_page_from_lNe() (due to the apparent failure), and hence it +- * must be dropped when the put operation is resumed (and completes), +- * but it must not be acquired if picking up the page for validation. ++ * If PTF_partial_general_ref is set, then the PTE at ++ * @nr_validated_ptef holds a general reference count for the ++ * page. ++ * ++ * This happens: ++ * - During de-validation, if de-validation of the page was ++ * interrupted ++ * - During validation, if an invalid entry is encountered and ++ * validation is preemptible ++ * - During validation, if PTF_partial_general_ref was set on ++ * this entry to begin with (perhaps because we're picking ++ * up from a partial de-validation). ++ * ++ * When resuming validation, if PTF_partial_general_ref is clear, ++ * then a general reference must be re-acquired; if it is set, no ++ * reference should be acquired. ++ * ++ * When resuming de-validation, if PTF_partial_general_ref is ++ * clear, no reference should be dropped; if it is set, a ++ * reference should be dropped. ++ * ++ * NB that PTF_partial_set and PTF_partial_general_ref are ++ * defined in mm.c, the only place where they are used. + * + * The 3rd field, @linear_pt_count, indicates + * - by a positive value, how many same-level page table entries a page +@@ -251,7 +266,7 @@ struct page_info + struct { + u16 nr_validated_ptes:PAGETABLE_ORDER + 1; + u16 :16 - PAGETABLE_ORDER - 1 - 2; +- s16 partial_pte:2; ++ u16 partial_flags:2; + s16 linear_pt_count; + }; + +-- +2.23.0 + |