debuggers.hg

view tools/xenpaging/xenpaging.c @ 20972:eb05347ac47a

tools/xenpaging: fix bug of Segmentation fault

Segmentation fault occurs in two situations:
1. argc is less than 3
2. xenpaging_init() fault

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 11 19:50:05 2010 +0000 (2010-02-11)
parents 0b138a019292
children 714a3152102c
line source
1 /******************************************************************************
2 * tools/xenpaging/xenpaging.c
3 *
4 * Domain paging.
5 * Copyright (c) 2009 by Citrix Systems, Inc. (Patrick Colp)
6 *
7 * This program 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.
11 *
12 * This program 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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <xc_private.h>
27 #include <xen/mem_event.h>
29 #include "bitops.h"
30 #include "spinlock.h"
31 #include "file_ops.h"
32 #include "xc.h"
34 #include "policy.h"
35 #include "xenpaging.h"
38 #if 0
39 #undef DPRINTF
40 #define DPRINTF(...) ((void)0)
41 #endif
44 static void *init_page(void)
45 {
46 void *buffer;
47 int ret;
49 /* Allocated page memory */
50 ret = posix_memalign(&buffer, PAGE_SIZE, PAGE_SIZE);
51 if ( ret != 0 )
52 goto out_alloc;
54 /* Lock buffer in memory so it can't be paged out */
55 ret = mlock(buffer, PAGE_SIZE);
56 if ( ret != 0 )
57 goto out_lock;
59 return buffer;
61 out_init:
62 munlock(buffer, PAGE_SIZE);
63 out_lock:
64 free(buffer);
65 out_alloc:
66 return NULL;
67 }
69 xenpaging_t *xenpaging_init(domid_t domain_id)
70 {
71 xenpaging_t *paging;
72 int rc;
74 DPRINTF("xenpaging init\n");
76 /* Allocate memory */
77 paging = malloc(sizeof(xenpaging_t));
78 memset(paging, 0, sizeof(xenpaging_t));
80 /* Open connection to xen */
81 paging->xc_handle = xc_interface_open();
82 if ( paging->xc_handle < 0 )
83 {
84 ERROR("Failed to open connection to Xen");
85 goto err;
86 }
88 /* Set domain id */
89 paging->mem_event.domain_id = domain_id;
91 /* Initialise shared page */
92 paging->mem_event.shared_page = init_page();
93 if ( paging->mem_event.shared_page == NULL )
94 {
95 ERROR("Error initialising shared page");
96 goto err;
97 }
99 /* Initialise ring page */
100 paging->mem_event.ring_page = init_page();
101 if ( paging->mem_event.ring_page == NULL )
102 {
103 ERROR("Error initialising shared page");
104 goto err;
105 }
107 /* Initialise ring */
108 SHARED_RING_INIT((mem_event_sring_t *)paging->mem_event.ring_page);
109 BACK_RING_INIT(&paging->mem_event.back_ring,
110 (mem_event_sring_t *)paging->mem_event.ring_page,
111 PAGE_SIZE);
113 /* Initialise lock */
114 mem_event_ring_lock_init(&paging->mem_event);
116 /* Initialise Xen */
117 rc = xc_mem_event_enable(paging->xc_handle, paging->mem_event.domain_id,
118 paging->mem_event.shared_page,
119 paging->mem_event.ring_page);
120 if ( rc != 0 )
121 {
122 ERROR("Error initialising shared page");
123 goto err;
124 }
126 /* Open event channel */
127 paging->mem_event.xce_handle = xc_evtchn_open();
128 if ( paging->mem_event.xce_handle < 0 )
129 {
130 ERROR("Failed to open event channel");
131 goto err;
132 }
134 /* Bind event notification */
135 rc = xc_evtchn_bind_interdomain(paging->mem_event.xce_handle,
136 paging->mem_event.domain_id,
137 paging->mem_event.shared_page->port);
138 if ( rc < 0 )
139 {
140 ERROR("Failed to bind event channel");
141 goto err;
142 }
144 paging->mem_event.port = rc;
146 /* Get platform info */
147 paging->platform_info = malloc(sizeof(xc_platform_info_t));
148 if ( paging->platform_info == NULL )
149 {
150 ERROR("Error allocating memory for platform info");
151 goto err;
152 }
154 rc = xc_get_platform_info(paging->xc_handle, domain_id,
155 paging->platform_info);
156 if ( rc != 1 )
157 {
158 ERROR("Error getting platform info");
159 goto err;
160 }
162 /* Get domaininfo */
163 paging->domain_info = malloc(sizeof(xc_domaininfo_t));
164 if ( paging->domain_info == NULL )
165 {
166 ERROR("Error allocating memory for domain info");
167 goto err;
168 }
170 rc = xc_domain_getinfolist(paging->xc_handle, domain_id, 1,
171 paging->domain_info);
172 if ( rc != 1 )
173 {
174 ERROR("Error getting domain info");
175 goto err;
176 }
178 /* Allocate bitmap for tracking pages that have been paged out */
179 paging->bitmap_size = (paging->domain_info->max_pages + BITS_PER_LONG) &
180 ~(BITS_PER_LONG - 1);
182 rc = alloc_bitmap(&paging->bitmap, paging->bitmap_size);
183 if ( rc != 0 )
184 {
185 ERROR("Error allocating bitmap");
186 goto err;
187 }
188 DPRINTF("max_pages = %"PRIx64"\n", paging->domain_info->max_pages);
190 /* Initialise policy */
191 rc = policy_init(paging);
192 if ( rc != 0 )
193 {
194 ERROR("Error initialising policy");
195 goto err;
196 }
198 return paging;
200 err:
201 if ( paging->bitmap )
202 free(paging->bitmap);
203 if ( paging->platform_info )
204 free(paging->platform_info);
205 if ( paging )
206 free(paging);
208 return NULL;
209 }
211 int xenpaging_teardown(xenpaging_t *paging)
212 {
213 int rc;
215 if ( paging == NULL )
216 return 0;
218 /* Tear down domain paging in Xen */
219 rc = xc_mem_event_disable(paging->xc_handle, paging->mem_event.domain_id);
220 if ( rc != 0 )
221 {
222 ERROR("Error tearing down domain paging in xen");
223 goto err;
224 }
226 /* Unbind VIRQ */
227 rc = xc_evtchn_unbind(paging->mem_event.xce_handle, paging->mem_event.port);
228 if ( rc != 0 )
229 {
230 ERROR("Error unbinding event port");
231 goto err;
232 }
233 paging->mem_event.port = -1;
235 /* Close event channel */
236 rc = xc_evtchn_close(paging->mem_event.xce_handle);
237 if ( rc != 0 )
238 {
239 ERROR("Error closing event channel");
240 goto err;
241 }
242 paging->mem_event.xce_handle = -1;
244 /* Close connection to Xen */
245 rc = xc_interface_close(paging->xc_handle);
246 if ( rc != 0 )
247 {
248 ERROR("Error closing connection to xen");
249 goto err;
250 }
251 paging->xc_handle = -1;
253 return 0;
255 err:
256 return -1;
257 }
259 static int get_request(mem_event_t *mem_event, mem_event_request_t *req)
260 {
261 mem_event_back_ring_t *back_ring;
262 RING_IDX req_cons;
264 mem_event_ring_lock(mem_event);
266 back_ring = &mem_event->back_ring;
267 req_cons = back_ring->req_cons;
269 /* Copy request */
270 memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req));
271 req_cons++;
273 /* Update ring */
274 back_ring->req_cons = req_cons;
275 back_ring->sring->req_event = req_cons + 1;
277 mem_event_ring_unlock(mem_event);
279 return 0;
280 }
282 static int put_response(mem_event_t *mem_event, mem_event_response_t *rsp)
283 {
284 mem_event_back_ring_t *back_ring;
285 RING_IDX rsp_prod;
287 mem_event_ring_lock(mem_event);
289 back_ring = &mem_event->back_ring;
290 rsp_prod = back_ring->rsp_prod_pvt;
292 /* Copy response */
293 memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp));
294 rsp_prod++;
296 /* Update ring */
297 back_ring->rsp_prod_pvt = rsp_prod;
298 RING_PUSH_RESPONSES(back_ring);
300 mem_event_ring_unlock(mem_event);
302 return 0;
303 }
305 int xenpaging_evict_page(xenpaging_t *paging, xenpaging_victim_t *victim, int fd, int i)
306 {
307 void *page;
308 unsigned long gfn;
309 int ret;
311 DECLARE_DOMCTL;
313 /* Map page */
314 gfn = victim->gfn;
315 ret = -EFAULT;
316 page = xc_map_foreign_pages(paging->xc_handle, victim->domain_id,
317 PROT_READ | PROT_WRITE, &gfn, 1);
318 if ( page == NULL )
319 {
320 ERROR("Error mapping page");
321 goto out;
322 }
324 /* Copy page */
325 ret = write_page(fd, page, i);
326 if ( ret != 0 )
327 {
328 munmap(page, PAGE_SIZE);
329 ERROR("Error copying page");
330 goto out;
331 }
333 /* Clear page */
334 memset(page, 0, PAGE_SIZE);
336 munmap(page, PAGE_SIZE);
338 /* Tell Xen to evict page */
339 ret = xc_mem_paging_evict(paging->xc_handle, paging->mem_event.domain_id,
340 victim->gfn);
341 if ( ret != 0 )
342 {
343 ERROR("Error evicting page");
344 goto out;
345 }
347 /* Notify policy of page being paged in */
348 policy_notify_paged_in(paging->mem_event.domain_id, victim->gfn);
350 out:
351 return ret;
352 }
354 int xenpaging_resume_page(xenpaging_t *paging, mem_event_response_t *rsp)
355 {
356 int ret;
358 /* Put the page info on the ring */
359 ret = put_response(&paging->mem_event, rsp);
360 if ( ret != 0 )
361 goto out;
363 /* Notify policy of page being paged in */
364 policy_notify_paged_in(paging->mem_event.domain_id, rsp->gfn);
366 /* Tell Xen page is ready */
367 ret = xc_mem_paging_resume(paging->xc_handle, paging->mem_event.domain_id,
368 rsp->gfn);
369 ret = xc_evtchn_notify(paging->mem_event.xce_handle,
370 paging->mem_event.port);
372 out:
373 return ret;
374 }
376 int xenpaging_populate_page(xenpaging_t *paging, unsigned long *gfn, int fd, int i)
377 {
378 void *page;
379 int ret;
381 /* Tell Xen to allocate a page for the domain */
382 ret = xc_mem_paging_prep(paging->xc_handle, paging->mem_event.domain_id,
383 *gfn);
384 if ( ret != 0 )
385 {
386 ERROR("Error preparing for page in");
387 goto out_map;
388 }
390 /* Map page */
391 ret = -EFAULT;
392 page = xc_map_foreign_pages(paging->xc_handle, paging->mem_event.domain_id,
393 PROT_READ | PROT_WRITE, gfn, 1);
394 if ( page == NULL )
395 {
396 ERROR("Error mapping page: page is null");
397 goto out_map;
398 }
400 /* Read page */
401 ret = read_page(fd, page, i);
402 if ( ret != 0 )
403 {
404 ERROR("Error reading page");
405 goto out;
406 }
408 out:
409 munmap(page, PAGE_SIZE);
410 out_map:
411 return ret;
412 }
414 static int evict_victim(xenpaging_t *paging, domid_t domain_id,
415 xenpaging_victim_t *victim, int fd, int i)
416 {
417 int j = 0;
418 int ret;
420 do
421 {
422 ret = policy_choose_victim(paging, domain_id, victim);
423 if ( ret != 0 )
424 {
425 ERROR("Error choosing victim");
426 goto out;
427 }
429 ret = xc_mem_paging_nominate(paging->xc_handle,
430 paging->mem_event.domain_id, victim->gfn);
431 if ( ret == 0 )
432 ret = xenpaging_evict_page(paging, victim, fd, i);
433 else
434 {
435 if ( j++ % 1000 == 0 )
436 if ( xc_mem_paging_flush_ioemu_cache(domain_id) )
437 ERROR("Error flushing ioemu cache");
438 }
439 }
440 while ( ret );
442 if ( test_and_set_bit(victim->gfn, paging->bitmap) )
443 ERROR("Page has been evicted before");
445 ret = 0;
447 out:
448 return ret;
449 }
451 int main(int argc, char *argv[])
452 {
453 domid_t domain_id;
454 int num_pages;
455 xenpaging_t *paging;
456 xenpaging_victim_t *victims;
457 mem_event_request_t req;
458 mem_event_response_t rsp;
459 int i;
460 int rc = -1, rc1;
462 int open_flags = O_CREAT | O_TRUNC | O_RDWR;
463 mode_t open_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
464 char filename[80];
465 int fd;
467 if ( argc != 3 ) {
468 fprintf(stderr, "Usage: %s <domain_id> <num_pages>\n", argv[0]);
469 return -1;
470 }
471 domain_id = atoi(argv[1]);
472 num_pages = atoi(argv[2]);
474 victims = calloc(num_pages, sizeof(xenpaging_victim_t));
476 /* Open file */
477 sprintf(filename, "page_cache_%d", domain_id);
478 fd = open(filename, open_flags, open_mode);
479 if ( fd < 0 )
480 {
481 perror("failed to open file");
482 return -1;
483 }
485 /* Seed random-number generator */
486 srand(time(NULL));
488 /* Initialise domain paging */
489 paging = xenpaging_init(domain_id);
490 if ( paging == NULL )
491 {
492 ERROR("Error initialising paging");
493 goto out;
494 }
496 /* Evict pages */
497 memset(victims, 0, sizeof(xenpaging_victim_t) * num_pages);
498 for ( i = 0; i < num_pages; i++ )
499 {
500 evict_victim(paging, domain_id, &victims[i], fd, i);
501 if ( i % 100 == 0 )
502 DPRINTF("%d pages evicted\n", i);
503 }
505 DPRINTF("pages evicted\n");
507 /* Swap pages in and out */
508 while ( 1 )
509 {
510 /* Wait for Xen to signal that a page needs paged in */
511 rc = xc_wait_for_event_or_timeout(paging->mem_event.xce_handle, 100);
512 if ( rc < -1 )
513 {
514 ERROR("Error getting event");
515 goto out;
516 }
517 else if ( rc != -1 )
518 {
519 DPRINTF("Got event from Xen\n");
520 }
522 while ( RING_HAS_UNCONSUMED_REQUESTS(&paging->mem_event.back_ring) )
523 {
524 rc = get_request(&paging->mem_event, &req);
525 if ( rc != 0 )
526 {
527 ERROR("Error getting request");
528 goto out;
529 }
531 /* Check if the page has already been paged in */
532 if ( test_and_clear_bit(req.gfn, paging->bitmap) )
533 {
534 /* Find where in the paging file to read from */
535 for ( i = 0; i < num_pages; i++ )
536 {
537 if ( (victims[i].domain_id == paging->mem_event.domain_id) &&
538 (victims[i].gfn == req.gfn) )
539 break;
540 }
542 if ( i >= num_pages )
543 {
544 DPRINTF("Couldn't find page %lx\n", req.gfn);
545 goto out;
546 }
548 /* Populate the page */
549 rc = xenpaging_populate_page(paging, &req.gfn, fd, i);
550 if ( rc != 0 )
551 {
552 ERROR("Error populating page");
553 goto out;
554 }
556 /* Prepare the response */
557 rsp.gfn = req.gfn;
558 rsp.p2mt = req.p2mt;
559 rsp.vcpu_id = req.vcpu_id;
560 rsp.flags = req.flags;
562 rc = xenpaging_resume_page(paging, &rsp);
563 if ( rc != 0 )
564 {
565 ERROR("Error resuming page");
566 goto out;
567 }
569 /* Evict a new page to replace the one we just paged in */
570 evict_victim(paging, domain_id, &victims[i], fd, i);
571 }
572 else
573 {
574 DPRINTF("page already populated (domain = %d; vcpu = %d;"
575 " gfn = %lx; paused = %"PRId64")\n",
576 paging->mem_event.domain_id, req.vcpu_id,
577 req.gfn, req.flags & MEM_EVENT_FLAG_VCPU_PAUSED);
579 /* Tell Xen to resume the vcpu */
580 /* XXX: Maybe just check if the vcpu was paused? */
581 if ( req.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
582 {
583 /* Prepare the response */
584 rsp.gfn = req.gfn;
585 rsp.p2mt = req.p2mt;
586 rsp.vcpu_id = req.vcpu_id;
587 rsp.flags = req.flags;
589 rc = xenpaging_resume_page(paging, &rsp);
590 if ( rc != 0 )
591 {
592 ERROR("Error resuming");
593 goto out;
594 }
595 }
596 }
597 }
598 }
600 out:
601 free(victims);
603 /* Tear down domain paging */
604 rc1 = xenpaging_teardown(paging);
605 if ( rc1 != 0 )
606 ERROR("Error tearing down paging");
608 if ( rc == 0 )
609 rc = rc1;
611 return rc;
612 }
615 /*
616 * Local variables:
617 * mode: C
618 * c-set-style: "BSD"
619 * c-basic-offset: 4
620 * indent-tabs-mode: nil
621 * End:
622 */