ia64/linux-2.6.18-xen.hg

view lib/kobject_uevent.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 /*
2 * kernel userspace event delivery
3 *
4 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2004 Novell, Inc. All rights reserved.
6 * Copyright (C) 2004 IBM, Inc. All rights reserved.
7 *
8 * Licensed under the GNU GPL v2.
9 *
10 * Authors:
11 * Robert Love <rml@novell.com>
12 * Kay Sievers <kay.sievers@vrfy.org>
13 * Arjan van de Ven <arjanv@redhat.com>
14 * Greg Kroah-Hartman <greg@kroah.com>
15 */
17 #include <linux/spinlock.h>
18 #include <linux/socket.h>
19 #include <linux/skbuff.h>
20 #include <linux/netlink.h>
21 #include <linux/string.h>
22 #include <linux/kobject.h>
23 #include <net/sock.h>
25 #define BUFFER_SIZE 2048 /* buffer for the variables */
26 #define NUM_ENVP 32 /* number of env pointers */
28 #if defined(CONFIG_HOTPLUG)
29 u64 uevent_seqnum;
30 char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
31 static DEFINE_SPINLOCK(sequence_lock);
32 #if defined(CONFIG_NET)
33 static struct sock *uevent_sock;
34 #endif
36 static char *action_to_string(enum kobject_action action)
37 {
38 switch (action) {
39 case KOBJ_ADD:
40 return "add";
41 case KOBJ_REMOVE:
42 return "remove";
43 case KOBJ_CHANGE:
44 return "change";
45 case KOBJ_MOUNT:
46 return "mount";
47 case KOBJ_UMOUNT:
48 return "umount";
49 case KOBJ_OFFLINE:
50 return "offline";
51 case KOBJ_ONLINE:
52 return "online";
53 default:
54 return NULL;
55 }
56 }
58 /**
59 * kobject_uevent - notify userspace by ending an uevent
60 *
61 * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
62 * @kobj: struct kobject that the action is happening to
63 */
64 void kobject_uevent(struct kobject *kobj, enum kobject_action action)
65 {
66 char **envp;
67 char *buffer;
68 char *scratch;
69 const char *action_string;
70 const char *devpath = NULL;
71 const char *subsystem;
72 struct kobject *top_kobj;
73 struct kset *kset;
74 struct kset_uevent_ops *uevent_ops;
75 u64 seq;
76 char *seq_buff;
77 int i = 0;
78 int retval;
80 pr_debug("%s\n", __FUNCTION__);
82 action_string = action_to_string(action);
83 if (!action_string)
84 return;
86 /* search the kset we belong to */
87 top_kobj = kobj;
88 if (!top_kobj->kset && top_kobj->parent) {
89 do {
90 top_kobj = top_kobj->parent;
91 } while (!top_kobj->kset && top_kobj->parent);
92 }
93 if (!top_kobj->kset)
94 return;
96 kset = top_kobj->kset;
97 uevent_ops = kset->uevent_ops;
99 /* skip the event, if the filter returns zero. */
100 if (uevent_ops && uevent_ops->filter)
101 if (!uevent_ops->filter(kset, kobj))
102 return;
104 /* environment index */
105 envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
106 if (!envp)
107 return;
109 /* environment values */
110 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
111 if (!buffer)
112 goto exit;
114 /* complete object path */
115 devpath = kobject_get_path(kobj, GFP_KERNEL);
116 if (!devpath)
117 goto exit;
119 /* originating subsystem */
120 if (uevent_ops && uevent_ops->name)
121 subsystem = uevent_ops->name(kset, kobj);
122 else
123 subsystem = kobject_name(&kset->kobj);
125 /* event environemnt for helper process only */
126 envp[i++] = "HOME=/";
127 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
129 /* default keys */
130 scratch = buffer;
131 envp [i++] = scratch;
132 scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
133 envp [i++] = scratch;
134 scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
135 envp [i++] = scratch;
136 scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
138 /* just reserve the space, overwrite it after kset call has returned */
139 envp[i++] = seq_buff = scratch;
140 scratch += strlen("SEQNUM=18446744073709551616") + 1;
142 /* let the kset specific function add its stuff */
143 if (uevent_ops && uevent_ops->uevent) {
144 retval = uevent_ops->uevent(kset, kobj,
145 &envp[i], NUM_ENVP - i, scratch,
146 BUFFER_SIZE - (scratch - buffer));
147 if (retval) {
148 pr_debug ("%s - uevent() returned %d\n",
149 __FUNCTION__, retval);
150 goto exit;
151 }
152 }
154 /* we will send an event, request a new sequence number */
155 spin_lock(&sequence_lock);
156 seq = ++uevent_seqnum;
157 spin_unlock(&sequence_lock);
158 sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
160 #if defined(CONFIG_NET)
161 /* send netlink message */
162 if (uevent_sock) {
163 struct sk_buff *skb;
164 size_t len;
166 /* allocate message with the maximum possible size */
167 len = strlen(action_string) + strlen(devpath) + 2;
168 skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
169 if (skb) {
170 /* add header */
171 scratch = skb_put(skb, len);
172 sprintf(scratch, "%s@%s", action_string, devpath);
174 /* copy keys to our continuous event payload buffer */
175 for (i = 2; envp[i]; i++) {
176 len = strlen(envp[i]) + 1;
177 scratch = skb_put(skb, len);
178 strcpy(scratch, envp[i]);
179 }
181 NETLINK_CB(skb).dst_group = 1;
182 netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
183 }
184 }
185 #endif
187 /* call uevent_helper, usually only enabled during early boot */
188 if (uevent_helper[0]) {
189 char *argv [3];
191 argv [0] = uevent_helper;
192 argv [1] = (char *)subsystem;
193 argv [2] = NULL;
194 call_usermodehelper (argv[0], argv, envp, 0);
195 }
197 exit:
198 kfree(devpath);
199 kfree(buffer);
200 kfree(envp);
201 return;
202 }
203 EXPORT_SYMBOL_GPL(kobject_uevent);
205 /**
206 * add_uevent_var - helper for creating event variables
207 * @envp: Pointer to table of environment variables, as passed into
208 * uevent() method.
209 * @num_envp: Number of environment variable slots available, as
210 * passed into uevent() method.
211 * @cur_index: Pointer to current index into @envp. It should be
212 * initialized to 0 before the first call to add_uevent_var(),
213 * and will be incremented on success.
214 * @buffer: Pointer to buffer for environment variables, as passed
215 * into uevent() method.
216 * @buffer_size: Length of @buffer, as passed into uevent() method.
217 * @cur_len: Pointer to current length of space used in @buffer.
218 * Should be initialized to 0 before the first call to
219 * add_uevent_var(), and will be incremented on success.
220 * @format: Format for creating environment variable (of the form
221 * "XXX=%x") for snprintf().
222 *
223 * Returns 0 if environment variable was added successfully or -ENOMEM
224 * if no space was available.
225 */
226 int add_uevent_var(char **envp, int num_envp, int *cur_index,
227 char *buffer, int buffer_size, int *cur_len,
228 const char *format, ...)
229 {
230 va_list args;
232 /*
233 * We check against num_envp - 1 to make sure there is at
234 * least one slot left after we return, since kobject_uevent()
235 * needs to set the last slot to NULL.
236 */
237 if (*cur_index >= num_envp - 1)
238 return -ENOMEM;
240 envp[*cur_index] = buffer + *cur_len;
242 va_start(args, format);
243 *cur_len += vsnprintf(envp[*cur_index],
244 max(buffer_size - *cur_len, 0),
245 format, args) + 1;
246 va_end(args);
248 if (*cur_len > buffer_size)
249 return -ENOMEM;
251 (*cur_index)++;
252 return 0;
253 }
254 EXPORT_SYMBOL_GPL(add_uevent_var);
256 #if defined(CONFIG_NET)
257 static int __init kobject_uevent_init(void)
258 {
259 uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
260 THIS_MODULE);
262 if (!uevent_sock) {
263 printk(KERN_ERR
264 "kobject_uevent: unable to create netlink socket!\n");
265 return -ENODEV;
266 }
268 return 0;
269 }
271 postcore_initcall(kobject_uevent_init);
272 #endif
274 #endif /* CONFIG_HOTPLUG */