ia64/linux-2.6.18-xen.hg

view arch/sparc/prom/memory.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $
2 * memory.c: Prom routine for acquiring various bits of information
3 * about RAM on the machine, both virtual and physical.
4 *
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6 * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
7 */
9 #include <linux/kernel.h>
10 #include <linux/init.h>
12 #include <asm/openprom.h>
13 #include <asm/sun4prom.h>
14 #include <asm/oplib.h>
16 /* This routine, for consistency, returns the ram parameters in the
17 * V0 prom memory descriptor format. I choose this format because I
18 * think it was the easiest to work with. I feel the religious
19 * arguments now... ;) Also, I return the linked lists sorted to
20 * prevent paging_init() upset stomach as I have not yet written
21 * the pepto-bismol kernel module yet.
22 */
24 struct linux_prom_registers prom_reg_memlist[64];
25 struct linux_prom_registers prom_reg_tmp[64];
27 struct linux_mlist_v0 prom_phys_total[64];
28 struct linux_mlist_v0 prom_prom_taken[64];
29 struct linux_mlist_v0 prom_phys_avail[64];
31 struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total;
32 struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken;
33 struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail;
35 struct linux_mem_v0 prom_memlist;
38 /* Internal Prom library routine to sort a linux_mlist_v0 memory
39 * list. Used below in initialization.
40 */
41 static void __init
42 prom_sortmemlist(struct linux_mlist_v0 *thislist)
43 {
44 int swapi = 0;
45 int i, mitr, tmpsize;
46 char *tmpaddr;
47 char *lowest;
49 for(i=0; thislist[i].theres_more; i++) {
50 lowest = thislist[i].start_adr;
51 for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
52 if(thislist[mitr].start_adr < lowest) {
53 lowest = thislist[mitr].start_adr;
54 swapi = mitr;
55 }
56 if(lowest == thislist[i].start_adr) continue;
57 tmpaddr = thislist[swapi].start_adr;
58 tmpsize = thislist[swapi].num_bytes;
59 for(mitr = swapi; mitr > i; mitr--) {
60 thislist[mitr].start_adr = thislist[mitr-1].start_adr;
61 thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
62 }
63 thislist[i].start_adr = tmpaddr;
64 thislist[i].num_bytes = tmpsize;
65 }
67 return;
68 }
70 /* Initialize the memory lists based upon the prom version. */
71 void __init prom_meminit(void)
72 {
73 int node = 0;
74 unsigned int iter, num_regs;
75 struct linux_mlist_v0 *mptr; /* ptr for traversal */
77 switch(prom_vers) {
78 case PROM_V0:
79 /* Nice, kind of easier to do in this case. */
80 /* First, the total physical descriptors. */
81 for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0;
82 mptr; mptr=mptr->theres_more, iter++) {
83 prom_phys_total[iter].start_adr = mptr->start_adr;
84 prom_phys_total[iter].num_bytes = mptr->num_bytes;
85 prom_phys_total[iter].theres_more = &prom_phys_total[iter+1];
86 }
87 prom_phys_total[iter-1].theres_more = NULL;
88 /* Second, the total prom taken descriptors. */
89 for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0;
90 mptr; mptr=mptr->theres_more, iter++) {
91 prom_prom_taken[iter].start_adr = mptr->start_adr;
92 prom_prom_taken[iter].num_bytes = mptr->num_bytes;
93 prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1];
94 }
95 prom_prom_taken[iter-1].theres_more = NULL;
96 /* Last, the available physical descriptors. */
97 for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0;
98 mptr; mptr=mptr->theres_more, iter++) {
99 prom_phys_avail[iter].start_adr = mptr->start_adr;
100 prom_phys_avail[iter].num_bytes = mptr->num_bytes;
101 prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1];
102 }
103 prom_phys_avail[iter-1].theres_more = NULL;
104 /* Sort all the lists. */
105 prom_sortmemlist(prom_phys_total);
106 prom_sortmemlist(prom_prom_taken);
107 prom_sortmemlist(prom_phys_avail);
108 break;
109 case PROM_V2:
110 case PROM_V3:
111 /* Grrr, have to traverse the prom device tree ;( */
112 node = prom_getchild(prom_root_node);
113 node = prom_searchsiblings(node, "memory");
114 num_regs = prom_getproperty(node, "available",
115 (char *) prom_reg_memlist,
116 sizeof(prom_reg_memlist));
117 num_regs = (num_regs/sizeof(struct linux_prom_registers));
118 for(iter=0; iter<num_regs; iter++) {
119 prom_phys_avail[iter].start_adr =
120 (char *) prom_reg_memlist[iter].phys_addr;
121 prom_phys_avail[iter].num_bytes =
122 (unsigned long) prom_reg_memlist[iter].reg_size;
123 prom_phys_avail[iter].theres_more =
124 &prom_phys_avail[iter+1];
125 }
126 prom_phys_avail[iter-1].theres_more = NULL;
128 num_regs = prom_getproperty(node, "reg",
129 (char *) prom_reg_memlist,
130 sizeof(prom_reg_memlist));
131 num_regs = (num_regs/sizeof(struct linux_prom_registers));
132 for(iter=0; iter<num_regs; iter++) {
133 prom_phys_total[iter].start_adr =
134 (char *) prom_reg_memlist[iter].phys_addr;
135 prom_phys_total[iter].num_bytes =
136 (unsigned long) prom_reg_memlist[iter].reg_size;
137 prom_phys_total[iter].theres_more =
138 &prom_phys_total[iter+1];
139 }
140 prom_phys_total[iter-1].theres_more = NULL;
142 node = prom_getchild(prom_root_node);
143 node = prom_searchsiblings(node, "virtual-memory");
144 num_regs = prom_getproperty(node, "available",
145 (char *) prom_reg_memlist,
146 sizeof(prom_reg_memlist));
147 num_regs = (num_regs/sizeof(struct linux_prom_registers));
149 /* Convert available virtual areas to taken virtual
150 * areas. First sort, then convert.
151 */
152 for(iter=0; iter<num_regs; iter++) {
153 prom_prom_taken[iter].start_adr =
154 (char *) prom_reg_memlist[iter].phys_addr;
155 prom_prom_taken[iter].num_bytes =
156 (unsigned long) prom_reg_memlist[iter].reg_size;
157 prom_prom_taken[iter].theres_more =
158 &prom_prom_taken[iter+1];
159 }
160 prom_prom_taken[iter-1].theres_more = NULL;
162 prom_sortmemlist(prom_prom_taken);
164 /* Finally, convert. */
165 for(iter=0; iter<num_regs; iter++) {
166 prom_prom_taken[iter].start_adr =
167 prom_prom_taken[iter].start_adr +
168 prom_prom_taken[iter].num_bytes;
169 prom_prom_taken[iter].num_bytes =
170 prom_prom_taken[iter+1].start_adr -
171 prom_prom_taken[iter].start_adr;
172 }
173 prom_prom_taken[iter-1].num_bytes =
174 0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr;
176 /* Sort the other two lists. */
177 prom_sortmemlist(prom_phys_total);
178 prom_sortmemlist(prom_phys_avail);
179 break;
181 case PROM_SUN4:
182 #ifdef CONFIG_SUN4
183 /* how simple :) */
184 prom_phys_total[0].start_adr = NULL;
185 prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize);
186 prom_phys_total[0].theres_more = NULL;
187 prom_prom_taken[0].start_adr = NULL;
188 prom_prom_taken[0].num_bytes = 0x0;
189 prom_prom_taken[0].theres_more = NULL;
190 prom_phys_avail[0].start_adr = NULL;
191 prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail);
192 prom_phys_avail[0].theres_more = NULL;
193 #endif
194 break;
196 default:
197 break;
198 };
200 /* Link all the lists into the top-level descriptor. */
201 prom_memlist.v0_totphys=&prom_ptot_ptr;
202 prom_memlist.v0_prommap=&prom_ptak_ptr;
203 prom_memlist.v0_available=&prom_pavl_ptr;
205 return;
206 }
208 /* This returns a pointer to our libraries internal v0 format
209 * memory descriptor.
210 */
211 struct linux_mem_v0 *
212 prom_meminfo(void)
213 {
214 return &prom_memlist;
215 }