ia64/linux-2.6.18-xen.hg

view arch/sparc64/kernel/semaphore.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: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
2 * semaphore.c: Sparc64 semaphore implementation.
3 *
4 * This is basically the PPC semaphore scheme ported to use
5 * the sparc64 atomic instructions, so see the PPC code for
6 * credits.
7 */
9 #include <linux/sched.h>
10 #include <linux/errno.h>
11 #include <linux/init.h>
13 /*
14 * Atomically update sem->count.
15 * This does the equivalent of the following:
16 *
17 * old_count = sem->count;
18 * tmp = MAX(old_count, 0) + incr;
19 * sem->count = tmp;
20 * return old_count;
21 */
22 static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
23 {
24 int old_count, tmp;
26 __asm__ __volatile__("\n"
27 " ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
28 "1: ldsw [%3], %0\n"
29 " mov %0, %1\n"
30 " cmp %0, 0\n"
31 " movl %%icc, 0, %1\n"
32 " add %1, %4, %1\n"
33 " cas [%3], %0, %1\n"
34 " cmp %0, %1\n"
35 " membar #StoreLoad | #StoreStore\n"
36 " bne,pn %%icc, 1b\n"
37 " nop\n"
38 : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
39 : "r" (&sem->count), "r" (incr), "m" (sem->count)
40 : "cc");
42 return old_count;
43 }
45 static void __up(struct semaphore *sem)
46 {
47 __sem_update_count(sem, 1);
48 wake_up(&sem->wait);
49 }
51 void up(struct semaphore *sem)
52 {
53 /* This atomically does:
54 * old_val = sem->count;
55 * new_val = sem->count + 1;
56 * sem->count = new_val;
57 * if (old_val < 0)
58 * __up(sem);
59 *
60 * The (old_val < 0) test is equivalent to
61 * the more straightforward (new_val <= 0),
62 * but it is easier to test the former because
63 * of how the CAS instruction works.
64 */
66 __asm__ __volatile__("\n"
67 " ! up sem(%0)\n"
68 " membar #StoreLoad | #LoadLoad\n"
69 "1: lduw [%0], %%g1\n"
70 " add %%g1, 1, %%g7\n"
71 " cas [%0], %%g1, %%g7\n"
72 " cmp %%g1, %%g7\n"
73 " bne,pn %%icc, 1b\n"
74 " addcc %%g7, 1, %%g0\n"
75 " membar #StoreLoad | #StoreStore\n"
76 " ble,pn %%icc, 3f\n"
77 " nop\n"
78 "2:\n"
79 " .subsection 2\n"
80 "3: mov %0, %%g1\n"
81 " save %%sp, -160, %%sp\n"
82 " call %1\n"
83 " mov %%g1, %%o0\n"
84 " ba,pt %%xcc, 2b\n"
85 " restore\n"
86 " .previous\n"
87 : : "r" (sem), "i" (__up)
88 : "g1", "g2", "g3", "g7", "memory", "cc");
89 }
91 static void __sched __down(struct semaphore * sem)
92 {
93 struct task_struct *tsk = current;
94 DECLARE_WAITQUEUE(wait, tsk);
96 tsk->state = TASK_UNINTERRUPTIBLE;
97 add_wait_queue_exclusive(&sem->wait, &wait);
99 while (__sem_update_count(sem, -1) <= 0) {
100 schedule();
101 tsk->state = TASK_UNINTERRUPTIBLE;
102 }
103 remove_wait_queue(&sem->wait, &wait);
104 tsk->state = TASK_RUNNING;
106 wake_up(&sem->wait);
107 }
109 void __sched down(struct semaphore *sem)
110 {
111 might_sleep();
112 /* This atomically does:
113 * old_val = sem->count;
114 * new_val = sem->count - 1;
115 * sem->count = new_val;
116 * if (old_val < 1)
117 * __down(sem);
118 *
119 * The (old_val < 1) test is equivalent to
120 * the more straightforward (new_val < 0),
121 * but it is easier to test the former because
122 * of how the CAS instruction works.
123 */
125 __asm__ __volatile__("\n"
126 " ! down sem(%0)\n"
127 "1: lduw [%0], %%g1\n"
128 " sub %%g1, 1, %%g7\n"
129 " cas [%0], %%g1, %%g7\n"
130 " cmp %%g1, %%g7\n"
131 " bne,pn %%icc, 1b\n"
132 " cmp %%g7, 1\n"
133 " membar #StoreLoad | #StoreStore\n"
134 " bl,pn %%icc, 3f\n"
135 " nop\n"
136 "2:\n"
137 " .subsection 2\n"
138 "3: mov %0, %%g1\n"
139 " save %%sp, -160, %%sp\n"
140 " call %1\n"
141 " mov %%g1, %%o0\n"
142 " ba,pt %%xcc, 2b\n"
143 " restore\n"
144 " .previous\n"
145 : : "r" (sem), "i" (__down)
146 : "g1", "g2", "g3", "g7", "memory", "cc");
147 }
149 int down_trylock(struct semaphore *sem)
150 {
151 int ret;
153 /* This atomically does:
154 * old_val = sem->count;
155 * new_val = sem->count - 1;
156 * if (old_val < 1) {
157 * ret = 1;
158 * } else {
159 * sem->count = new_val;
160 * ret = 0;
161 * }
162 *
163 * The (old_val < 1) test is equivalent to
164 * the more straightforward (new_val < 0),
165 * but it is easier to test the former because
166 * of how the CAS instruction works.
167 */
169 __asm__ __volatile__("\n"
170 " ! down_trylock sem(%1) ret(%0)\n"
171 "1: lduw [%1], %%g1\n"
172 " sub %%g1, 1, %%g7\n"
173 " cmp %%g1, 1\n"
174 " bl,pn %%icc, 2f\n"
175 " mov 1, %0\n"
176 " cas [%1], %%g1, %%g7\n"
177 " cmp %%g1, %%g7\n"
178 " bne,pn %%icc, 1b\n"
179 " mov 0, %0\n"
180 " membar #StoreLoad | #StoreStore\n"
181 "2:\n"
182 : "=&r" (ret)
183 : "r" (sem)
184 : "g1", "g7", "memory", "cc");
186 return ret;
187 }
189 static int __sched __down_interruptible(struct semaphore * sem)
190 {
191 int retval = 0;
192 struct task_struct *tsk = current;
193 DECLARE_WAITQUEUE(wait, tsk);
195 tsk->state = TASK_INTERRUPTIBLE;
196 add_wait_queue_exclusive(&sem->wait, &wait);
198 while (__sem_update_count(sem, -1) <= 0) {
199 if (signal_pending(current)) {
200 __sem_update_count(sem, 0);
201 retval = -EINTR;
202 break;
203 }
204 schedule();
205 tsk->state = TASK_INTERRUPTIBLE;
206 }
207 tsk->state = TASK_RUNNING;
208 remove_wait_queue(&sem->wait, &wait);
209 wake_up(&sem->wait);
210 return retval;
211 }
213 int __sched down_interruptible(struct semaphore *sem)
214 {
215 int ret = 0;
217 might_sleep();
218 /* This atomically does:
219 * old_val = sem->count;
220 * new_val = sem->count - 1;
221 * sem->count = new_val;
222 * if (old_val < 1)
223 * ret = __down_interruptible(sem);
224 *
225 * The (old_val < 1) test is equivalent to
226 * the more straightforward (new_val < 0),
227 * but it is easier to test the former because
228 * of how the CAS instruction works.
229 */
231 __asm__ __volatile__("\n"
232 " ! down_interruptible sem(%2) ret(%0)\n"
233 "1: lduw [%2], %%g1\n"
234 " sub %%g1, 1, %%g7\n"
235 " cas [%2], %%g1, %%g7\n"
236 " cmp %%g1, %%g7\n"
237 " bne,pn %%icc, 1b\n"
238 " cmp %%g7, 1\n"
239 " membar #StoreLoad | #StoreStore\n"
240 " bl,pn %%icc, 3f\n"
241 " nop\n"
242 "2:\n"
243 " .subsection 2\n"
244 "3: mov %2, %%g1\n"
245 " save %%sp, -160, %%sp\n"
246 " call %3\n"
247 " mov %%g1, %%o0\n"
248 " ba,pt %%xcc, 2b\n"
249 " restore\n"
250 " .previous\n"
251 : "=r" (ret)
252 : "0" (ret), "r" (sem), "i" (__down_interruptible)
253 : "g1", "g2", "g3", "g7", "memory", "cc");
254 return ret;
255 }