Skip to content

Commit

Permalink
Merge branches 'stable/bug.fixes-3.2' and 'stable/mmu.fixes' of git:/…
Browse files Browse the repository at this point in the history
…/git.kernel.org/pub/scm/linux/kernel/git/konrad/xen

* 'stable/bug.fixes-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/p2m/debugfs: Make type_name more obvious.
  xen/p2m/debugfs: Fix potential pointer exception.
  xen/enlighten: Fix compile warnings and set cx to known value.
  xen/xenbus: Remove the unnecessary check.
  xen/irq: If we fail during msi_capability_init return proper error code.
  xen/events: Don't check the info for NULL as it is already done.
  xen/events: BUG() when we can't allocate our event->irq array.

* 'stable/mmu.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen: Fix selfballooning and ensure it doesn't go too far
  xen/gntdev: Fix sleep-inside-spinlock
  xen: modify kernel mappings corresponding to granted pages
  xen: add an "highmem" parameter to alloc_xenballooned_pages
  xen/p2m: Use SetPagePrivate and its friends for M2P overrides.
  xen/p2m: Make debug/xen/mmu/p2m visible again.
  Revert "xen/debug: WARN_ON when identity PFN has no _PAGE_IOMAP flag set."
  • Loading branch information
Linus Torvalds committed Oct 25, 2011
3 parents 5eef150 + a491dbe + 38a1ed4 commit 31018ac
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 111 deletions.
6 changes: 2 additions & 4 deletions arch/x86/include/asm/xen/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <asm/pgtable.h>

#include <xen/interface/xen.h>
#include <xen/grant_table.h>
#include <xen/features.h>

/* Xen machine address */
Expand Down Expand Up @@ -48,14 +49,11 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s,
unsigned long pfn_e);

extern int m2p_add_override(unsigned long mfn, struct page *page,
bool clear_pte);
struct gnttab_map_grant_ref *kmap_op);
extern int m2p_remove_override(struct page *page, bool clear_pte);
extern struct page *m2p_find_override(unsigned long mfn);
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);

#ifdef CONFIG_XEN_DEBUG_FS
extern int p2m_dump_show(struct seq_file *m, void *v);
#endif
static inline unsigned long pfn_to_mfn(unsigned long pfn)
{
unsigned long mfn;
Expand Down
10 changes: 7 additions & 3 deletions arch/x86/pci/xen.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
"pcifront-msi-x" :
"pcifront-msi",
DOMID_SELF);
if (irq < 0)
if (irq < 0) {
ret = irq;
goto free;
}
i++;
}
kfree(v);
Expand Down Expand Up @@ -221,8 +223,10 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (msg.data != XEN_PIRQ_MSI_DATA ||
xen_irq_from_pirq(pirq) < 0) {
pirq = xen_allocate_pirq_msi(dev, msidesc);
if (pirq < 0)
if (pirq < 0) {
irq = -ENODEV;
goto error;
}
xen_msi_compose_msg(dev, pirq, &msg);
__write_msi_msg(msidesc, &msg);
dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
Expand All @@ -244,7 +248,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
error:
dev_err(&dev->dev,
"Xen PCI frontend has not registered MSI/MSI-X support!\n");
return -ENODEV;
return irq;
}

#ifdef CONFIG_XEN_DOM0
Expand Down
8 changes: 0 additions & 8 deletions arch/x86/xen/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,3 @@ config XEN_DEBUG_FS
help
Enable statistics output and various tuning options in debugfs.
Enabling this option may incur a significant performance overhead.

config XEN_DEBUG
bool "Enable Xen debug checks"
depends on XEN
default n
help
Enable various WARN_ON checks in the Xen MMU code.
Enabling this option WILL incur a significant performance overhead.
1 change: 1 addition & 0 deletions arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ static void __init xen_init_cpuid_mask(void)
~((1 << X86_FEATURE_APIC) | /* disable local APIC */
(1 << X86_FEATURE_ACPI)); /* disable ACPI */
ax = 1;
cx = 0;
xen_cpuid(&ax, &bx, &cx, &dx);

xsave_mask =
Expand Down
52 changes: 0 additions & 52 deletions arch/x86/xen/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,41 +495,6 @@ static pte_t xen_make_pte(pteval_t pte)
}
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);

#ifdef CONFIG_XEN_DEBUG
pte_t xen_make_pte_debug(pteval_t pte)
{
phys_addr_t addr = (pte & PTE_PFN_MASK);
phys_addr_t other_addr;
bool io_page = false;
pte_t _pte;

if (pte & _PAGE_IOMAP)
io_page = true;

_pte = xen_make_pte(pte);

if (!addr)
return _pte;

if (io_page &&
(xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
WARN_ONCE(addr != other_addr,
"0x%lx is using VM_IO, but it is 0x%lx!\n",
(unsigned long)addr, (unsigned long)other_addr);
} else {
pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
other_addr = (_pte.pte & PTE_PFN_MASK);
WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set),
"0x%lx is missing VM_IO (and wasn't fixed)!\n",
(unsigned long)addr);
}

return _pte;
}
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
#endif

static pgd_t xen_make_pgd(pgdval_t pgd)
{
pgd = pte_pfn_to_mfn(pgd);
Expand Down Expand Up @@ -1992,9 +1957,6 @@ void __init xen_ident_map_ISA(void)

static void __init xen_post_allocator_init(void)
{
#ifdef CONFIG_XEN_DEBUG
pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
#endif
pv_mmu_ops.set_pte = xen_set_pte;
pv_mmu_ops.set_pmd = xen_set_pmd;
pv_mmu_ops.set_pud = xen_set_pud;
Expand Down Expand Up @@ -2404,17 +2366,3 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
return err;
}
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);

#ifdef CONFIG_XEN_DEBUG_FS
static int p2m_dump_open(struct inode *inode, struct file *filp)
{
return single_open(filp, p2m_dump_show, NULL);
}

static const struct file_operations p2m_dump_fops = {
.open = p2m_dump_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif /* CONFIG_XEN_DEBUG_FS */
128 changes: 109 additions & 19 deletions arch/x86/xen/p2m.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@
#include <asm/xen/page.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
#include <xen/grant_table.h>

#include "multicalls.h"
#include "xen-ops.h"

static void __init m2p_override_init(void);
Expand Down Expand Up @@ -676,7 +678,8 @@ static unsigned long mfn_hash(unsigned long mfn)
}

/* Add an MFN override for a particular page */
int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
int m2p_add_override(unsigned long mfn, struct page *page,
struct gnttab_map_grant_ref *kmap_op)
{
unsigned long flags;
unsigned long pfn;
Expand All @@ -692,16 +695,28 @@ int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
"m2p_add_override: pfn %lx not mapped", pfn))
return -EINVAL;
}

page->private = mfn;
WARN_ON(PagePrivate(page));
SetPagePrivate(page);
set_page_private(page, mfn);
page->index = pfn_to_mfn(pfn);

if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
return -ENOMEM;

if (clear_pte && !PageHighMem(page))
/* Just zap old mapping for now */
pte_clear(&init_mm, address, ptep);
if (kmap_op != NULL) {
if (!PageHighMem(page)) {
struct multicall_space mcs =
xen_mc_entry(sizeof(*kmap_op));

MULTI_grant_table_op(mcs.mc,
GNTTABOP_map_grant_ref, kmap_op, 1);

xen_mc_issue(PARAVIRT_LAZY_MMU);
}
/* let's use dev_bus_addr to record the old mfn instead */
kmap_op->dev_bus_addr = page->index;
page->index = (unsigned long) kmap_op;
}
spin_lock_irqsave(&m2p_override_lock, flags);
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
spin_unlock_irqrestore(&m2p_override_lock, flags);
Expand Down Expand Up @@ -735,13 +750,56 @@ int m2p_remove_override(struct page *page, bool clear_pte)
spin_lock_irqsave(&m2p_override_lock, flags);
list_del(&page->lru);
spin_unlock_irqrestore(&m2p_override_lock, flags);
set_phys_to_machine(pfn, page->index);
WARN_ON(!PagePrivate(page));
ClearPagePrivate(page);

if (clear_pte && !PageHighMem(page))
set_pte_at(&init_mm, address, ptep,
pfn_pte(pfn, PAGE_KERNEL));
/* No tlb flush necessary because the caller already
* left the pte unmapped. */
if (clear_pte) {
struct gnttab_map_grant_ref *map_op =
(struct gnttab_map_grant_ref *) page->index;
set_phys_to_machine(pfn, map_op->dev_bus_addr);
if (!PageHighMem(page)) {
struct multicall_space mcs;
struct gnttab_unmap_grant_ref *unmap_op;

/*
* It might be that we queued all the m2p grant table
* hypercalls in a multicall, then m2p_remove_override
* get called before the multicall has actually been
* issued. In this case handle is going to -1 because
* it hasn't been modified yet.
*/
if (map_op->handle == -1)
xen_mc_flush();
/*
* Now if map_op->handle is negative it means that the
* hypercall actually returned an error.
*/
if (map_op->handle == GNTST_general_error) {
printk(KERN_WARNING "m2p_remove_override: "
"pfn %lx mfn %lx, failed to modify kernel mappings",
pfn, mfn);
return -1;
}

mcs = xen_mc_entry(
sizeof(struct gnttab_unmap_grant_ref));
unmap_op = mcs.args;
unmap_op->host_addr = map_op->host_addr;
unmap_op->handle = map_op->handle;
unmap_op->dev_bus_addr = 0;

MULTI_grant_table_op(mcs.mc,
GNTTABOP_unmap_grant_ref, unmap_op, 1);

xen_mc_issue(PARAVIRT_LAZY_MMU);

set_pte_at(&init_mm, address, ptep,
pfn_pte(pfn, PAGE_KERNEL));
__flush_tlb_single(address);
map_op->host_addr = 0;
}
} else
set_phys_to_machine(pfn, page->index);

return 0;
}
Expand All @@ -758,7 +816,7 @@ struct page *m2p_find_override(unsigned long mfn)
spin_lock_irqsave(&m2p_override_lock, flags);

list_for_each_entry(p, bucket, lru) {
if (p->private == mfn) {
if (page_private(p) == mfn) {
ret = p;
break;
}
Expand All @@ -782,17 +840,21 @@ unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn)
EXPORT_SYMBOL_GPL(m2p_find_override_pfn);

#ifdef CONFIG_XEN_DEBUG_FS

int p2m_dump_show(struct seq_file *m, void *v)
#include <linux/debugfs.h>
#include "debugfs.h"
static int p2m_dump_show(struct seq_file *m, void *v)
{
static const char * const level_name[] = { "top", "middle",
"entry", "abnormal" };
static const char * const type_name[] = { "identity", "missing",
"pfn", "abnormal"};
"entry", "abnormal", "error"};
#define TYPE_IDENTITY 0
#define TYPE_MISSING 1
#define TYPE_PFN 2
#define TYPE_UNKNOWN 3
static const char * const type_name[] = {
[TYPE_IDENTITY] = "identity",
[TYPE_MISSING] = "missing",
[TYPE_PFN] = "pfn",
[TYPE_UNKNOWN] = "abnormal"};
unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0;
unsigned int uninitialized_var(prev_level);
unsigned int uninitialized_var(prev_type);
Expand Down Expand Up @@ -856,4 +918,32 @@ int p2m_dump_show(struct seq_file *m, void *v)
#undef TYPE_PFN
#undef TYPE_UNKNOWN
}
#endif

static int p2m_dump_open(struct inode *inode, struct file *filp)
{
return single_open(filp, p2m_dump_show, NULL);
}

static const struct file_operations p2m_dump_fops = {
.open = p2m_dump_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

static struct dentry *d_mmu_debug;

static int __init xen_p2m_debugfs(void)
{
struct dentry *d_xen = xen_init_debugfs();

if (d_xen == NULL)
return -ENOMEM;

d_mmu_debug = debugfs_create_dir("mmu", d_xen);

debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
return 0;
}
fs_initcall(xen_p2m_debugfs);
#endif /* CONFIG_XEN_DEBUG_FS */
2 changes: 1 addition & 1 deletion drivers/block/xen-blkback/blkback.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ static int xen_blkbk_map(struct blkif_request *req,
continue;

ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr),
blkbk->pending_page(pending_req, i), false);
blkbk->pending_page(pending_req, i), NULL);
if (ret) {
pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n",
(unsigned long)map[i].dev_bus_addr, ret);
Expand Down
12 changes: 8 additions & 4 deletions drivers/xen/balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,20 +501,24 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target);
* alloc_xenballooned_pages - get pages that have been ballooned out
* @nr_pages: Number of pages to get
* @pages: pages returned
* @highmem: highmem or lowmem pages
* @return 0 on success, error otherwise
*/
int alloc_xenballooned_pages(int nr_pages, struct page** pages)
int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
{
int pgno = 0;
struct page* page;
mutex_lock(&balloon_mutex);
while (pgno < nr_pages) {
page = balloon_retrieve(true);
if (page) {
page = balloon_retrieve(highmem);
if (page && PageHighMem(page) == highmem) {
pages[pgno++] = page;
} else {
enum bp_state st;
st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER);
if (page)
balloon_append(page);
st = decrease_reservation(nr_pages - pgno,
highmem ? GFP_HIGHUSER : GFP_USER);
if (st != BP_DONE)
goto out_undo;
}
Expand Down
Loading

0 comments on commit 31018ac

Please sign in to comment.