1) When the Guest sets the new TLS entries, we don't need to re-verify
the whole GDT.
2) We also don't need to copy all the GDT entries if only the TLS
entries have changed.
Before:
Time for one context switch via pipe: 5406 (5170 - 7467)
After:
Time for one context switch via pipe: 4916 (4661 - 7004)
Signed-off-by: Rusty Russell <[email protected]>
---
drivers/lguest/core.c | 5 ++++-
drivers/lguest/lg.h | 2 ++
drivers/lguest/segments.c | 30 ++++++++++++++++++------------
3 files changed, 24 insertions(+), 13 deletions(-)
diff -r e5e8dfc0fda2 drivers/lguest/core.c
--- a/drivers/lguest/core.c Thu May 31 17:04:16 2007 +1000
+++ b/drivers/lguest/core.c Thu May 31 17:12:24 2007 +1000
@@ -278,6 +278,9 @@ static void copy_in_guest_info(struct lg
/* Copy all GDT entries but the TSS. */
if (lg->changed & CHANGED_GDT)
copy_gdt(lg, pages->state.guest_gdt);
+ /* If only the TLS entries have changed, copy them. */
+ else if (lg->changed & CHANGED_GDT_TLS)
+ copy_gdt_tls(lg, pages->state.guest_gdt);
lg->changed = 0;
}
diff -r e5e8dfc0fda2 drivers/lguest/lg.h
--- a/drivers/lguest/lg.h Thu May 31 17:04:16 2007 +1000
+++ b/drivers/lguest/lg.h Thu May 31 17:10:20 2007 +1000
@@ -115,6 +115,7 @@ struct lguest_pages
#define CHANGED_IDT 1
#define CHANGED_GDT 2
+#define CHANGED_GDT_TLS 4 /* Actually a subset of CHANGED_GDT */
#define CHANGED_ALL 3
/* The private info the thread maintains about the guest. */
@@ -202,6 +203,7 @@ void load_guest_gdt(struct lguest *lg, u
void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num);
void guest_load_tls(struct lguest *lg, unsigned long tls_array);
void copy_gdt(const struct lguest *lg, struct desc_struct *gdt);
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
/* page_tables.c: */
int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
diff -r e5e8dfc0fda2 drivers/lguest/segments.c
--- a/drivers/lguest/segments.c Thu May 31 17:04:16 2007 +1000
+++ b/drivers/lguest/segments.c Thu May 31 17:11:46 2007 +1000
@@ -34,11 +34,11 @@ static void check_segment_use(struct lgu
kill_guest(lg, "Removed live GDT entry %u", desc);
}
-static void fixup_gdt_table(struct lguest *lg)
+static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(lg->gdt); i++) {
+ for (i = start; i < end; i++) {
/* We never copy these ones to real gdt */
if (ignored_gdt(i))
continue;
@@ -86,6 +86,16 @@ void setup_guest_gdt(struct lguest *lg)
lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
}
+/* This is a fast version for the common case where only the three TLS entries
+ * have changed. */
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
+{
+ unsigned int i;
+
+ for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
+ gdt[i] = lg->gdt[i];
+}
+
void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
{
unsigned int i;
@@ -101,7 +111,7 @@ void load_guest_gdt(struct lguest *lg, u
kill_guest(lg, "too many gdt entries %i", num);
lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
- fixup_gdt_table(lg);
+ fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
lg->changed |= CHANGED_GDT;
}
@@ -110,6 +120,6 @@ void guest_load_tls(struct lguest *lg, u
struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
- fixup_gdt_table(lg);
- lg->changed |= CHANGED_GDT;
+ fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+ lg->changed |= CHANGED_GDT_TLS;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]