debuggers.hg

view linux-2.6.10-rc2-xen-sparse/drivers/xen/balloon/balloon.c @ 3289:a169836882cb

bitkeeper revision 1.1159.170.59 (41b4c2fdJ2gj_BWy27Vj3ptayZp_yg)

sync w/ head.
author cl349@arcadians.cl.cam.ac.uk
date Mon Dec 06 20:37:17 2004 +0000 (2004-12-06)
parents 13728122c78d
children
line source
1 /******************************************************************************
2 * balloon.c
3 *
4 * Xen balloon driver - enables returning/claiming memory to/from Xen.
5 *
6 * Copyright (c) 2003, B Dragovic
7 * Copyright (c) 2003-2004, M Williamson, K Fraser
8 *
9 * This file may be distributed separately from the Linux kernel, or
10 * incorporated into other software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
31 #include <linux/config.h>
32 #include <linux/kernel.h>
33 #include <linux/module.h>
34 #include <linux/sched.h>
35 #include <linux/errno.h>
36 #include <linux/mm.h>
37 #include <linux/mman.h>
38 #include <linux/smp_lock.h>
39 #include <linux/pagemap.h>
40 #include <linux/bootmem.h>
41 #include <linux/highmem.h>
42 #include <linux/vmalloc.h>
43 #include <asm-xen/xen_proc.h>
44 #include <asm-xen/hypervisor.h>
45 #include <asm-xen/ctrl_if.h>
46 #include <asm-xen/balloon.h>
47 #include <asm/pgalloc.h>
48 #include <asm/pgtable.h>
49 #include <asm/uaccess.h>
50 #include <asm/tlb.h>
51 #include <linux/list.h>
53 static struct proc_dir_entry *balloon_pde;
55 static DECLARE_MUTEX(balloon_mutex);
56 spinlock_t balloon_lock = SPIN_LOCK_UNLOCKED;
58 /* We aim for 'current allocation' == 'target allocation'. */
59 static unsigned long current_pages;
60 static unsigned long target_pages;
62 /* We may hit the hard limit in Xen. If we do then we remember it. */
63 static unsigned long hard_limit;
65 /*
66 * Drivers may alter the memory reservation independently, but they must
67 * inform the balloon driver so that we can avoid hitting the hard limit.
68 */
69 static unsigned long driver_pages;
71 /* List of ballooned pages, threaded through the mem_map array. */
72 static LIST_HEAD(ballooned_pages);
73 static unsigned long balloon_low, balloon_high;
75 /* Main work function, always executed in process context. */
76 static void balloon_process(void *unused);
77 static DECLARE_WORK(balloon_worker, balloon_process, NULL);
78 static struct timer_list balloon_timer;
80 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
81 /* Use the private and mapping fields of struct page as a list. */
82 #define PAGE_TO_LIST(p) ( (struct list_head *)&p->private )
83 #define LIST_TO_PAGE(l) ( list_entry( ((unsigned long *)l), \
84 struct page, private ) )
85 #define UNLIST_PAGE(p) do { list_del(PAGE_TO_LIST(p)); \
86 p->mapping = NULL; \
87 p->private = 0; } while(0)
88 #else
89 /* There's a dedicated list field in struct page we can use. */
90 #define PAGE_TO_LIST(p) ( &p->list )
91 #define LIST_TO_PAGE(l) ( list_entry(l, struct page, list) )
92 #define UNLIST_PAGE(p) ( list_del(&p->list) )
93 #define pte_offset_kernel pte_offset
94 #define subsys_initcall(_fn) __initcall(_fn)
95 #endif
97 #define IPRINTK(fmt, args...) \
98 printk(KERN_INFO "xen_mem: " fmt, ##args)
99 #define WPRINTK(fmt, args...) \
100 printk(KERN_WARNING "xen_mem: " fmt, ##args)
102 /* balloon_append: add the given page to the balloon. */
103 static void balloon_append(struct page *page)
104 {
105 /* Low memory is re-populated first, so highmem pages go at list tail. */
106 if ( PageHighMem(page) )
107 {
108 list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
109 balloon_high++;
110 }
111 else
112 {
113 list_add(PAGE_TO_LIST(page), &ballooned_pages);
114 balloon_low++;
115 }
116 }
118 /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
119 static struct page *balloon_retrieve(void)
120 {
121 struct page *page;
123 if ( list_empty(&ballooned_pages) )
124 return NULL;
126 page = LIST_TO_PAGE(ballooned_pages.next);
127 UNLIST_PAGE(page);
129 if ( PageHighMem(page) )
130 balloon_high--;
131 else
132 balloon_low--;
134 return page;
135 }
137 static inline pte_t *get_ptep(unsigned long addr)
138 {
139 pgd_t *pgd;
140 pmd_t *pmd;
142 pgd = pgd_offset_k(addr);
143 if ( pgd_none(*pgd) || pgd_bad(*pgd) ) BUG();
145 pmd = pmd_offset(pgd, addr);
146 if ( pmd_none(*pmd) || pmd_bad(*pmd) ) BUG();
148 return pte_offset_kernel(pmd, addr);
149 }
151 static void balloon_alarm(unsigned long unused)
152 {
153 schedule_work(&balloon_worker);
154 }
156 static unsigned long current_target(void)
157 {
158 unsigned long target = min(target_pages, hard_limit);
159 if ( target > (current_pages + balloon_low + balloon_high) )
160 target = current_pages + balloon_low + balloon_high;
161 return target;
162 }
164 /*
165 * We avoid multiple worker processes conflicting via the balloon mutex.
166 * We may of course race updates of the target counts (which are protected
167 * by the balloon lock), or with changes to the Xen hard limit, but we will
168 * recover from these in time.
169 */
170 static void balloon_process(void *unused)
171 {
172 unsigned long *mfn_list, pfn, i, flags;
173 struct page *page;
174 long credit, debt, rc;
175 void *v;
177 down(&balloon_mutex);
179 retry:
180 mfn_list = NULL;
182 if ( (credit = current_target() - current_pages) > 0 )
183 {
184 mfn_list = (unsigned long *)vmalloc(credit * sizeof(*mfn_list));
185 if ( mfn_list == NULL )
186 goto out;
188 balloon_lock(flags);
189 rc = HYPERVISOR_dom_mem_op(
190 MEMOP_increase_reservation, mfn_list, credit, 0);
191 balloon_unlock(flags);
192 if ( rc < credit )
193 {
194 /* We hit the Xen hard limit: reprobe. */
195 if ( HYPERVISOR_dom_mem_op(
196 MEMOP_decrease_reservation, mfn_list, rc, 0) != rc )
197 BUG();
198 hard_limit = current_pages + rc - driver_pages;
199 vfree(mfn_list);
200 goto retry;
201 }
203 for ( i = 0; i < credit; i++ )
204 {
205 if ( (page = balloon_retrieve()) == NULL )
206 BUG();
208 pfn = page - mem_map;
209 if ( phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY )
210 BUG();
212 /* Update P->M and M->P tables. */
213 phys_to_machine_mapping[pfn] = mfn_list[i];
214 queue_machphys_update(mfn_list[i], pfn);
216 /* Link back into the page tables if it's not a highmem page. */
217 if ( pfn < max_low_pfn )
218 queue_l1_entry_update(
219 get_ptep((unsigned long)__va(pfn << PAGE_SHIFT)),
220 (mfn_list[i] << PAGE_SHIFT) | pgprot_val(PAGE_KERNEL));
222 /* Finally, relinquish the memory back to the system allocator. */
223 ClearPageReserved(page);
224 set_page_count(page, 1);
225 __free_page(page);
226 }
228 current_pages += credit;
229 }
230 else if ( credit < 0 )
231 {
232 debt = -credit;
234 mfn_list = (unsigned long *)vmalloc(debt * sizeof(*mfn_list));
235 if ( mfn_list == NULL )
236 goto out;
238 for ( i = 0; i < debt; i++ )
239 {
240 if ( (page = alloc_page(GFP_HIGHUSER)) == NULL )
241 {
242 debt = i;
243 break;
244 }
246 pfn = page - mem_map;
247 mfn_list[i] = phys_to_machine_mapping[pfn];
248 phys_to_machine_mapping[pfn] = INVALID_P2M_ENTRY;
250 if ( !PageHighMem(page) )
251 {
252 v = phys_to_virt((page - mem_map) << PAGE_SHIFT);
253 scrub_pages(v, 1);
254 queue_l1_entry_update(get_ptep((unsigned long)v), 0);
255 }
256 #ifdef CONFIG_XEN_SCRUB_PAGES
257 else
258 {
259 v = kmap(page);
260 scrub_pages(v, 1);
261 kunmap(page);
262 }
263 #endif
265 balloon_append(page);
266 }
268 /* Flush updates through and flush the TLB. */
269 xen_tlb_flush();
271 if ( HYPERVISOR_dom_mem_op(
272 MEMOP_decrease_reservation, mfn_list, debt, 0) != debt )
273 BUG();
275 current_pages -= debt;
276 }
278 out:
279 if ( mfn_list != NULL )
280 vfree(mfn_list);
282 /* Schedule more work if there is some still to be done. */
283 if ( current_target() != current_pages )
284 mod_timer(&balloon_timer, jiffies + HZ);
286 up(&balloon_mutex);
287 }
289 /* Resets the Xen limit, sets new target, and kicks off processing. */
290 static void set_new_target(unsigned long target)
291 {
292 /* No need for lock. Not read-modify-write updates. */
293 hard_limit = ~0UL;
294 target_pages = target;
295 schedule_work(&balloon_worker);
296 }
298 static void balloon_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
299 {
300 switch ( msg->subtype )
301 {
302 case CMSG_MEM_REQUEST_SET:
303 {
304 mem_request_t *req = (mem_request_t *)&msg->msg[0];
305 if ( msg->length != sizeof(mem_request_t) )
306 goto parse_error;
307 set_new_target(req->target);
308 req->status = 0;
309 }
310 break;
311 default:
312 goto parse_error;
313 }
315 ctrl_if_send_response(msg);
316 return;
318 parse_error:
319 msg->length = 0;
320 ctrl_if_send_response(msg);
321 }
323 static int balloon_write(struct file *file, const char __user *buffer,
324 unsigned long count, void *data)
325 {
326 char memstring[64], *endchar;
327 unsigned long long target_bytes;
329 if ( !capable(CAP_SYS_ADMIN) )
330 return -EPERM;
332 if ( count <= 1 )
333 return -EBADMSG; /* runt */
334 if ( count > sizeof(memstring) )
335 return -EFBIG; /* too long */
337 if ( copy_from_user(memstring, buffer, count) )
338 return -EFAULT;
339 memstring[sizeof(memstring)-1] = '\0';
341 target_bytes = memparse(memstring, &endchar);
342 set_new_target(target_bytes >> PAGE_SHIFT);
344 return count;
345 }
347 static int balloon_read(char *page, char **start, off_t off,
348 int count, int *eof, void *data)
349 {
350 int len;
352 #define K(_p) ((_p)<<(PAGE_SHIFT-10))
353 len = sprintf(
354 page,
355 "Current allocation: %8lu kB\n"
356 "Requested target: %8lu kB\n"
357 "Low-mem balloon: %8lu kB\n"
358 "High-mem balloon: %8lu kB\n"
359 "Xen hard limit: ",
360 K(current_pages), K(target_pages), K(balloon_low), K(balloon_high));
362 if ( hard_limit != ~0UL )
363 len += sprintf(
364 page + len,
365 "%8lu kB (inc. %8lu kB driver headroom)\n",
366 K(hard_limit), K(driver_pages));
367 else
368 len += sprintf(
369 page + len,
370 " ??? kB\n");
372 *eof = 1;
373 return len;
374 }
376 static int __init balloon_init(void)
377 {
378 unsigned long pfn;
379 struct page *page;
381 IPRINTK("Initialising balloon driver.\n");
383 current_pages = min(xen_start_info.nr_pages, max_pfn);
384 target_pages = current_pages;
385 balloon_low = 0;
386 balloon_high = 0;
387 driver_pages = 0UL;
388 hard_limit = ~0UL;
390 init_timer(&balloon_timer);
391 balloon_timer.data = 0;
392 balloon_timer.function = balloon_alarm;
394 if ( (balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL )
395 {
396 WPRINTK("Unable to create /proc/xen/balloon.\n");
397 return -1;
398 }
400 balloon_pde->read_proc = balloon_read;
401 balloon_pde->write_proc = balloon_write;
403 (void)ctrl_if_register_receiver(CMSG_MEM_REQUEST, balloon_ctrlif_rx, 0);
405 /* Initialise the balloon with excess memory space. */
406 for ( pfn = xen_start_info.nr_pages; pfn < max_pfn; pfn++ )
407 {
408 page = &mem_map[pfn];
409 if ( !PageReserved(page) )
410 balloon_append(page);
411 }
413 return 0;
414 }
416 subsys_initcall(balloon_init);
418 void balloon_update_driver_allowance(long delta)
419 {
420 unsigned long flags;
421 balloon_lock(flags);
422 driver_pages += delta; /* non-atomic update */
423 balloon_unlock(flags);
424 }
426 void balloon_put_pages(unsigned long *mfn_list, unsigned long nr_mfns)
427 {
428 unsigned long flags;
430 balloon_lock(flags);
431 if ( HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
432 mfn_list, nr_mfns, 0) != nr_mfns )
433 BUG();
434 current_pages -= nr_mfns; /* non-atomic update */
435 balloon_unlock(flags);
437 schedule_work(&balloon_worker);
438 }
440 EXPORT_SYMBOL(balloon_update_driver_allowance);
441 EXPORT_SYMBOL(balloon_put_pages);