ia64/linux-2.6.18-xen.hg

view drivers/block/cryptoloop.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 Linux loop encryption enabling module
4 Copyright (C) 2002 Herbert Valerio Riedel <hvr@gnu.org>
5 Copyright (C) 2003 Fruhwirth Clemens <clemens@endorphin.org>
7 This module is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This module is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this module; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
22 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/string.h>
26 #include <linux/crypto.h>
27 #include <linux/blkdev.h>
28 #include <linux/loop.h>
29 #include <asm/semaphore.h>
30 #include <asm/uaccess.h>
32 MODULE_LICENSE("GPL");
33 MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI");
34 MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
36 #define LOOP_IV_SECTOR_BITS 9
37 #define LOOP_IV_SECTOR_SIZE (1 << LOOP_IV_SECTOR_BITS)
39 static int
40 cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
41 {
42 int err = -EINVAL;
43 char cms[LO_NAME_SIZE]; /* cipher-mode string */
44 char *cipher;
45 char *mode;
46 char *cmsp = cms; /* c-m string pointer */
47 struct crypto_tfm *tfm = NULL;
49 /* encryption breaks for non sector aligned offsets */
51 if (info->lo_offset % LOOP_IV_SECTOR_SIZE)
52 goto out;
54 strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE);
55 cms[LO_NAME_SIZE - 1] = 0;
56 cipher = strsep(&cmsp, "-");
57 mode = strsep(&cmsp, "-");
59 if (mode == NULL || strcmp(mode, "cbc") == 0)
60 tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC |
61 CRYPTO_TFM_REQ_MAY_SLEEP);
62 else if (strcmp(mode, "ecb") == 0)
63 tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB |
64 CRYPTO_TFM_REQ_MAY_SLEEP);
65 if (tfm == NULL)
66 return -EINVAL;
68 err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key,
69 info->lo_encrypt_key_size);
71 if (err != 0)
72 goto out_free_tfm;
74 lo->key_data = tfm;
75 return 0;
77 out_free_tfm:
78 crypto_free_tfm(tfm);
80 out:
81 return err;
82 }
85 typedef int (*encdec_ecb_t)(struct crypto_tfm *tfm,
86 struct scatterlist *sg_out,
87 struct scatterlist *sg_in,
88 unsigned int nsg);
91 static int
92 cryptoloop_transfer_ecb(struct loop_device *lo, int cmd,
93 struct page *raw_page, unsigned raw_off,
94 struct page *loop_page, unsigned loop_off,
95 int size, sector_t IV)
96 {
97 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
98 struct scatterlist sg_out = { NULL, };
99 struct scatterlist sg_in = { NULL, };
101 encdec_ecb_t encdecfunc;
102 struct page *in_page, *out_page;
103 unsigned in_offs, out_offs;
105 if (cmd == READ) {
106 in_page = raw_page;
107 in_offs = raw_off;
108 out_page = loop_page;
109 out_offs = loop_off;
110 encdecfunc = tfm->crt_u.cipher.cit_decrypt;
111 } else {
112 in_page = loop_page;
113 in_offs = loop_off;
114 out_page = raw_page;
115 out_offs = raw_off;
116 encdecfunc = tfm->crt_u.cipher.cit_encrypt;
117 }
119 while (size > 0) {
120 const int sz = min(size, LOOP_IV_SECTOR_SIZE);
122 sg_in.page = in_page;
123 sg_in.offset = in_offs;
124 sg_in.length = sz;
126 sg_out.page = out_page;
127 sg_out.offset = out_offs;
128 sg_out.length = sz;
130 encdecfunc(tfm, &sg_out, &sg_in, sz);
132 size -= sz;
133 in_offs += sz;
134 out_offs += sz;
135 }
137 return 0;
138 }
140 typedef int (*encdec_cbc_t)(struct crypto_tfm *tfm,
141 struct scatterlist *sg_out,
142 struct scatterlist *sg_in,
143 unsigned int nsg, u8 *iv);
145 static int
146 cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
147 struct page *raw_page, unsigned raw_off,
148 struct page *loop_page, unsigned loop_off,
149 int size, sector_t IV)
150 {
151 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
152 struct scatterlist sg_out = { NULL, };
153 struct scatterlist sg_in = { NULL, };
155 encdec_cbc_t encdecfunc;
156 struct page *in_page, *out_page;
157 unsigned in_offs, out_offs;
159 if (cmd == READ) {
160 in_page = raw_page;
161 in_offs = raw_off;
162 out_page = loop_page;
163 out_offs = loop_off;
164 encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv;
165 } else {
166 in_page = loop_page;
167 in_offs = loop_off;
168 out_page = raw_page;
169 out_offs = raw_off;
170 encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv;
171 }
173 while (size > 0) {
174 const int sz = min(size, LOOP_IV_SECTOR_SIZE);
175 u32 iv[4] = { 0, };
176 iv[0] = cpu_to_le32(IV & 0xffffffff);
178 sg_in.page = in_page;
179 sg_in.offset = in_offs;
180 sg_in.length = sz;
182 sg_out.page = out_page;
183 sg_out.offset = out_offs;
184 sg_out.length = sz;
186 encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv);
188 IV++;
189 size -= sz;
190 in_offs += sz;
191 out_offs += sz;
192 }
194 return 0;
195 }
197 static int
198 cryptoloop_transfer(struct loop_device *lo, int cmd,
199 struct page *raw_page, unsigned raw_off,
200 struct page *loop_page, unsigned loop_off,
201 int size, sector_t IV)
202 {
203 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
204 if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB)
205 {
206 lo->transfer = cryptoloop_transfer_ecb;
207 return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off,
208 loop_page, loop_off, size, IV);
209 }
210 if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC)
211 {
212 lo->transfer = cryptoloop_transfer_cbc;
213 return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off,
214 loop_page, loop_off, size, IV);
215 }
217 /* This is not supposed to happen */
219 printk( KERN_ERR "cryptoloop: unsupported cipher mode in cryptoloop_transfer!\n");
220 return -EINVAL;
221 }
223 static int
224 cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
225 {
226 return -EINVAL;
227 }
229 static int
230 cryptoloop_release(struct loop_device *lo)
231 {
232 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
233 if (tfm != NULL) {
234 crypto_free_tfm(tfm);
235 lo->key_data = NULL;
236 return 0;
237 }
238 printk(KERN_ERR "cryptoloop_release(): tfm == NULL?\n");
239 return -EINVAL;
240 }
242 static struct loop_func_table cryptoloop_funcs = {
243 .number = LO_CRYPT_CRYPTOAPI,
244 .init = cryptoloop_init,
245 .ioctl = cryptoloop_ioctl,
246 .transfer = cryptoloop_transfer,
247 .release = cryptoloop_release,
248 .owner = THIS_MODULE
249 };
251 static int __init
252 init_cryptoloop(void)
253 {
254 int rc = loop_register_transfer(&cryptoloop_funcs);
256 if (rc)
257 printk(KERN_ERR "cryptoloop: loop_register_transfer failed\n");
258 return rc;
259 }
261 static void __exit
262 cleanup_cryptoloop(void)
263 {
264 if (loop_unregister_transfer(LO_CRYPT_CRYPTOAPI))
265 printk(KERN_ERR
266 "cryptoloop: loop_unregister_transfer failed\n");
267 }
269 module_init(init_cryptoloop);
270 module_exit(cleanup_cryptoloop);