nfsd4: don't sleep in lease-break callback
[safe/jmp/linux-2.6] / drivers / xen / balloon.c
index a0fb5ea..f6738d8 100644 (file)
 #include <linux/list.h>
 #include <linux/sysdev.h>
 
-#include <asm/xen/hypervisor.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
 
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/xen.h>
+#include <xen/interface/xen.h>
 #include <xen/interface/memory.h>
 #include <xen/xenbus.h>
 #include <xen/features.h>
@@ -64,8 +68,6 @@ struct balloon_stats {
        /* We aim for 'current allocation' == 'target allocation'. */
        unsigned long current_pages;
        unsigned long target_pages;
-       /* We may hit the hard limit in Xen. If we do then we remember it. */
-       unsigned long hard_limit;
        /*
         * Drivers may alter the memory reservation independently, but they
         * must inform the balloon driver so we avoid hitting the hard limit.
@@ -94,11 +96,7 @@ static struct balloon_stats balloon_stats;
 /* We increase/decrease in batches which fit in a page */
 static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
 
-/* VM /proc information for memory */
-extern unsigned long totalram_pages;
-
 #ifdef CONFIG_HIGHMEM
-extern unsigned long totalhigh_pages;
 #define inc_totalhigh_pages() (totalhigh_pages++)
 #define dec_totalhigh_pages() (totalhigh_pages--)
 #else
@@ -122,14 +120,7 @@ static struct timer_list balloon_timer;
 static void scrub_page(struct page *page)
 {
 #ifdef CONFIG_XEN_SCRUB_PAGES
-       if (PageHighMem(page)) {
-               void *v = kmap(page);
-               clear_page(v);
-               kunmap(v);
-       } else {
-               void *v = page_address(page);
-               clear_page(v);
-       }
+       clear_highpage(page);
 #endif
 }
 
@@ -145,6 +136,8 @@ static void balloon_append(struct page *page)
                list_add(&page->lru, &ballooned_pages);
                balloon_stats.balloon_low++;
        }
+
+       totalram_pages--;
 }
 
 /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
@@ -165,6 +158,8 @@ static struct page *balloon_retrieve(void)
        else
                balloon_stats.balloon_low--;
 
+       totalram_pages++;
+
        return page;
 }
 
@@ -190,7 +185,7 @@ static void balloon_alarm(unsigned long unused)
 
 static unsigned long current_target(void)
 {
-       unsigned long target = min(balloon_stats.target_pages, balloon_stats.hard_limit);
+       unsigned long target = balloon_stats.target_pages;
 
        target = min(target,
                     balloon_stats.current_pages +
@@ -219,30 +214,17 @@ static int increase_reservation(unsigned long nr_pages)
        page = balloon_first_page();
        for (i = 0; i < nr_pages; i++) {
                BUG_ON(page == NULL);
-               frame_list[i] = page_to_pfn(page);;
+               frame_list[i] = page_to_pfn(page);
                page = balloon_next_page(page);
        }
 
        set_xen_guest_handle(reservation.extent_start, frame_list);
        reservation.nr_extents = nr_pages;
        rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
-       if (rc < nr_pages) {
-               if (rc > 0) {
-                       int ret;
-
-                       /* We hit the Xen hard limit: reprobe. */
-                       reservation.nr_extents = rc;
-                       ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-                                                  &reservation);
-                       BUG_ON(ret != rc);
-               }
-               if (rc >= 0)
-                       balloon_stats.hard_limit = (balloon_stats.current_pages + rc -
-                                                   balloon_stats.driver_pages);
+       if (rc < 0)
                goto out;
-       }
 
-       for (i = 0; i < nr_pages; i++) {
+       for (i = 0; i < rc; i++) {
                page = balloon_retrieve();
                BUG_ON(page == NULL);
 
@@ -268,13 +250,12 @@ static int increase_reservation(unsigned long nr_pages)
                __free_page(page);
        }
 
-       balloon_stats.current_pages += nr_pages;
-       totalram_pages = balloon_stats.current_pages;
+       balloon_stats.current_pages += rc;
 
  out:
        spin_unlock_irqrestore(&balloon_lock, flags);
 
-       return 0;
+       return rc < 0 ? rc : rc != nr_pages;
 }
 
 static int decrease_reservation(unsigned long nr_pages)
@@ -303,6 +284,14 @@ static int decrease_reservation(unsigned long nr_pages)
                frame_list[i] = pfn_to_mfn(pfn);
 
                scrub_page(page);
+
+               if (!PageHighMem(page)) {
+                       ret = HYPERVISOR_update_va_mapping(
+                               (unsigned long)__va(pfn << PAGE_SHIFT),
+                               __pte_ma(0), 0);
+                       BUG_ON(ret);
+                }
+
        }
 
        /* Ensure that ballooned highmem pages don't have kmaps. */
@@ -324,7 +313,6 @@ static int decrease_reservation(unsigned long nr_pages)
        BUG_ON(ret != nr_pages);
 
        balloon_stats.current_pages -= nr_pages;
-       totalram_pages = balloon_stats.current_pages;
 
        spin_unlock_irqrestore(&balloon_lock, flags);
 
@@ -368,7 +356,6 @@ static void balloon_process(struct work_struct *work)
 static void balloon_set_new_target(unsigned long target)
 {
        /* No need for lock. Not read-modify-write updates. */
-       balloon_stats.hard_limit   = ~0UL;
        balloon_stats.target_pages = target;
        schedule_work(&balloon_worker);
 }
@@ -423,12 +410,10 @@ static int __init balloon_init(void)
        pr_info("xen_balloon: Initialising balloon driver.\n");
 
        balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn);
-       totalram_pages   = balloon_stats.current_pages;
        balloon_stats.target_pages  = balloon_stats.current_pages;
        balloon_stats.balloon_low   = 0;
        balloon_stats.balloon_high  = 0;
        balloon_stats.driver_pages  = 0UL;
-       balloon_stats.hard_limit    = ~0UL;
 
        init_timer(&balloon_timer);
        balloon_timer.data = 0;
@@ -473,9 +458,6 @@ module_exit(balloon_exit);
 BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
 BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
 BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
-BALLOON_SHOW(hard_limit_kb,
-            (balloon_stats.hard_limit!=~0UL) ? "%lu\n" : "???\n",
-            (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
 BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
 
 static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
@@ -495,7 +477,7 @@ static ssize_t store_target_kb(struct sys_device *dev,
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       target_bytes = memparse(buf, &endchar);
+       target_bytes = simple_strtoull(buf, &endchar, 0) * 1024;
 
        balloon_set_new_target(target_bytes >> PAGE_SHIFT);
 
@@ -505,15 +487,46 @@ static ssize_t store_target_kb(struct sys_device *dev,
 static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
                   show_target_kb, store_target_kb);
 
+
+static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr,
+                             char *buf)
+{
+       return sprintf(buf, "%llu\n",
+                      (unsigned long long)balloon_stats.target_pages
+                      << PAGE_SHIFT);
+}
+
+static ssize_t store_target(struct sys_device *dev,
+                           struct sysdev_attribute *attr,
+                           const char *buf,
+                           size_t count)
+{
+       char *endchar;
+       unsigned long long target_bytes;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       target_bytes = memparse(buf, &endchar);
+
+       balloon_set_new_target(target_bytes >> PAGE_SHIFT);
+
+       return count;
+}
+
+static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR,
+                  show_target, store_target);
+
+
 static struct sysdev_attribute *balloon_attrs[] = {
        &attr_target_kb,
+       &attr_target,
 };
 
 static struct attribute *balloon_info_attrs[] = {
        &attr_current_kb.attr,
        &attr_low_kb.attr,
        &attr_high_kb.attr,
-       &attr_hard_limit_kb.attr,
        &attr_driver_kb.attr,
        NULL
 };