ia64/linux-2.6.18-xen.hg

view drivers/mtd/mtdcore.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 * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $
3 *
4 * Core registration and callback routines for MTD
5 * drivers and users.
6 *
7 */
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/ptrace.h>
13 #include <linux/slab.h>
14 #include <linux/string.h>
15 #include <linux/timer.h>
16 #include <linux/major.h>
17 #include <linux/fs.h>
18 #include <linux/ioctl.h>
19 #include <linux/init.h>
20 #include <linux/mtd/compatmac.h>
21 #include <linux/proc_fs.h>
23 #include <linux/mtd/mtd.h>
25 /* These are exported solely for the purpose of mtd_blkdevs.c. You
26 should not use them for _anything_ else */
27 DEFINE_MUTEX(mtd_table_mutex);
28 struct mtd_info *mtd_table[MAX_MTD_DEVICES];
30 EXPORT_SYMBOL_GPL(mtd_table_mutex);
31 EXPORT_SYMBOL_GPL(mtd_table);
33 static LIST_HEAD(mtd_notifiers);
35 /**
36 * add_mtd_device - register an MTD device
37 * @mtd: pointer to new MTD device info structure
38 *
39 * Add a device to the list of MTD devices present in the system, and
40 * notify each currently active MTD 'user' of its arrival. Returns
41 * zero on success or 1 on failure, which currently will only happen
42 * if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16)
43 */
45 int add_mtd_device(struct mtd_info *mtd)
46 {
47 int i;
49 BUG_ON(mtd->writesize == 0);
50 mutex_lock(&mtd_table_mutex);
52 for (i=0; i < MAX_MTD_DEVICES; i++)
53 if (!mtd_table[i]) {
54 struct list_head *this;
56 mtd_table[i] = mtd;
57 mtd->index = i;
58 mtd->usecount = 0;
60 DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
61 /* No need to get a refcount on the module containing
62 the notifier, since we hold the mtd_table_mutex */
63 list_for_each(this, &mtd_notifiers) {
64 struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
65 not->add(mtd);
66 }
68 mutex_unlock(&mtd_table_mutex);
69 /* We _know_ we aren't being removed, because
70 our caller is still holding us here. So none
71 of this try_ nonsense, and no bitching about it
72 either. :) */
73 __module_get(THIS_MODULE);
74 return 0;
75 }
77 mutex_unlock(&mtd_table_mutex);
78 return 1;
79 }
81 /**
82 * del_mtd_device - unregister an MTD device
83 * @mtd: pointer to MTD device info structure
84 *
85 * Remove a device from the list of MTD devices present in the system,
86 * and notify each currently active MTD 'user' of its departure.
87 * Returns zero on success or 1 on failure, which currently will happen
88 * if the requested device does not appear to be present in the list.
89 */
91 int del_mtd_device (struct mtd_info *mtd)
92 {
93 int ret;
95 mutex_lock(&mtd_table_mutex);
97 if (mtd_table[mtd->index] != mtd) {
98 ret = -ENODEV;
99 } else if (mtd->usecount) {
100 printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
101 mtd->index, mtd->name, mtd->usecount);
102 ret = -EBUSY;
103 } else {
104 struct list_head *this;
106 /* No need to get a refcount on the module containing
107 the notifier, since we hold the mtd_table_mutex */
108 list_for_each(this, &mtd_notifiers) {
109 struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
110 not->remove(mtd);
111 }
113 mtd_table[mtd->index] = NULL;
115 module_put(THIS_MODULE);
116 ret = 0;
117 }
119 mutex_unlock(&mtd_table_mutex);
120 return ret;
121 }
123 /**
124 * register_mtd_user - register a 'user' of MTD devices.
125 * @new: pointer to notifier info structure
126 *
127 * Registers a pair of callbacks function to be called upon addition
128 * or removal of MTD devices. Causes the 'add' callback to be immediately
129 * invoked for each MTD device currently present in the system.
130 */
132 void register_mtd_user (struct mtd_notifier *new)
133 {
134 int i;
136 mutex_lock(&mtd_table_mutex);
138 list_add(&new->list, &mtd_notifiers);
140 __module_get(THIS_MODULE);
142 for (i=0; i< MAX_MTD_DEVICES; i++)
143 if (mtd_table[i])
144 new->add(mtd_table[i]);
146 mutex_unlock(&mtd_table_mutex);
147 }
149 /**
150 * unregister_mtd_user - unregister a 'user' of MTD devices.
151 * @old: pointer to notifier info structure
152 *
153 * Removes a callback function pair from the list of 'users' to be
154 * notified upon addition or removal of MTD devices. Causes the
155 * 'remove' callback to be immediately invoked for each MTD device
156 * currently present in the system.
157 */
159 int unregister_mtd_user (struct mtd_notifier *old)
160 {
161 int i;
163 mutex_lock(&mtd_table_mutex);
165 module_put(THIS_MODULE);
167 for (i=0; i< MAX_MTD_DEVICES; i++)
168 if (mtd_table[i])
169 old->remove(mtd_table[i]);
171 list_del(&old->list);
172 mutex_unlock(&mtd_table_mutex);
173 return 0;
174 }
177 /**
178 * get_mtd_device - obtain a validated handle for an MTD device
179 * @mtd: last known address of the required MTD device
180 * @num: internal device number of the required MTD device
181 *
182 * Given a number and NULL address, return the num'th entry in the device
183 * table, if any. Given an address and num == -1, search the device table
184 * for a device with that address and return if it's still present. Given
185 * both, return the num'th driver only if its address matches. Return NULL
186 * if not.
187 */
189 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
190 {
191 struct mtd_info *ret = NULL;
192 int i;
194 mutex_lock(&mtd_table_mutex);
196 if (num == -1) {
197 for (i=0; i< MAX_MTD_DEVICES; i++)
198 if (mtd_table[i] == mtd)
199 ret = mtd_table[i];
200 } else if (num < MAX_MTD_DEVICES) {
201 ret = mtd_table[num];
202 if (mtd && mtd != ret)
203 ret = NULL;
204 }
206 if (ret && !try_module_get(ret->owner))
207 ret = NULL;
209 if (ret)
210 ret->usecount++;
212 mutex_unlock(&mtd_table_mutex);
213 return ret;
214 }
216 void put_mtd_device(struct mtd_info *mtd)
217 {
218 int c;
220 mutex_lock(&mtd_table_mutex);
221 c = --mtd->usecount;
222 mutex_unlock(&mtd_table_mutex);
223 BUG_ON(c < 0);
225 module_put(mtd->owner);
226 }
228 /* default_mtd_writev - default mtd writev method for MTD devices that
229 * dont implement their own
230 */
232 int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
233 unsigned long count, loff_t to, size_t *retlen)
234 {
235 unsigned long i;
236 size_t totlen = 0, thislen;
237 int ret = 0;
239 if(!mtd->write) {
240 ret = -EROFS;
241 } else {
242 for (i=0; i<count; i++) {
243 if (!vecs[i].iov_len)
244 continue;
245 ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
246 totlen += thislen;
247 if (ret || thislen != vecs[i].iov_len)
248 break;
249 to += vecs[i].iov_len;
250 }
251 }
252 if (retlen)
253 *retlen = totlen;
254 return ret;
255 }
257 EXPORT_SYMBOL(add_mtd_device);
258 EXPORT_SYMBOL(del_mtd_device);
259 EXPORT_SYMBOL(get_mtd_device);
260 EXPORT_SYMBOL(put_mtd_device);
261 EXPORT_SYMBOL(register_mtd_user);
262 EXPORT_SYMBOL(unregister_mtd_user);
263 EXPORT_SYMBOL(default_mtd_writev);
265 #ifdef CONFIG_PROC_FS
267 /*====================================================================*/
268 /* Support for /proc/mtd */
270 static struct proc_dir_entry *proc_mtd;
272 static inline int mtd_proc_info (char *buf, int i)
273 {
274 struct mtd_info *this = mtd_table[i];
276 if (!this)
277 return 0;
279 return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size,
280 this->erasesize, this->name);
281 }
283 static int mtd_read_proc (char *page, char **start, off_t off, int count,
284 int *eof, void *data_unused)
285 {
286 int len, l, i;
287 off_t begin = 0;
289 mutex_lock(&mtd_table_mutex);
291 len = sprintf(page, "dev: size erasesize name\n");
292 for (i=0; i< MAX_MTD_DEVICES; i++) {
294 l = mtd_proc_info(page + len, i);
295 len += l;
296 if (len+begin > off+count)
297 goto done;
298 if (len+begin < off) {
299 begin += len;
300 len = 0;
301 }
302 }
304 *eof = 1;
306 done:
307 mutex_unlock(&mtd_table_mutex);
308 if (off >= len+begin)
309 return 0;
310 *start = page + (off-begin);
311 return ((count < begin+len-off) ? count : begin+len-off);
312 }
314 /*====================================================================*/
315 /* Init code */
317 static int __init init_mtd(void)
318 {
319 if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
320 proc_mtd->read_proc = mtd_read_proc;
321 return 0;
322 }
324 static void __exit cleanup_mtd(void)
325 {
326 if (proc_mtd)
327 remove_proc_entry( "mtd", NULL);
328 }
330 module_init(init_mtd);
331 module_exit(cleanup_mtd);
333 #endif /* CONFIG_PROC_FS */
336 MODULE_LICENSE("GPL");
337 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
338 MODULE_DESCRIPTION("Core MTD registration and access routines");