debuggers.hg

view tools/libxc/xc_tmem.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents c98fd816db85
children 3ffdb094c2c0
line source
1 /******************************************************************************
2 * xc_tmem.c
3 *
4 * Copyright (C) 2008 Oracle Corp.
5 */
7 #include "xc_private.h"
8 #include <xen/tmem.h>
10 static int do_tmem_op(int xc, tmem_op_t *op)
11 {
12 int ret;
13 DECLARE_HYPERCALL;
15 hypercall.op = __HYPERVISOR_tmem_op;
16 hypercall.arg[0] = (unsigned long)op;
17 if (lock_pages(op, sizeof(*op)) != 0)
18 {
19 PERROR("Could not lock memory for Xen hypercall");
20 return -EFAULT;
21 }
22 if ((ret = do_xen_hypercall(xc, &hypercall)) < 0)
23 {
24 if ( errno == EACCES )
25 DPRINTF("tmem operation failed -- need to"
26 " rebuild the user-space tool set?\n");
27 }
28 unlock_pages(op, sizeof(*op));
30 return ret;
31 }
33 int xc_tmem_control(int xc,
34 int32_t pool_id,
35 uint32_t subop,
36 uint32_t cli_id,
37 uint32_t arg1,
38 uint32_t arg2,
39 uint64_t arg3,
40 void *buf)
41 {
42 tmem_op_t op;
43 int rc;
45 op.cmd = TMEM_CONTROL;
46 op.pool_id = pool_id;
47 op.u.ctrl.subop = subop;
48 op.u.ctrl.cli_id = cli_id;
49 set_xen_guest_handle(op.u.ctrl.buf,buf);
50 op.u.ctrl.arg1 = arg1;
51 op.u.ctrl.arg2 = arg2;
52 op.u.ctrl.arg3 = arg3;
54 if (subop == TMEMC_LIST) {
55 if ((arg1 != 0) && (lock_pages(buf, arg1) != 0))
56 {
57 PERROR("Could not lock memory for Xen hypercall");
58 return -ENOMEM;
59 }
60 }
62 #ifdef VALGRIND
63 if (arg1 != 0)
64 memset(buf, 0, arg1);
65 #endif
67 rc = do_tmem_op(xc, &op);
69 if (subop == TMEMC_LIST) {
70 if (arg1 != 0)
71 unlock_pages(buf, arg1);
72 }
74 return rc;
75 }
77 static int xc_tmem_uuid_parse(char *uuid_str, uint64_t *uuid_lo, uint64_t *uuid_hi)
78 {
79 char *p = uuid_str;
80 uint64_t *x = uuid_hi;
81 int i = 0, digit;
83 *uuid_lo = 0; *uuid_hi = 0;
84 for ( p = uuid_str, i = 0; i != 36 && *p != '\0'; p++, i++ )
85 {
86 if ( (i == 8 || i == 13 || i == 18 || i == 23) )
87 {
88 if ( *p != '-' )
89 return -1;
90 if ( i == 18 )
91 x = uuid_lo;
92 continue;
93 }
94 else if ( *p >= '0' && *p <= '9' )
95 digit = *p - '0';
96 else if ( *p >= 'A' && *p <= 'F' )
97 digit = *p - 'A';
98 else if ( *p >= 'a' && *p <= 'f' )
99 digit = *p - 'a';
100 else
101 return -1;
102 *x = (*x << 4) | digit;
103 }
104 if ( (i != 1 && i != 36) || *p != '\0' )
105 return -1;
106 return 0;
107 }
109 int xc_tmem_auth(int xc,
110 int cli_id,
111 char *uuid_str,
112 int arg1)
113 {
114 tmem_op_t op;
116 op.cmd = TMEM_AUTH;
117 op.pool_id = 0;
118 op.u.new.arg1 = cli_id;
119 op.u.new.flags = arg1;
120 if ( xc_tmem_uuid_parse(uuid_str, &op.u.new.uuid[0],
121 &op.u.new.uuid[1]) < 0 )
122 {
123 PERROR("Can't parse uuid, use xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
124 return -1;
125 }
127 return do_tmem_op(xc, &op);
128 }
130 /* Save/restore/live migrate */
132 /*
133 Note that live migration complicates the save/restore format in
134 multiple ways: Though saving/migration can only occur when all
135 tmem pools belonging to the domain-being-saved are frozen and
136 this ensures that new pools can't be created or existing pools
137 grown (in number of pages), it is possible during a live migration
138 that pools may be destroyed and pages invalidated while the migration
139 is in process. As a result, (1) it is not safe to pre-specify counts
140 for these values precisely, but only as a "max", and (2) a "invalidation"
141 list (of pools, objects, pages) must be appended when the domain is truly
142 suspended.
143 */
145 /* returns 0 if nothing to save, -1 if error saving, 1 if saved successfully */
146 int xc_tmem_save(int xc, int dom, int io_fd, int live, int field_marker)
147 {
148 int marker = field_marker;
149 int i, j;
150 uint32_t max_pools, version;
151 uint32_t weight, cap, flags;
152 uint32_t pool_id;
153 uint32_t minusone = -1;
154 struct tmem_handle *h;
156 if ( xc_tmem_control(xc,0,TMEMC_SAVE_BEGIN,dom,live,0,0,NULL) <= 0 )
157 return 0;
159 if ( write_exact(io_fd, &marker, sizeof(marker)) )
160 return -1;
161 version = xc_tmem_control(xc,0,TMEMC_SAVE_GET_VERSION,0,0,0,0,NULL);
162 if ( write_exact(io_fd, &version, sizeof(version)) )
163 return -1;
164 max_pools = xc_tmem_control(xc,0,TMEMC_SAVE_GET_MAXPOOLS,0,0,0,0,NULL);
165 if ( write_exact(io_fd, &max_pools, sizeof(max_pools)) )
166 return -1;
167 if ( version == -1 || max_pools == -1 )
168 return -1;
169 if ( write_exact(io_fd, &minusone, sizeof(minusone)) )
170 return -1;
171 flags = xc_tmem_control(xc,0,TMEMC_SAVE_GET_CLIENT_FLAGS,dom,0,0,0,NULL);
172 if ( write_exact(io_fd, &flags, sizeof(flags)) )
173 return -1;
174 weight = xc_tmem_control(xc,0,TMEMC_SAVE_GET_CLIENT_WEIGHT,dom,0,0,0,NULL);
175 if ( write_exact(io_fd, &weight, sizeof(weight)) )
176 return -1;
177 cap = xc_tmem_control(xc,0,TMEMC_SAVE_GET_CLIENT_CAP,dom,0,0,0,NULL);
178 if ( write_exact(io_fd, &cap, sizeof(cap)) )
179 return -1;
180 if ( flags == -1 || weight == -1 || cap == -1 )
181 return -1;
182 if ( write_exact(io_fd, &minusone, sizeof(minusone)) )
183 return -1;
184 for ( i = 0; i < max_pools; i++ )
185 {
186 uint64_t uuid[2];
187 uint32_t n_pages;
188 uint32_t pagesize;
189 char *buf = NULL;
190 int bufsize = 0;
191 int checksum = 0;
193 /* get pool id, flags, pagesize, n_pages, uuid */
194 flags = xc_tmem_control(xc,i,TMEMC_SAVE_GET_POOL_FLAGS,dom,0,0,0,NULL);
195 if ( flags != -1 )
196 {
197 pool_id = i;
198 n_pages = xc_tmem_control(xc,i,TMEMC_SAVE_GET_POOL_NPAGES,dom,0,0,0,NULL);
199 if ( !(flags & TMEM_POOL_PERSIST) )
200 n_pages = 0;
201 (void)xc_tmem_control(xc,i,TMEMC_SAVE_GET_POOL_UUID,dom,sizeof(uuid),0,0,&uuid);
202 if ( write_exact(io_fd, &pool_id, sizeof(pool_id)) )
203 return -1;
204 if ( write_exact(io_fd, &flags, sizeof(flags)) )
205 return -1;
206 if ( write_exact(io_fd, &n_pages, sizeof(n_pages)) )
207 return -1;
208 if ( write_exact(io_fd, &uuid, sizeof(uuid)) )
209 return -1;
210 if ( n_pages == 0 )
211 continue;
213 pagesize = 1 << (((flags >> TMEM_POOL_PAGESIZE_SHIFT) &
214 TMEM_POOL_PAGESIZE_MASK) + 12);
215 if ( pagesize > bufsize )
216 {
217 bufsize = pagesize + sizeof(struct tmem_handle);
218 if ( (buf = realloc(buf,bufsize)) == NULL )
219 return -1;
220 }
221 for ( j = n_pages; j > 0; j-- )
222 {
223 int ret;
224 if ( (ret = xc_tmem_control(xc, pool_id,
225 TMEMC_SAVE_GET_NEXT_PAGE, dom,
226 bufsize, 0, 0, buf)) > 0 )
227 {
228 h = (struct tmem_handle *)buf;
229 if ( write_exact(io_fd, &h->oid, sizeof(h->oid)) )
230 return -1;
231 if ( write_exact(io_fd, &h->index, sizeof(h->index)) )
232 return -1;
233 h++;
234 checksum += *(char *)h;
235 if ( write_exact(io_fd, h, pagesize) )
236 return -1;
237 } else if ( ret == 0 ) {
238 continue;
239 } else {
240 /* page list terminator */
241 h = (struct tmem_handle *)buf;
242 h->oid = -1;
243 if ( write_exact(io_fd, &h->oid, sizeof(h->oid)) )
244 return -1;
245 break;
246 }
247 }
248 DPRINTF("saved %d tmem pages for dom=%d pool=%d, checksum=%x\n",
249 n_pages-j,dom,pool_id,checksum);
250 }
251 }
252 /* pool list terminator */
253 minusone = -1;
254 if ( write_exact(io_fd, &minusone, sizeof(minusone)) )
255 return -1;
257 return 1;
258 }
260 /* only called for live migration */
261 int xc_tmem_save_extra(int xc, int dom, int io_fd, int field_marker)
262 {
263 struct tmem_handle handle;
264 int marker = field_marker;
265 uint32_t minusone;
266 int count = 0, checksum = 0;
268 if ( write_exact(io_fd, &marker, sizeof(marker)) )
269 return -1;
270 while ( xc_tmem_control(xc, 0, TMEMC_SAVE_GET_NEXT_INV, dom,
271 sizeof(handle),0,0,&handle) > 0 ) {
272 if ( write_exact(io_fd, &handle.pool_id, sizeof(handle.pool_id)) )
273 return -1;
274 if ( write_exact(io_fd, &handle.oid, sizeof(handle.oid)) )
275 return -1;
276 if ( write_exact(io_fd, &handle.index, sizeof(handle.index)) )
277 return -1;
278 count++;
279 checksum += handle.pool_id + handle.oid + handle.index;
280 }
281 if ( count )
282 DPRINTF("needed %d tmem invalidates, check=%d\n",count,checksum);
283 minusone = -1;
284 if ( write_exact(io_fd, &minusone, sizeof(minusone)) )
285 return -1;
286 return 0;
287 }
289 /* only called for live migration */
290 void xc_tmem_save_done(int xc, int dom)
291 {
292 xc_tmem_control(xc,0,TMEMC_SAVE_END,dom,0,0,0,NULL);
293 }
295 /* restore routines */
297 static int xc_tmem_restore_new_pool(
298 int xc,
299 int cli_id,
300 uint32_t pool_id,
301 uint32_t flags,
302 uint64_t uuid_lo,
303 uint64_t uuid_hi)
304 {
305 tmem_op_t op;
307 op.cmd = TMEM_RESTORE_NEW;
308 op.pool_id = pool_id;
309 op.u.new.arg1 = cli_id;
310 op.u.new.flags = flags;
311 op.u.new.uuid[0] = uuid_lo;
312 op.u.new.uuid[1] = uuid_hi;
314 return do_tmem_op(xc, &op);
315 }
317 int xc_tmem_restore(int xc, int dom, int io_fd)
318 {
319 uint32_t save_max_pools, save_version;
320 uint32_t this_max_pools, this_version;
321 uint32_t pool_id;
322 uint32_t minusone;
323 uint32_t weight, cap, flags;
324 int checksum = 0;
326 save_version = xc_tmem_control(xc,0,TMEMC_SAVE_GET_VERSION,dom,0,0,0,NULL);
327 if ( save_version == -1 )
328 return -1; /* domain doesn't exist */
329 save_max_pools = xc_tmem_control(xc,0,TMEMC_SAVE_GET_MAXPOOLS,0,0,0,0,NULL);
330 if ( read_exact(io_fd, &this_version, sizeof(this_version)) )
331 return -1;
332 if ( read_exact(io_fd, &this_max_pools, sizeof(this_max_pools)) )
333 return -1;
334 /* FIXME check here to ensure no version mismatch or maxpools mismatch */
335 if ( read_exact(io_fd, &minusone, sizeof(minusone)) )
336 return -1;
337 if ( minusone != -1 )
338 return -1;
339 if ( xc_tmem_control(xc,0,TMEMC_RESTORE_BEGIN,dom,0,0,0,NULL) < 0 )
340 return -1;
341 if ( read_exact(io_fd, &flags, sizeof(flags)) )
342 return -1;
343 if ( flags & TMEM_CLIENT_COMPRESS )
344 if ( xc_tmem_control(xc,0,TMEMC_SET_COMPRESS,dom,1,0,0,NULL) < 0 )
345 return -1;
346 if ( flags & TMEM_CLIENT_FROZEN )
347 if ( xc_tmem_control(xc,0,TMEMC_FREEZE,dom,0,0,0,NULL) < 0 )
348 return -1;
349 if ( read_exact(io_fd, &weight, sizeof(weight)) )
350 return -1;
351 if ( xc_tmem_control(xc,0,TMEMC_SET_WEIGHT,dom,0,0,0,NULL) < 0 )
352 return -1;
353 if ( read_exact(io_fd, &cap, sizeof(cap)) )
354 return -1;
355 if ( xc_tmem_control(xc,0,TMEMC_SET_CAP,dom,0,0,0,NULL) < 0 )
356 return -1;
357 if ( read_exact(io_fd, &minusone, sizeof(minusone)) )
358 return -1;
359 while ( read_exact(io_fd, &pool_id, sizeof(pool_id)) == 0 && pool_id != -1 )
360 {
361 uint64_t uuid[2];
362 uint32_t n_pages;
363 char *buf = NULL;
364 int bufsize = 0, pagesize;
365 int j;
367 if ( read_exact(io_fd, &flags, sizeof(flags)) )
368 return -1;
369 if ( read_exact(io_fd, &n_pages, sizeof(n_pages)) )
370 return -1;
371 if ( read_exact(io_fd, &uuid, sizeof(uuid)) )
372 return -1;
373 if ( xc_tmem_restore_new_pool(xc, dom, pool_id,
374 flags, uuid[0], uuid[1]) < 0)
375 return -1;
376 if ( n_pages <= 0 )
377 continue;
379 pagesize = 1 << (((flags >> TMEM_POOL_PAGESIZE_SHIFT) &
380 TMEM_POOL_PAGESIZE_MASK) + 12);
381 if ( pagesize > bufsize )
382 {
383 bufsize = pagesize;
384 if ( (buf = realloc(buf,bufsize)) == NULL )
385 return -1;
386 }
387 for ( j = n_pages; j > 0; j-- )
388 {
389 uint64_t oid;
390 uint32_t index;
391 int rc;
392 if ( read_exact(io_fd, &oid, sizeof(oid)) )
393 return -1;
394 if ( oid == -1 )
395 break;
396 if ( read_exact(io_fd, &index, sizeof(index)) )
397 return -1;
398 if ( read_exact(io_fd, buf, pagesize) )
399 return -1;
400 checksum += *buf;
401 if ( (rc = xc_tmem_control(xc, pool_id, TMEMC_RESTORE_PUT_PAGE,
402 dom, bufsize, index, oid, buf)) <= 0 )
403 {
404 DPRINTF("xc_tmem_restore: putting page failed, rc=%d\n",rc);
405 return -1;
406 }
407 }
408 if ( n_pages )
409 DPRINTF("restored %d tmem pages for dom=%d pool=%d, check=%x\n",
410 n_pages-j,dom,pool_id,checksum);
411 }
412 if ( pool_id != -1 )
413 return -1;
415 return 0;
416 }
418 /* only called for live migration, must be called after suspend */
419 int xc_tmem_restore_extra(int xc, int dom, int io_fd)
420 {
421 uint32_t pool_id;
422 uint64_t oid;
423 uint32_t index;
424 int count = 0;
425 int checksum = 0;
427 while ( read_exact(io_fd, &pool_id, sizeof(pool_id)) == 0 && pool_id != -1 )
428 {
429 if ( read_exact(io_fd, &oid, sizeof(oid)) )
430 return -1;
431 if ( read_exact(io_fd, &index, sizeof(index)) )
432 return -1;
433 if ( xc_tmem_control(xc, pool_id, TMEMC_RESTORE_FLUSH_PAGE, dom,
434 0,index,oid,NULL) <= 0 )
435 return -1;
436 count++;
437 checksum += pool_id + oid + index;
438 }
439 if ( pool_id != -1 )
440 return -1;
441 if ( count )
442 DPRINTF("invalidated %d tmem pages, check=%d\n",count,checksum);
444 return 0;
445 }
447 /*
448 * Local variables:
449 * mode: C
450 * c-set-style: "BSD"
451 * c-basic-offset: 4
452 * tab-width: 4
453 * indent-tabs-mode: nil
454 * End:
455 */