All of lore.kernel.org
 help / color / mirror / Atom feed
From: ak@linux.intel.com
To: speck@linutronix.de
Cc: Andi Kleen <ak@linux.intel.com>
Subject: [MODERATED] [PATCH v4 7/8] L1TFv4 2
Date: Wed,  9 May 2018 14:25:52 -0700	[thread overview]
Message-ID: <b31f6dd0e2447e3cbc0959209a946a5224d10499.1525900921.git.ak@linux.intel.com> (raw)
In-Reply-To: <cover.1525900921.git.ak@linux.intel.com>
In-Reply-To: <cover.1525900921.git.ak@linux.intel.com>

For the L1TF workaround we want to limit the swap file size to below
MAX_PA/2, so that the higher bits of the swap offset inverted never
point to valid memory.

Add a way for the architecture to override the swap file
size check in swapfile.c and add a x86 specific max swapfile check
function that enforces that limit.

The check is only enabled if the CPU is vulnerable to L1TF.

In VMs with 42bit MAX_PA the typical limit is 2TB now,
on a native system with 46bit PA it is 32TB. The limit
is only per individual swap file, so it's always possible
to exceed these limits with multiple swap files or
partitions.

v2: Use new helper for maxpa_mask computation.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 arch/x86/include/asm/processor.h |  5 +++++
 arch/x86/mm/init.c               | 15 ++++++++++++++
 include/linux/swapfile.h         |  2 ++
 mm/swapfile.c                    | 44 +++++++++++++++++++++++++---------------
 4 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 21a114914ba4..2bd676e450cf 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -181,6 +181,11 @@ extern const struct seq_operations cpuinfo_op;
 
 extern void cpu_detect(struct cpuinfo_x86 *c);
 
+static inline u64 maxpa_pfn_bit(int offset)
+{
+	return BIT_ULL(boot_cpu_data.x86_phys_bits - offset - PAGE_SHIFT);
+}
+
 extern void early_cpu_init(void);
 extern void identify_boot_cpu(void);
 extern void identify_secondary_cpu(struct cpuinfo_x86 *);
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index fec82b577c18..b4078eb05ca0 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -4,6 +4,8 @@
 #include <linux/swap.h>
 #include <linux/memblock.h>
 #include <linux/bootmem.h>	/* for max_low_pfn */
+#include <linux/swapfile.h>
+#include <linux/swapops.h>
 
 #include <asm/set_memory.h>
 #include <asm/e820/api.h>
@@ -878,3 +880,16 @@ void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache)
 	__cachemode2pte_tbl[cache] = __cm_idx2pte(entry);
 	__pte2cachemode_tbl[entry] = cache;
 }
+
+unsigned long max_swapfile_size(void)
+{
+	unsigned long pages;
+
+	pages = generic_max_swapfile_size();
+
+	if (boot_cpu_has(X86_BUG_L1TF)) {
+		/* Limit the swap file size to MAX_PA/2 for L1TF workaround */
+		pages = min_t(unsigned long, maxpa_pfn_bit(1), pages);
+	}
+	return pages;
+}
diff --git a/include/linux/swapfile.h b/include/linux/swapfile.h
index 06bd7b096167..e06febf62978 100644
--- a/include/linux/swapfile.h
+++ b/include/linux/swapfile.h
@@ -10,5 +10,7 @@ extern spinlock_t swap_lock;
 extern struct plist_head swap_active_head;
 extern struct swap_info_struct *swap_info[];
 extern int try_to_unuse(unsigned int, bool, unsigned long);
+extern unsigned long generic_max_swapfile_size(void);
+extern unsigned long max_swapfile_size(void);
 
 #endif /* _LINUX_SWAPFILE_H */
diff --git a/mm/swapfile.c b/mm/swapfile.c
index cc2cf04d9018..413f48424194 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2909,6 +2909,33 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
 	return 0;
 }
 
+
+/*
+ * Find out how many pages are allowed for a single swap
+ * device. There are two limiting factors: 1) the number
+ * of bits for the swap offset in the swp_entry_t type, and
+ * 2) the number of bits in the swap pte as defined by the
+ * different architectures. In order to find the
+ * largest possible bit mask, a swap entry with swap type 0
+ * and swap offset ~0UL is created, encoded to a swap pte,
+ * decoded to a swp_entry_t again, and finally the swap
+ * offset is extracted. This will mask all the bits from
+ * the initial ~0UL mask that can't be encoded in either
+ * the swp_entry_t or the architecture definition of a
+ * swap pte.
+ */
+unsigned long generic_max_swapfile_size(void)
+{
+	return swp_offset(pte_to_swp_entry(
+			swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1;
+}
+
+/* Can be overridden by an architecture for additional checks. */
+__weak unsigned long max_swapfile_size(void)
+{
+	return generic_max_swapfile_size();
+}
+
 static unsigned long read_swap_header(struct swap_info_struct *p,
 					union swap_header *swap_header,
 					struct inode *inode)
@@ -2944,22 +2971,7 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
 	p->cluster_next = 1;
 	p->cluster_nr = 0;
 
-	/*
-	 * Find out how many pages are allowed for a single swap
-	 * device. There are two limiting factors: 1) the number
-	 * of bits for the swap offset in the swp_entry_t type, and
-	 * 2) the number of bits in the swap pte as defined by the
-	 * different architectures. In order to find the
-	 * largest possible bit mask, a swap entry with swap type 0
-	 * and swap offset ~0UL is created, encoded to a swap pte,
-	 * decoded to a swp_entry_t again, and finally the swap
-	 * offset is extracted. This will mask all the bits from
-	 * the initial ~0UL mask that can't be encoded in either
-	 * the swp_entry_t or the architecture definition of a
-	 * swap pte.
-	 */
-	maxpages = swp_offset(pte_to_swp_entry(
-			swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1;
+	maxpages = max_swapfile_size();
 	last_page = swap_header->info.last_page;
 	if (!last_page) {
 		pr_warn("Empty swap-file\n");
-- 
2.14.3

  parent reply	other threads:[~2018-05-09 21:26 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-09 21:25 [MODERATED] [PATCH v4 0/8] L1TFv4 0 ak
2018-05-09 21:25 ` [MODERATED] [PATCH v4 1/8] L1TFv4 1 ak
2018-05-10 23:00   ` Thomas Gleixner
2018-05-10 23:18     ` [MODERATED] " Andi Kleen
2018-05-09 21:25 ` [MODERATED] [PATCH v4 2/8] L1TFv4 4 ak
2018-05-09 21:25 ` [MODERATED] [PATCH v4 3/8] L1TFv4 6 ak
2018-05-10 23:15   ` Thomas Gleixner
2018-05-10 23:32     ` [MODERATED] " Andi Kleen
2018-05-10 23:41       ` Thomas Gleixner
2018-05-09 21:25 ` [MODERATED] [PATCH v4 4/8] L1TFv4 7 ak
2018-05-09 21:25 ` [MODERATED] [PATCH v4 5/8] L1TFv4 8 ak
2018-05-10 23:27   ` Thomas Gleixner
2018-05-09 21:25 ` [MODERATED] [PATCH v4 6/8] L1TFv4 3 ak
2018-05-10 22:52   ` Thomas Gleixner
2018-05-10 23:26     ` [MODERATED] " Andi Kleen
2018-05-10 23:46       ` Thomas Gleixner
2018-05-09 21:25 ` ak [this message]
2018-05-11  8:23   ` [PATCH v4 7/8] L1TFv4 2 Thomas Gleixner
2018-05-11  8:24   ` Thomas Gleixner
2018-05-09 21:25 ` [MODERATED] [PATCH v4 8/8] L1TFv4 5 ak
2018-05-10  4:13   ` [MODERATED] " Andi Kleen
2018-05-09 21:54 ` [MODERATED] Re: [PATCH v4 0/8] L1TFv4 0 Andi Kleen
2018-05-10  6:47 ` [MODERATED] Re: ***UNCHECKED*** " Vlastimil Babka
2018-05-10  8:04   ` Michal Hocko
2018-05-10 16:07     ` Andi Kleen
2018-05-10 16:57       ` [MODERATED] " Borislav Petkov
2018-05-10 17:35         ` Andi Kleen
2018-05-10 22:11           ` Thomas Gleixner
2018-05-10 22:26             ` [MODERATED] " Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b31f6dd0e2447e3cbc0959209a946a5224d10499.1525900921.git.ak@linux.intel.com \
    --to=ak@linux.intel.com \
    --cc=speck@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.