Merge branches 'stable/bug.fixes-3.2' and 'stable/mmu.fixes' of git://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."
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
@@ -432,7 +432,8 @@ static int __must_check xen_allocate_irq_dynamic(void)
|
||||
|
||||
irq = irq_alloc_desc_from(first, -1);
|
||||
|
||||
xen_irq_init(irq);
|
||||
if (irq >= 0)
|
||||
xen_irq_init(irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
@@ -713,7 +714,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
|
||||
mutex_lock(&irq_mapping_update_lock);
|
||||
|
||||
irq = xen_allocate_irq_dynamic();
|
||||
if (irq == -1)
|
||||
if (irq < 0)
|
||||
goto out;
|
||||
|
||||
irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
|
||||
@@ -729,7 +730,7 @@ out:
|
||||
error_irq:
|
||||
mutex_unlock(&irq_mapping_update_lock);
|
||||
xen_free_irq(irq);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -779,7 +780,7 @@ int xen_irq_from_pirq(unsigned pirq)
|
||||
mutex_lock(&irq_mapping_update_lock);
|
||||
|
||||
list_for_each_entry(info, &xen_irq_list_head, list) {
|
||||
if (info == NULL || info->type != IRQT_PIRQ)
|
||||
if (info->type != IRQT_PIRQ)
|
||||
continue;
|
||||
irq = info->irq;
|
||||
if (info->u.pirq.pirq == pirq)
|
||||
@@ -1670,6 +1671,7 @@ void __init xen_init_IRQ(void)
|
||||
|
||||
evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
|
||||
GFP_KERNEL);
|
||||
BUG_ON(!evtchn_to_irq);
|
||||
for (i = 0; i < NR_EVENT_CHANNELS; i++)
|
||||
evtchn_to_irq[i] = -1;
|
||||
|
||||
|
@@ -83,6 +83,7 @@ struct grant_map {
|
||||
struct ioctl_gntdev_grant_ref *grants;
|
||||
struct gnttab_map_grant_ref *map_ops;
|
||||
struct gnttab_unmap_grant_ref *unmap_ops;
|
||||
struct gnttab_map_grant_ref *kmap_ops;
|
||||
struct page **pages;
|
||||
};
|
||||
|
||||
@@ -116,19 +117,22 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
|
||||
add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL);
|
||||
add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL);
|
||||
add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL);
|
||||
add->kmap_ops = kzalloc(sizeof(add->kmap_ops[0]) * count, GFP_KERNEL);
|
||||
add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL);
|
||||
if (NULL == add->grants ||
|
||||
NULL == add->map_ops ||
|
||||
NULL == add->unmap_ops ||
|
||||
NULL == add->kmap_ops ||
|
||||
NULL == add->pages)
|
||||
goto err;
|
||||
|
||||
if (alloc_xenballooned_pages(count, add->pages))
|
||||
if (alloc_xenballooned_pages(count, add->pages, false /* lowmem */))
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
add->map_ops[i].handle = -1;
|
||||
add->unmap_ops[i].handle = -1;
|
||||
add->kmap_ops[i].handle = -1;
|
||||
}
|
||||
|
||||
add->index = 0;
|
||||
@@ -142,6 +146,7 @@ err:
|
||||
kfree(add->grants);
|
||||
kfree(add->map_ops);
|
||||
kfree(add->unmap_ops);
|
||||
kfree(add->kmap_ops);
|
||||
kfree(add);
|
||||
return NULL;
|
||||
}
|
||||
@@ -243,10 +248,35 @@ static int map_grant_pages(struct grant_map *map)
|
||||
gnttab_set_unmap_op(&map->unmap_ops[i], addr,
|
||||
map->flags, -1 /* handle */);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Setup the map_ops corresponding to the pte entries pointing
|
||||
* to the kernel linear addresses of the struct pages.
|
||||
* These ptes are completely different from the user ptes dealt
|
||||
* with find_grant_ptes.
|
||||
*/
|
||||
for (i = 0; i < map->count; i++) {
|
||||
unsigned level;
|
||||
unsigned long address = (unsigned long)
|
||||
pfn_to_kaddr(page_to_pfn(map->pages[i]));
|
||||
pte_t *ptep;
|
||||
u64 pte_maddr = 0;
|
||||
BUG_ON(PageHighMem(map->pages[i]));
|
||||
|
||||
ptep = lookup_address(address, &level);
|
||||
pte_maddr = arbitrary_virt_to_machine(ptep).maddr;
|
||||
gnttab_set_map_op(&map->kmap_ops[i], pte_maddr,
|
||||
map->flags |
|
||||
GNTMAP_host_map |
|
||||
GNTMAP_contains_pte,
|
||||
map->grants[i].ref,
|
||||
map->grants[i].domid);
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("map %d+%d\n", map->index, map->count);
|
||||
err = gnttab_map_refs(map->map_ops, map->pages, map->count);
|
||||
err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL,
|
||||
map->pages, map->count);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -462,13 +492,11 @@ static int gntdev_release(struct inode *inode, struct file *flip)
|
||||
|
||||
pr_debug("priv %p\n", priv);
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
while (!list_empty(&priv->maps)) {
|
||||
map = list_entry(priv->maps.next, struct grant_map, next);
|
||||
list_del(&map->next);
|
||||
gntdev_put_map(map);
|
||||
}
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
if (use_ptemod)
|
||||
mmu_notifier_unregister(&priv->mn, priv->mm);
|
||||
@@ -532,10 +560,11 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
|
||||
map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
|
||||
if (map) {
|
||||
list_del(&map->next);
|
||||
gntdev_put_map(map);
|
||||
err = 0;
|
||||
}
|
||||
spin_unlock(&priv->lock);
|
||||
if (map)
|
||||
gntdev_put_map(map);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@@ -448,7 +448,8 @@ unsigned int gnttab_max_grant_frames(void)
|
||||
EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
|
||||
|
||||
int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
|
||||
struct page **pages, unsigned int count)
|
||||
struct gnttab_map_grant_ref *kmap_ops,
|
||||
struct page **pages, unsigned int count)
|
||||
{
|
||||
int i, ret;
|
||||
pte_t *pte;
|
||||
@@ -488,8 +489,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
ret = m2p_add_override(mfn, pages[i],
|
||||
map_ops[i].flags & GNTMAP_contains_pte);
|
||||
ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@@ -68,6 +68,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/module.h>
|
||||
@@ -93,6 +95,15 @@ static unsigned int selfballoon_uphysteresis __read_mostly = 1;
|
||||
/* In HZ, controls frequency of worker invocation. */
|
||||
static unsigned int selfballoon_interval __read_mostly = 5;
|
||||
|
||||
/*
|
||||
* Minimum usable RAM in MB for selfballooning target for balloon.
|
||||
* If non-zero, it is added to totalreserve_pages and self-ballooning
|
||||
* will not balloon below the sum. If zero, a piecewise linear function
|
||||
* is calculated as a minimum and added to totalreserve_pages. Note that
|
||||
* setting this value indiscriminately may cause OOMs and crashes.
|
||||
*/
|
||||
static unsigned int selfballoon_min_usable_mb;
|
||||
|
||||
static void selfballoon_process(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
|
||||
|
||||
@@ -189,20 +200,23 @@ static int __init xen_selfballooning_setup(char *s)
|
||||
__setup("selfballooning", xen_selfballooning_setup);
|
||||
#endif /* CONFIG_FRONTSWAP */
|
||||
|
||||
#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
|
||||
|
||||
/*
|
||||
* Use current balloon size, the goal (vm_committed_as), and hysteresis
|
||||
* parameters to set a new target balloon size
|
||||
*/
|
||||
static void selfballoon_process(struct work_struct *work)
|
||||
{
|
||||
unsigned long cur_pages, goal_pages, tgt_pages;
|
||||
unsigned long cur_pages, goal_pages, tgt_pages, floor_pages;
|
||||
unsigned long useful_pages;
|
||||
bool reset_timer = false;
|
||||
|
||||
if (xen_selfballooning_enabled) {
|
||||
cur_pages = balloon_stats.current_pages;
|
||||
cur_pages = totalram_pages;
|
||||
tgt_pages = cur_pages; /* default is no change */
|
||||
goal_pages = percpu_counter_read_positive(&vm_committed_as) +
|
||||
balloon_stats.current_pages - totalram_pages;
|
||||
totalreserve_pages;
|
||||
#ifdef CONFIG_FRONTSWAP
|
||||
/* allow space for frontswap pages to be repatriated */
|
||||
if (frontswap_selfshrinking && frontswap_enabled)
|
||||
@@ -217,7 +231,26 @@ static void selfballoon_process(struct work_struct *work)
|
||||
((goal_pages - cur_pages) /
|
||||
selfballoon_uphysteresis);
|
||||
/* else if cur_pages == goal_pages, no change */
|
||||
balloon_set_new_target(tgt_pages);
|
||||
useful_pages = max_pfn - totalreserve_pages;
|
||||
if (selfballoon_min_usable_mb != 0)
|
||||
floor_pages = totalreserve_pages +
|
||||
MB2PAGES(selfballoon_min_usable_mb);
|
||||
/* piecewise linear function ending in ~3% slope */
|
||||
else if (useful_pages < MB2PAGES(16))
|
||||
floor_pages = max_pfn; /* not worth ballooning */
|
||||
else if (useful_pages < MB2PAGES(64))
|
||||
floor_pages = totalreserve_pages + MB2PAGES(16) +
|
||||
((useful_pages - MB2PAGES(16)) >> 1);
|
||||
else if (useful_pages < MB2PAGES(512))
|
||||
floor_pages = totalreserve_pages + MB2PAGES(40) +
|
||||
((useful_pages - MB2PAGES(40)) >> 3);
|
||||
else /* useful_pages >= MB2PAGES(512) */
|
||||
floor_pages = totalreserve_pages + MB2PAGES(99) +
|
||||
((useful_pages - MB2PAGES(99)) >> 5);
|
||||
if (tgt_pages < floor_pages)
|
||||
tgt_pages = floor_pages;
|
||||
balloon_set_new_target(tgt_pages +
|
||||
balloon_stats.current_pages - totalram_pages);
|
||||
reset_timer = true;
|
||||
}
|
||||
#ifdef CONFIG_FRONTSWAP
|
||||
@@ -340,6 +373,31 @@ static ssize_t store_selfballoon_uphys(struct sys_device *dev,
|
||||
static SYSDEV_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR,
|
||||
show_selfballoon_uphys, store_selfballoon_uphys);
|
||||
|
||||
SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n",
|
||||
selfballoon_min_usable_mb);
|
||||
|
||||
static ssize_t store_selfballoon_min_usable_mb(struct sys_device *dev,
|
||||
struct sysdev_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
err = strict_strtoul(buf, 10, &val);
|
||||
if (err || val == 0)
|
||||
return -EINVAL;
|
||||
selfballoon_min_usable_mb = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
static SYSDEV_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR,
|
||||
show_selfballoon_min_usable_mb,
|
||||
store_selfballoon_min_usable_mb);
|
||||
|
||||
|
||||
#ifdef CONFIG_FRONTSWAP
|
||||
SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking);
|
||||
|
||||
@@ -421,6 +479,7 @@ static struct attribute *selfballoon_attrs[] = {
|
||||
&attr_selfballoon_interval.attr,
|
||||
&attr_selfballoon_downhysteresis.attr,
|
||||
&attr_selfballoon_uphysteresis.attr,
|
||||
&attr_selfballoon_min_usable_mb.attr,
|
||||
#ifdef CONFIG_FRONTSWAP
|
||||
&attr_frontswap_selfshrinking.attr,
|
||||
&attr_frontswap_hysteresis.attr,
|
||||
|
@@ -104,8 +104,6 @@ static int xenbus_uevent_backend(struct device *dev,
|
||||
|
||||
xdev = to_xenbus_device(dev);
|
||||
bus = container_of(xdev->dev.bus, struct xen_bus_type, bus);
|
||||
if (xdev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (add_uevent_var(env, "MODALIAS=xen-backend:%s", xdev->devicetype))
|
||||
return -ENOMEM;
|
||||
|
Reference in New Issue
Block a user