xenpaging fixes for xen-unstable
PATCH 1/1 xenpaging fixes for xen-unstable
The following series adds support for xenpaging to libxl and the xl command. A few code cleanup changes are also part of this series.
The logic of xenpaging was reversed.
It does now monitor the guests tot_pages value and work toward that number by either paging out more pages, or write pages back into the guest.
Three new configuration file options specific for xenpaging were added:
totmem=<int>
xenpaging_file=<string>
xenpaging_extra=[ 'string', 'string' ]
A new xl command 'mem-tot_pages' instructs xenpaging to adjust its pagefile size, and it instructs the xl monitor process to actually start xenpaging if totmem= was not specified in the config file.
Please review and apply.
Olaf
Config.mk | 2 config/StdGNU.mk | 2 tools/libxc/xc_bitops.h | 6 tools/libxl/libxl.c | 121 +++++++++ tools/libxl/libxl.h | 5 tools/libxl/libxl_create.c | 146 +++++++++++ tools/libxl/libxl_device.c | 84 ------ tools/libxl/libxl_dm.c | 65 +---- tools/libxl/libxl_dom.c | 8 tools/libxl/libxl_exec.c | 142 +++++++++++ tools/libxl/libxl_internal.h | 33 ++ tools/libxl/libxl_paths.c | 5 tools/libxl/libxl_types.idl | 4 tools/libxl/xl.h | 1 tools/libxl/xl_cmdimpl.c | 71 +++++ tools/libxl/xl_cmdtable.c | 5 tools/xenpaging/Makefile | 6 tools/xenpaging/file_ops.c | 6 tools/xenpaging/policy_default.c | 23 + tools/xenpaging/xenpaging.c | 479 ++++++++++++++++++++++++++++----------- tools/xenpaging/xenpaging.h | 8 21 files changed, 934 insertions(+), 288 deletions(-)
PATCH 1/1 xenpaging: remove filename from comment
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653595 -7200
# Node ID f2c4a25eec9ce1fcba0efb26ef21711929cca47c # Parent e78cd03b0308c3ba5737ba9821bf7272f45549ca
xenpaging: remove filename from comment
tools/xenpaging/file_ops.c +0 -1
@@ -1,5 +1,4 @@/****************************************************************************** -* tools/xenpaging/file_ops.c * * Common file operations. *
tools/xenpaging/policy_default.c +0 -1
@@ -1,5 +1,4 @@/****************************************************************************** -* tools/xenpaging/policy.c * * Xen domain paging default policy. *
tools/xenpaging/xenpaging.c +0 -1
@@ -1,5 +1,4 @@/****************************************************************************** -* tools/xenpaging/xenpaging.c * * Domain paging. * Copyright (c) 2009 by Citrix Systems, Inc. (Patrick Colp)
PATCH 1/1 xenpaging: remove obsolete comment in resume path
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653596 -7200
# Node ID 21b7c9a6545ac1ec9d91fce83d46aab0b5808b05 # Parent f2c4a25eec9ce1fcba0efb26ef21711929cca47c
xenpaging: remove obsolete comment in resume path
Remove stale comment.
If a page was populated several times the vcpu is paused and xenpaging has to unpause it again.
tools/xenpaging/xenpaging.c +0 -1
@@ -742,7 +742,6 @@ int main(int argc, char *argv[]) req.gfn, req.flags & MEM_EVENT_FLAG_VCPU_PAUSED);/* Tell Xen to resume the vcpu */ -/* XXX: Maybe just check if the vcpu was paused? */ if ( req.flags &MEM_EVENT_FLAG_VCPU_PAUSED ) {/* Prepare the response */
PATCH 1/1 xenpaging: use PERROR to print errno
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653597 -7200
# Node ID ee4c4c7699e0de2b6bddce1e816d35f36ffb0470 # Parent 21b7c9a6545ac1ec9d91fce83d46aab0b5808b05
xenpaging: use PERROR to print errno
Also catch lseek() errors in file_op().
tools/xenpaging/file_ops.c +5 -0
@@ -37,6 +37,11 @@ static int file_op(int fd, void *page, iint ret; seek_ret =lseek (fd, i <<PAGE_SHIFT ,SEEK_SET ); +if (seek_ret ==-1 ) + { + ret = -errno; + goto err; + } total =0 ;while ( total <PAGE_SIZE )
tools/xenpaging/xenpaging.c +31 -31
241 lines not on this page · raw message
PATCH 1/1 xenpaging: update xenpaging_init
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653599 -7200
# Node ID cef74f38274df3bf619f9b4f80d2843dd033fea5 # Parent ee4c4c7699e0de2b6bddce1e816d35f36ffb0470
xenpaging: update xenpaging_init
Move comment about xc_handle to the right place.
Allocate paging early and use calloc.
tools/xenpaging/xenpaging.c +11 -11
@@ -169,18 +169,21 @@ static xenpaging_t *xenpaging_init(domidchar *p;int rc; +/* Allocate memory */ + paging =calloc (1 ,sizeof (xenpaging_t)); +if ( !paging ) + goto err; +if (getenv ("XENPAGING_DEBUG" ) ) dbg = (xentoollog_logger *)xtl_createlogger_stdiostream (stderr,XTL_DEBUG ,0 ); - xch =xc_interface_open (dbg,NULL ,0 ); + +/* Open connection to xen */ + paging->xc_handle = xch =xc_interface_open (dbg,NULL ,0 );if ( !xch ) - goto err_iface; + goto err;DPRINTF ("xenpaging init\n" ); -/* Allocate memory */ - paging =malloc (sizeof (xenpaging_t)); -memset (paging,0 ,sizeof (xenpaging_t)); -/* Open connection to xenstore */ paging->xs_handle =xs_open (0 );if ( paging->xs_handle ==NULL )
@@ -204,9 +207,6 @@ static xenpaging_t *xenpaging_init(domidDPRINTF ("Setting policy mru_size to %d\n" , paging->policy_mru_size); } -/* Open connection to xen */ - paging->xc_handle = xch; -/* Set domain id */ paging->mem_event.domain_id = domain_id;
@@ -319,7 +319,8 @@ static xenpaging_t *xenpaging_init(domid {if ( paging->xs_handle )xs_close (paging->xs_handle); -xc_interface_close (xch); +if ( xch ) +xc_interface_close (xch);if ( paging->mem_event.shared_page ) {munlock (paging->mem_event.shared_page,PAGE_SIZE );
@@ -337,7 +338,6 @@ static xenpaging_t *xenpaging_init(domidfree (paging); } - err_iface:return NULL ; }
PATCH 1/1 xenpaging: remove xc_dominfo_t from paging_t
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653600 -7200
# Node ID 003ad7aa543db226db53760549a172dcff236672 # Parent cef74f38274df3bf619f9b4f80d2843dd033fea5
xenpaging: remove xc_dominfo_t from paging_t
Remove xc_dominfo_t from paging_t, record only max_pages. This value is used to setup internal data structures.
tools/xenpaging/policy_default.c +4 -4
@@ -41,17 +41,17 @@ int policy_init(xenpaging_t *paging)int i;int rc = -ENOMEM ; + max_pages = paging->max_pages; +/* Allocate bitmap for pages not to page out */ - bitmap =bitmap_alloc (paging->domain_info->max_pages); + bitmap =bitmap_alloc (max_pages);if ( !bitmap ) goto out;/* Allocate bitmap to track unusable pages */ - unconsumed =bitmap_alloc (paging->domain_info->max_pages); + unconsumed =bitmap_alloc (max_pages);if ( !unconsumed ) goto out; - max_pages = paging->domain_info->max_pages; -/* Initialise MRU list of paged in pages */ if ( paging->policy_mru_size >0 ) mru_size = paging->policy_mru_size;
tools/xenpaging/xenpaging.c +11 -16
@@ -164,6 +164,7 @@ static void *init_page(void)static xenpaging_t *xenpaging_init (domid_t domain_id,int num_pages) {xenpaging_t *paging; +xc_domaininfo_t domain_info;xc_interface *xch;xentoollog_logger *dbg =NULL ;char *p;
@@ -272,34 +273,29 @@ static xenpaging_t *xenpaging_init(domid paging->mem_event.port = rc; -/* Get domaininfo */ - paging->domain_info =malloc (sizeof (xc_domaininfo_t)); -if ( paging->domain_info ==NULL ) - { -PERROR ("Error allocating memory for domain info" ); - goto err; - } - rc =xc_domain_getinfolist (xch, paging->mem_event.domain_id,1 , - paging->domain_info); + &domain_info);if ( rc !=1 ) {PERROR ("Error getting domain info" ); goto err; } +/* Record number of max_pages */ + paging->max_pages = domain_info.max_pages; +/* Allocate bitmap for tracking pages that have been paged out */ - paging->bitmap =bitmap_alloc (paging->domain_info->max_pages); + paging->bitmap =bitmap_alloc (paging->max_pages);if ( !paging->bitmap ) {PERROR ("Error allocating bitmap" ); goto err; } -DPRINTF ("max_pages = %" PRIx64"\n" , paging->domain_info->max_pages); +DPRINTF ("max_pages = %d\n" , paging->max_pages); -if ( num_pages <0 || num_pages > paging->domain_info->max_pages ) +if ( num_pages <0 || num_pages > paging->max_pages ) { - num_pages = paging->domain_info->max_pages; + num_pages = paging->max_pages;DPRINTF ("setting num_pages to %d\n" , num_pages); } paging->num_pages = num_pages;
@@ -334,7 +330,6 @@ static xenpaging_t *xenpaging_init(domid }free (paging->bitmap); -free (paging->domain_info);free (paging); }
@@ -763,7 +758,7 @@ int main(int argc, char *argv[])if ( interrupted ==SIGTERM || interrupted ==SIGINT ) {int num =0 ; -for ( i =0 ; i < paging->domain_info->max_pages; i++ ) +for ( i =0 ; i < paging->max_pages; i++ ) {if (test_bit (i, paging->bitmap) ) {
@@ -779,7 +774,7 @@ int main(int argc, char *argv[])*/ if ( num )page_in_trigger (); -else if ( i == paging->domain_info->max_pages ) +else if ( i == paging->max_pages )break ; }else
tools/xenpaging/xenpaging.h +2 -2
@@ -44,11 +44,11 @@ typedef struct xenpaging {xc_interface *xc_handle;struct xs_handle *xs_handle; -xc_domaininfo_t *domain_info; -unsigned long *bitmap;mem_event_t mem_event; +/* number of pages for which data structures were allocated */ +int max_pages;int num_pages;int policy_mru_size;unsigned long pagein_queue[XENPAGING_PAGEIN_QUEUE_SIZE ];
PATCH 1/1 xenpaging: track the number of paged-out pages
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653601 -7200
# Node ID 363c2f3df22b27d56297fa96f8d1706e224a323e # Parent 003ad7aa543db226db53760549a172dcff236672
xenpaging: track the number of paged-out pages
This change is required by subsequent changes.
tools/xenpaging/xenpaging.c +8 -0
@@ -467,6 +467,9 @@ static int xenpaging_evict_page(xenpagin/* Notify policy of page being paged out */ policy_notify_paged_out (victim->gfn); +/* Record number of evicted pages */ + paging->num_paged_out++; + out:return ret; }
@@ -480,8 +483,13 @@ static int xenpaging_resume_page(xenpagi/* Notify policy of page being paged in */ if ( notify_policy ) + {policy_notify_paged_in (rsp->gfn); +/* Record number of resumed pages */ + paging->num_paged_out--; + } +/* Tell Xen page is ready */ ret =xc_mem_paging_resume (paging->xc_handle, paging->mem_event.domain_id, rsp->gfn);
tools/xenpaging/xenpaging.h +1 -0
@@ -49,6 +49,7 @@ typedef struct xenpaging {mem_event_t mem_event;/* number of pages for which data structures were allocated */ int max_pages; +int num_paged_out;int num_pages;int policy_mru_size;unsigned long pagein_queue[XENPAGING_PAGEIN_QUEUE_SIZE ];
PATCH 1/1 xenpaging: move page add/resume loops into its own function
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653603 -7200
# Node ID 02453d6279baad46b1388267639892feaf6d56af # Parent 363c2f3df22b27d56297fa96f8d1706e224a323e
xenpaging: move page add/resume loops into its own function.
Move page resume loop into its own function.
Move page eviction loop into its own function.
Allocate all possible slots in a paging file to allow growing and shrinking of the number of paged-out pages. Adjust other places to iterate over all slots.
This change is required by subsequent patches.
v2:
- check if victims allocation succeeded
tools/xenpaging/xenpaging.c +61 -33
@@ -553,6 +553,27 @@ static int xenpaging_populate_page(xenpareturn ret; } +/* Trigger a page-in for a batch of pages */ +static void resume_pages (xenpaging_t *paging,int num_pages) +{ +xc_interface *xch = paging->xc_handle; +int i, num =0 ; + +for ( i =0 ; i < paging->max_pages && num < num_pages; i++ ) + { +if (test_bit (i, paging->bitmap) ) + { + paging->pagein_queue[num] = i; + num++; +if ( num ==XENPAGING_PAGEIN_QUEUE_SIZE ) +break ; + } + } +/* num may be less than num_pages, caller has to try again */ +if ( num ) +page_in_trigger (); +} +static int evict_victim (xenpaging_t *paging,xenpaging_victim_t *victim,int fd,int i) {
@@ -596,6 +617,30 @@ static int evict_victim(xenpaging_t *pagreturn ret; } +/* Evict a batch of pages and write them to a free slot in the paging file */ +static int evict_pages (xenpaging_t *paging,int fd,xenpaging_victim_t *victims,int num_pages) +{ +xc_interface *xch = paging->xc_handle; +int rc, slot, num =0 ; + +for ( slot =0 ; slot < paging->max_pages && num < num_pages; slot++ ) + { +/* Slot is allocated */ +if ( victims[slot].gfn !=INVALID_MFN ) +continue ; + + rc =evict_victim (paging, &victims[slot], fd, slot); +if ( rc == -ENOSPC ) +break ; +if ( rc == -EINTR ) +break ; +if ( num && num %100 ==0 ) +DPRINTF ("%d pages evicted\n" , num); + num++; + } +return num; +} +int main (int argc,char *argv[]) {struct sigaction act;
@@ -638,7 +683,14 @@ int main(int argc, char *argv[])return 2 ; } - victims =calloc (paging->num_pages,sizeof (xenpaging_victim_t)); +/* Allocate upper limit of pages to allow growing and shrinking */ + victims =calloc (paging->max_pages,sizeof (xenpaging_victim_t)); +if ( !victims ) + goto out; + +/* Mark all slots as unallocated */ +for ( i =0 ; i < paging->max_pages; i++ ) + victims[i].gfn =INVALID_MFN ;/* ensure that if we get a signal, we'll do cleanup, then exit */ act.sa_handler = close_handler;
@@ -652,18 +704,7 @@ int main(int argc, char *argv[])/* listen for page-in events to stop pager */ create_page_in_thread (paging); -/* Evict pages */ -for ( i =0 ; i < paging->num_pages; i++ ) - { - rc =evict_victim (paging, &victims[i], fd, i); -if ( rc == -ENOSPC ) -break ; -if ( rc == -EINTR ) -break ; -if ( i %100 ==0 ) -DPRINTF ("%d pages evicted\n" , i); - } - + i =evict_pages (paging, fd, victims, paging->num_pages);DPRINTF ("%d pages evicted. Done.\n" , i);/* Swap pages in and out */
@@ -689,13 +730,13 @@ int main(int argc, char *argv[])if (test_and_clear_bit (req.gfn, paging->bitmap) ) {/* Find where in the paging file to read from */ -for ( i =0 ; i < paging->num_pages; i++ ) +for ( i =0 ; i < paging->max_pages; i++ ) {if ( victims[i].gfn == req.gfn )break ; } -if ( i >= paging->num_pages ) +if ( i >= paging->max_pages ) {DPRINTF ("Couldn't find page %" PRIx64"\n" , req.gfn); goto out;
@@ -765,25 +806,12 @@ int main(int argc, char *argv[])/* Write all pages back into the guest */ if ( interrupted ==SIGTERM || interrupted ==SIGINT ) { -int num =0 ; -for ( i =0 ; i < paging->max_pages; i++ ) - { -if (test_bit (i, paging->bitmap) ) - { - paging->pagein_queue[num] = i; - num++; -if ( num ==XENPAGING_PAGEIN_QUEUE_SIZE ) -break ; - } - } -/* -* One more round if there are still pages to process. -* If no more pages to process, exit loop. -*/ -if ( num ) -page_in_trigger (); -else if ( i == paging->max_pages ) +/* If no more pages to process, exit loop. */ +if ( !paging->num_paged_out )break ; + +/* One more round if there are still pages to process. */ +resume_pages (paging, paging->num_paged_out); }else {
PATCH 1/1 xenpaging: compare both token and path when checking for @releaseDomain event
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653604 -7200
# Node ID 87cc0a717a5edc87411295ad0d5cf0b3366da0d3
# Parent 02453d6279baad46b1388267639892feaf6d56af
xenpaging: compare both token and path when checking for @releaseDomain event
Subsequent patches will use xenstored to store the numbers of pages xenpaging is suppose to page-out. A domain_id value could be misinterpreted as number of pages. Compare both path and token to recognize the @releaseDomain event.
Also add debug output to show received watch event.
tools/xenpaging/xenpaging.c +2 -1
@@ -101,7 +101,8 @@ static int xenpaging_wait_for_event_or_t vec =xs_read_watch (paging->xs_handle, &num);if ( vec ) { -if (strcmp (vec[XS_WATCH_TOKEN ], watch_token) ==0 ) +DPRINTF ("path '%s' token '%s'\n" , vec[XS_WATCH_PATH ], vec[XS_WATCH_TOKEN ]); +if (strcmp (vec[XS_WATCH_PATH ],"@releaseDomain" ) ==0 &&strcmp (vec[XS_WATCH_TOKEN ], watch_token) ==0 ) {/* If our guest disappeared, set interrupt flag and fall through */ if (xs_is_domain_introduced (paging->xs_handle, paging->mem_event.domain_id) == false )
PATCH 1/1 xenpaging: improve mainloop exit handling
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653605 -7200
# Node ID 5d2d87fb19e4749ca11d9d002ee5b44271594cb3 # Parent 87cc0a717a5edc87411295ad0d5cf0b3366da0d3
xenpaging: improve mainloop exit handling
Remove the if/else logic to exit from the in case a signal arrives. Update comments.
tools/xenpaging/xenpaging.c +9 -7
@@ -804,7 +804,7 @@ int main(int argc, char *argv[]) } } -/* Write all pages back into the guest */ +/* If interrupted, write all pages back into the guest */ if ( interrupted ==SIGTERM || interrupted ==SIGINT ) {/* If no more pages to process, exit loop. */
@@ -813,13 +813,15 @@ int main(int argc, char *argv[])/* One more round if there are still pages to process. */ resume_pages (paging, paging->num_paged_out); + +/* Resume main loop */ +continue ; } -else - { -/* Exit on any other signal */ -if ( interrupted ) -break ; - } + +/* Exit main loop on any other signal */ +if ( interrupted ) +break ; + }DPRINTF ("xenpaging got signal %d\n" , interrupted);
PATCH 1/1 libxc: add bitmap_clear function
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653607 -7200
# Node ID b85b2fa9a485cdd815eb9eb3e3a7794b462fa814 # Parent 5d2d87fb19e4749ca11d9d002ee5b44271594cb3
libxc: add bitmap_clear function
tools/libxc/xc_bitops.h +6 -0
@@ -4,6 +4,7 @@/* bitmap operations for single threaded access */ #include <stdlib.h> +#include <string.h> #define BITS_PER_LONG (sizeof(unsigned long) * 8)#define ORDER_LONG (sizeof(unsigned long) == 4 ? 5 : 6)
@@ -25,6 +26,11 @@ static inline unsigned long *bitmap_alloreturn calloc (1 ,bitmap_size (nr_bits)); } +static inline void bitmap_clear (unsigned long *addr,int nr_bits) +{ +memset (addr,0 ,bitmap_size (nr_bits)); +} +static inline int test_bit (int nr,volatile unsigned long *addr) {return (BITMAP_ENTRY (nr, addr) >>BITMAP_SHIFT (nr)) &1 ;
PATCH 1/1 xenpaging: retry unpageable gfns
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653608 -7200
# Node ID 3924c1ef71ee975b4556ca7766b730dfa3e12295 # Parent b85b2fa9a485cdd815eb9eb3e3a7794b462fa814
xenpaging: retry unpageable gfns
Nomination of gfns can fail, but may succeed later. Thats the case for a guest that starts ballooned.
tools/xenpaging/policy_default.c +13 -0
@@ -32,6 +32,7 @@ static unsigned int i_mru;static unsigned int mru_size;static unsigned long *bitmap;static unsigned long *unconsumed; +static unsigned int unconsumed_cleared;static unsigned long current_gfn;static unsigned long max_pages;
@@ -87,8 +88,20 @@ int policy_choose_victim(xenpaging_t *pa current_gfn++;if ( current_gfn >= max_pages ) current_gfn =0 ; +/* Could not nominate any gfn */ if ( wrap == current_gfn ) { +/* Count wrap arounds */ + unconsumed_cleared++; +/* Force retry every few seconds (depends on poll() timeout) */ +if ( unconsumed_cleared >123 ) + { +/* Force retry of unconsumed gfns */ +bitmap_clear (unconsumed, max_pages); + unconsumed_cleared =0 ; +/* One more round before returning ENOSPC */ +continue ; + } victim->gfn =INVALID_MFN ;return -ENOSPC ; }
PATCH 1/1 libxl: rename libxl__device_model_starting
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653609 -7200
# Node ID ea8738e045595a235fc05384d3f4d7c74537cd0a # Parent 3924c1ef71ee975b4556ca7766b730dfa3e12295
libxl: rename libxl__device_model_starting
tools/libxl/libxl_create.c +1 -1
@@ -434,7 +434,7 @@ static int do_domain_create(libxl__gc *g uint32_t *domid_out, int restore_fd) {libxl_ctx *ctx =libxl__gc_owner (gc); -libxl__device_model_starting *dm_starting =0 ; +libxl__spawner_starting *dm_starting =0 ;libxl_device_model_info *dm_info = &d_config->dm_info;libxl__domain_build_state state;uint32_t domid;
tools/libxl/libxl_dm.c +10 -10
@@ -518,7 +518,7 @@ static char ** libxl__build_device_modelstatic void dm_xenstore_record_pid (void *for_spawn,pid_t innerchild) { -libxl__device_model_starting *starting = for_spawn; +libxl__spawner_starting *starting = for_spawn;struct xs_handle *xsh;char *path =NULL , *pid =NULL ;int len;
@@ -619,7 +619,7 @@ static int libxl__create_stubdom(libxl__ libxl_device_nic *vifs, int num_vifs, libxl_device_vfb *vfb, libxl_device_vkb *vkb, - libxl__device_model_starting **starting_r) + libxl__spawner_starting **starting_r) { libxl_ctx *ctx = libxl__gc_owner(gc);int i, num_console =STUBDOM_SPECIAL_CONSOLES , ret;
@@ -631,7 +631,7 @@ static int libxl__create_stubdom(libxl__char **args;struct xs_permissions perm[2 ];xs_transaction_t t; -libxl__device_model_starting *dm_starting =0 ; +libxl__spawner_starting *dm_starting =0 ;libxl_device_model_info xenpv_dm_info;if (info->device_model_version !=LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL ) {
@@ -784,7 +784,7 @@ retry_transaction:libxl_domain_unpause (ctx, domid);if (starting_r) { - *starting_r =calloc (1 ,sizeof (libxl__device_model_starting)); + *starting_r =calloc (1 ,sizeof (libxl__spawner_starting)); (*starting_r)->domid = info->domid; (*starting_r)->dom_path =libxl__xs_get_dompath (gc, info->domid); (*starting_r)->for_spawn =NULL ;
@@ -802,14 +802,14 @@ int libxl__create_device_model(libxl__gc libxl_device_model_info *info, libxl_device_disk *disks, int num_disks, libxl_device_nic *vifs, int num_vifs, - libxl__device_model_starting **starting_r) + libxl__spawner_starting **starting_r) {libxl_ctx *ctx =libxl__gc_owner (gc);char *path, *logfile;int logfile_w, null;int rc;char **args; -libxl__device_model_starting buf_starting, *p; +libxl__spawner_starting buf_starting, *p;xs_transaction_t t;char *vm_path;char **pass_stuff;
@@ -861,7 +861,7 @@ int libxl__create_device_model(libxl__gcif (starting_r) { rc =ERROR_NOMEM ; - *starting_r =calloc (1 ,sizeof (libxl__device_model_starting)); + *starting_r =calloc (1 ,sizeof (libxl__spawner_starting));if (!*starting_r) goto out_close; p = *starting_r;
@@ -915,7 +915,7 @@ out: }static int detach_device_model (libxl__gc *gc, -libxl__device_model_starting *starting) +libxl__spawner_starting *starting) {int rc; rc =libxl__spawn_detach (gc, starting->for_spawn);
@@ -926,7 +926,7 @@ static int detach_device_model(libxl__gc }int libxl__confirm_device_model_startup (libxl__gc *gc, -libxl__device_model_starting *starting) +libxl__spawner_starting *starting) {int detach; int problem = libxl__wait_for_device_model(gc, starting->domid, "running",
@@ -1041,7 +1041,7 @@ out:int libxl__create_xenpv_qemu (libxl__gc *gc,uint32_t domid,libxl_device_model_info *info,libxl_device_vfb *vfb, -libxl__device_model_starting **starting_r) +libxl__spawner_starting **starting_r) {libxl__build_xenpv_qemu_args (gc, domid, vfb, info);libxl__create_device_model (gc, info,NULL ,0 ,NULL ,0 , starting_r);
tools/libxl/libxl_internal.h +5 -5
@@ -252,7 +252,7 @@ typedef struct {char *dom_path;/* from libxl_malloc, only for dm_xenstore_record_pid */ int domid;libxl__spawn_starting *for_spawn; -} libxl__device_model_starting; +} libxl__spawner_starting;/* from xl_create */ _hidden int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info, uint32_t *domid);
@@ -269,11 +269,11 @@ _hidden int libxl__create_device_model(l libxl_device_model_info *info, libxl_device_disk *disk, int num_disks, libxl_device_nic *vifs, int num_vifs, - libxl__device_model_starting **starting_r); + libxl__spawner_starting **starting_r); _hidden int libxl__create_xenpv_qemu(libxl__gc *gc, uint32_t domid,libxl_device_model_info *dm_info,libxl_device_vfb *vfb, -libxl__device_model_starting **starting_r); +libxl__spawner_starting **starting_r); _hidden int libxl__need_xenpv_qemu(libxl__gc *gc, int nr_consoles, libxl_device_console *consoles, int nr_vfbs, libxl_device_vfb *vfbs,
@@ -282,8 +282,8 @@ _hidden int libxl__need_xenpv_qemu(libxl* return pass *starting_r (which will be non-0) to * libxl_confirm_device_model or libxl_detach_device_model. */ _hidden int libxl__confirm_device_model_startup(libxl__gc *gc, -libxl__device_model_starting *starting); -_hidden int libxl__detach_device_model(libxl__gc *gc, libxl__device_model_starting *starting); +libxl__spawner_starting *starting); +_hidden int libxl__detach_device_model(libxl__gc *gc, libxl__spawner_starting *starting); _hidden int libxl__wait_for_device_model(libxl__gc *gc, uint32_t domid, char *state, libxl__spawn_starting *spawning,
PATCH 1/1 libxl: rename dm_xenstore_record_pid to libxl_spawner_record_pid
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653611 -7200
# Node ID df7be429654c62fb4c61f83549374d77b80ebea3
# Parent ea8738e045595a235fc05384d3f4d7c74537cd0a
libxl: rename dm_xenstore_record_pid to libxl_spawner_record_pid
tools/libxl/libxl_dm.c +1 -26
@@ -516,31 +516,6 @@ static char ** libxl__build_device_model } } -static void dm_xenstore_record_pid (void *for_spawn,pid_t innerchild) -{ -libxl__spawner_starting *starting = for_spawn; -struct xs_handle *xsh; -char *path =NULL , *pid =NULL ; -int len; - -if (asprintf (&path,"%s/%s" , starting->dom_path,"image/device-model-pid" ) <0 ) - goto out; - - len =asprintf (&pid,"%d" , innerchild); -if (len <0 ) - goto out; - -/* we mustn't use the parent's handle in the child */ - xsh =xs_daemon_open (); - -xs_write (xsh,XBT_NULL , path, pid, len); - -xs_daemon_close (xsh); -out: -free (path); -free (pid); -} - static int libxl__vfb_and_vkb_from_device_model_info(libxl__gc *gc, libxl_device_model_info *info, libxl_device_vfb *vfb,
@@ -896,7 +871,7 @@ retry_transaction: } rc =libxl__spawn_spawn (gc, p->for_spawn,"device model" , - dm_xenstore_record_pid, p); + libxl_spawner_record_pid, p);if (rc <0 ) goto out_close;if (!rc) {/* inner child */
tools/libxl/libxl_exec.c +25 -0
@@ -144,6 +144,31 @@ void libxl_report_child_exitstatus(libxl } } +void libxl_spawner_record_pid (void *for_spawn,pid_t innerchild) +{ +libxl__spawner_starting *starting = for_spawn; +struct xs_handle *xsh; +char *path =NULL , *pid =NULL ; +int len; + +if (asprintf (&path,"%s/%s" , starting->dom_path,"image/device-model-pid" ) <0 ) + goto out; + + len =asprintf (&pid,"%d" , innerchild); +if (len <0 ) + goto out; + +/* we mustn't use the parent's handle in the child */ + xsh =xs_daemon_open (); + +xs_write (xsh,XBT_NULL , path, pid, len); + +xs_daemon_close (xsh); +out: +free (path); +free (pid); +} +static int libxl__set_fd_flag (libxl__gc *gc,int fd,int flag) {int flags;
tools/libxl/libxl_internal.h +3 -1
@@ -249,7 +249,7 @@ typedef struct { } libxl__spawn_starting;typedef struct { -char *dom_path;/* from libxl_malloc, only for dm_xenstore_record_pid */ +char *dom_path;/* from libxl_malloc, only for libxl_spawner_record_pid */ int domid;libxl__spawn_starting *for_spawn; }libxl__spawner_starting ;
@@ -300,6 +300,8 @@ _hidden int libxl__spawn_spawn(libxl__gc void *hook_data); _hidden int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid); +_hidden void libxl_spawner_record_pid(void *for_spawn, pid_t innerchild); +/* Logs errors. A copy of "what" is taken. Return values: * < 0 error, for_spawn need not be detached * +1 caller is the parent, must call detach on *for_spawn eventually
PATCH 1/1 libxl: add pid path to libxl__spawner_starting
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653612 -7200
# Node ID 219ab93f22c0492595686a1cc34911e9d6775b07 # Parent df7be429654c62fb4c61f83549374d77b80ebea3
libxl: add pid path to libxl__spawner_starting
libxl_spawner_record_pid() should be able to write the pid to arbitrary paths.
tools/libxl/libxl_dm.c +1 -0
@@ -848,6 +848,7 @@ int libxl__create_device_model(libxl__gc p->domid = info->domid; p->dom_path =libxl__xs_get_dompath (gc, info->domid); + p->pid_path ="image/device-model-pid" ;if (!p->dom_path) { rc =ERROR_FAIL ; goto out_close;
tools/libxl/libxl_exec.c +1 -1
@@ -151,7 +151,7 @@ void libxl_spawner_record_pid(void *for_char *path =NULL , *pid =NULL ;int len; -if (asprintf (&path,"%s/%s" , starting->dom_path,"image/device-model-pid" ) <0 ) +if (asprintf (&path,"%s/%s" , starting->dom_path, starting->pid_path) <0 ) goto out; len =asprintf (&pid,"%d" , innerchild);
tools/libxl/libxl_internal.h +1 -0
@@ -250,6 +250,7 @@ typedef struct {typedef struct {char *dom_path;/* from libxl_malloc, only for libxl_spawner_record_pid */ +char *pid_path;/* from libxl_malloc, only for libxl_spawner_record_pid */ int domid;libxl__spawn_starting *for_spawn; }libxl__spawner_starting ;
PATCH 1/1 libxl: add libxl__wait_for_offspring function
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653613 -7200
# Node ID cfca4b1f83f9c2ebf1c1986aad51571243db4c77 # Parent 219ab93f22c0492595686a1cc34911e9d6775b07
libxl: add libxl__wait_for_offspring function
libxl__wait_for_offspring() is a generic version of libxl__wait_for_device_model().
tools/libxl/libxl_exec.c +93 -0
@@ -169,6 +169,99 @@ out:free (pid); } +int libxl__wait_for_offspring (libxl__gc *gc, +uint32_t domid, +uint32_t timeout,char *what, +char *path,char *state, +libxl__spawn_starting *spawning, +int (*check_callback)(libxl__gc *gc, +uint32_t domid, +const char *state, +void *userdata), +void *check_callback_userdata) +{ +libxl_ctx *ctx =libxl__gc_owner (gc); +char *p; +unsigned int len; +int rc =0 ; +struct xs_handle *xsh; +int nfds; +fd_set rfds; +struct timeval tv; +unsigned int num; +char **l =NULL ; + + xsh =xs_daemon_open (); +if (xsh ==NULL ) { +LIBXL__LOG (ctx,LIBXL__LOG_ERROR ,"Unable to open xenstore connection" ); + goto err; + } + +xs_watch (xsh, path, path); + tv.tv_sec = timeout; + tv.tv_usec =0 ; + nfds =xs_fileno (xsh) +1 ; +if (spawning && spawning->fd >xs_fileno (xsh)) + nfds = spawning->fd +1 ; + +while (rc >0 || (!rc && tv.tv_sec >0 )) { +if ( spawning ) { + rc =libxl__spawn_check (gc, spawning); +if ( rc ) { +LIBXL__LOG (ctx,LIBXL__LOG_ERROR , +"%s died during startup" , what); + rc =-1 ; + goto err_died; + } + } + p =xs_read (xsh,XBT_NULL , path, &len); +if (NULL == p ) + goto again; + +if (NULL != state &&strcmp (p, state) ) + goto again; + +if (NULL != check_callback ) { + rc = (*check_callback)(gc, domid, p, check_callback_userdata); +if ( rc >0 ) + goto again; + } + +free (p); +xs_unwatch (xsh, path, path); +xs_daemon_close (xsh); +return rc; +again: +free (p); +FD_ZERO (&rfds); +FD_SET (xs_fileno (xsh), &rfds); +if (spawning) +FD_SET (spawning->fd, &rfds); + rc =select (nfds, &rfds,NULL ,NULL , &tv); +if (rc >0 ) { +if (FD_ISSET (xs_fileno (xsh), &rfds)) { + l =xs_read_watch (xsh, &num); +if (l !=NULL ) +free (l); +else + goto again; + } +if (spawning &&FD_ISSET (spawning->fd, &rfds)) { +unsigned char dummy; +if (read (spawning->fd, &dummy,sizeof (dummy)) !=1 ) +LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_DEBUG , +"failed to read spawn status pipe" ); + } + } + } +LIBXL__LOG (ctx,LIBXL__LOG_ERROR ,"%s not ready" , what); +err_died: +xs_unwatch (xsh, path, path); +xs_daemon_close (xsh); +err: +return -1 ; +} +static int libxl__set_fd_flag (libxl__gc *gc,int fd,int flag) {int flags;
tools/libxl/libxl_internal.h +11 -1
@@ -303,6 +303,16 @@ _hidden int libxl__destroy_device_model( _hidden void libxl_spawner_record_pid(void *for_spawn, pid_t innerchild); +_hidden int libxl__wait_for_offspring(libxl__gc *gc, +uint32_t domid, +uint32_t timeout,char *what, +char *path,char *state, +libxl__spawn_starting *spawning, +int (*check_callback)(libxl__gc *gc, +uint32_t domid, +const char *state, +void *userdata), +void *check_callback_userdata);/* Logs errors. A copy of "what" is taken. Return values: * < 0 error, for_spawn need not be detached * +1 caller is the parent, must call detach on *for_spawn eventually
@@ -318,7 +328,7 @@ _hidden int libxl__spawn_check(libxl__gc/* Logs errors but also returns them. * for_spawn must actually be a libxl__spawn_starting* but * we take void* so you can pass this function directly to -* libxl__wait_for_device_model. Caller must still call detach. */ +* libxl__wait_for_offspring. Caller must still call detach. */ /* low-level stuff, for synchronous subprocesses etc. */
PATCH 1/1 libxl: use libxl__wait_for_offspring for device model
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653615 -7200
# Node ID 35ec0355b3283a87477c7377a2fd3da5e84d2bcd # Parent cfca4b1f83f9c2ebf1c1986aad51571243db4c77
libxl: use libxl__wait_for_offspring for device model
tools/libxl/libxl_device.c +4 -80
@@ -535,88 +535,12 @@ int libxl__wait_for_device_model(libxl__ void *userdata), void *check_callback_userdata) { - libxl_ctx *ctx = libxl__gc_owner(gc); char *path; -char *p; -unsigned int len; -int rc =0 ; -struct xs_handle *xsh; -int nfds; -fd_set rfds; -struct timeval tv; -unsigned int num; -char **l =NULL ; - - xsh =xs_daemon_open (); -if (xsh ==NULL ) { -LIBXL__LOG (ctx,LIBXL__LOG_ERROR ,"Unable to open xenstore connection" ); - goto err; - } - path =libxl__sprintf (gc,"/local/domain/0/device-model/%d/state" , domid); -xs_watch (xsh, path, path); - tv.tv_sec =LIBXL_DEVICE_MODEL_START_TIMEOUT ; - tv.tv_usec =0 ; - nfds =xs_fileno (xsh) +1 ; -if (spawning && spawning->fd >xs_fileno (xsh)) - nfds = spawning->fd +1 ; - -while (rc >0 || (!rc && tv.tv_sec >0 )) { -if ( spawning ) { - rc =libxl__spawn_check (gc, spawning); -if ( rc ) { -LIBXL__LOG (ctx,LIBXL__LOG_ERROR , -"Device Model died during startup" ); - rc =-1 ; - goto err_died; - } - } - p =xs_read (xsh,XBT_NULL , path, &len); -if (NULL == p ) - goto again; - -if (NULL != state &&strcmp (p, state) ) - goto again; - -if (NULL != check_callback ) { - rc = (*check_callback)(gc, domid, p, check_callback_userdata); -if ( rc >0 ) - goto again; - } - -free (p); -xs_unwatch (xsh, path, path); -xs_daemon_close (xsh); -return rc; -again: -free (p); -FD_ZERO (&rfds); -FD_SET (xs_fileno (xsh), &rfds); -if (spawning) -FD_SET (spawning->fd, &rfds); - rc =select (nfds, &rfds,NULL ,NULL , &tv); -if (rc >0 ) { -if (FD_ISSET (xs_fileno (xsh), &rfds)) { - l =xs_read_watch (xsh, &num); -if (l !=NULL ) -free (l); -else - goto again; - } -if (spawning &&FD_ISSET (spawning->fd, &rfds)) { -unsigned char dummy; -if (read (spawning->fd, &dummy,sizeof (dummy)) !=1 ) -LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_DEBUG , -"failed to read spawn status pipe" ); - } - } - } -LIBXL__LOG (ctx,LIBXL__LOG_ERROR ,"Device Model not ready" ); -err_died: -xs_unwatch (xsh, path, path); -xs_daemon_close (xsh); -err: -return -1 ; +return libxl__wait_for_offspring (gc, domid, +LIBXL_DEVICE_MODEL_START_TIMEOUT , +"Device Model" , path, state, spawning, + check_callback, check_callback_userdata); }int libxl__wait_for_backend (libxl__gc *gc,char *be_path,char *state)
PATCH 1/1 libxl: add libxl__spawn_confirm_offspring_startup
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653616 -7200
# Node ID 018f63b6e4863faca16a832a5a34c6a6e7726cf7 # Parent 35ec0355b3283a87477c7377a2fd3da5e84d2bcd
libxl: add libxl__spawn_confirm_offspring_startup
libxl__spawn_confirm_offspring_startup() is a generic version of libxl__confirm_device_model_startup().
tools/libxl/libxl_exec.c +24 -0
@@ -262,6 +262,30 @@ err:return -1 ; } +static int detach_offspring (libxl__gc *gc, +libxl__spawner_starting *starting) +{ +int rc; + rc =libxl__spawn_detach (gc, starting->for_spawn); +if (starting->for_spawn) +free (starting->for_spawn); +free (starting); +return rc; +} + +int libxl__spawn_confirm_offspring_startup (libxl__gc *gc, +uint32_t timeout,char *what, +char *path,char *state, +libxl__spawner_starting *starting) +{ +int detach; +int problem =libxl__wait_for_offspring (gc, starting->domid, timeout, what, + path, state, + starting->for_spawn,NULL ,NULL ); + detach =detach_offspring (gc, starting); +return problem ? problem : detach; +} +static int libxl__set_fd_flag (libxl__gc *gc,int fd,int flag) {int flags;
tools/libxl/libxl_internal.h +6 -0
@@ -313,6 +313,12 @@ _hidden int libxl__wait_for_offspring(liconst char *state, void *userdata), void *check_callback_userdata); + +_hidden int libxl__spawn_confirm_offspring_startup(libxl__gc *gc, +uint32_t timeout,char *what, +char *path,char *state, +libxl__spawner_starting *starting); +/* Logs errors. A copy of "what" is taken. Return values: * < 0 error, for_spawn need not be detached * +1 caller is the parent, must call detach on *for_spawn eventually
PATCH 1/1 libxl: use libxl__spawn_confirm_offspring_startup for device model
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653617 -7200
# Node ID acc1ee9d0c10a961834029726d11227c2ff9e97b
# Parent 018f63b6e4863faca16a832a5a34c6a6e7726cf7
libxl: use libxl__spawn_confirm_offspring_startup for device model
tools/libxl/libxl_dm.c +6 -15
@@ -890,25 +890,16 @@ out:return rc; } -static int detach_device_model (libxl__gc *gc, -libxl__spawner_starting *starting) -{ -int rc; - rc =libxl__spawn_detach (gc, starting->for_spawn); -if (starting->for_spawn) -free (starting->for_spawn); -free (starting); -return rc; -}int libxl__confirm_device_model_startup (libxl__gc *gc,libxl__spawner_starting *starting) { -int detach; -int problem =libxl__wait_for_device_model (gc, starting->domid,"running" , - starting->for_spawn,NULL ,NULL ); - detach =detach_device_model (gc, starting); -return problem ? problem : detach; +char *path; +int domid = starting->domid; + path =libxl__sprintf (gc,"/local/domain/0/device-model/%d/state" , domid); +return libxl__spawn_confirm_offspring_startup (gc, +LIBXL_DEVICE_MODEL_START_TIMEOUT , +"Device Model" , path,"running" , starting); }int libxl__destroy_device_model (libxl__gc *gc,uint32_t domid)
PATCH 1/1 xenpaging: install into LIBEXEC dir
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653619 -7200
# Node ID f9b5da9bcffdd96dcae4a26ead0b9c26507711e4 # Parent acc1ee9d0c10a961834029726d11227c2ff9e97b
xenpaging: install into LIBEXEC dir
In preparation of upcoming libxl integration, move xenpaging binary from /usr/sbin/ to /usr/lib/xen/bin/
tools/xenpaging/Makefile +2 -2
@@ -24,8 +24,8 @@ xenpaging: $(OBJS) install: all $(INSTALL_DIR) $(DESTDIR)/var/lib/xen/xenpaging - $(INSTALL_DIR) $(DESTDIR)$(SBINDIR) - $(INSTALL_PROG) $(IBINS) $(DESTDIR)$(SBINDIR) + $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC) + $(INSTALL_PROG) $(IBINS) $(DESTDIR)$(LIBEXEC) clean: rm -f *.o *~ $(DEPS) xen TAGS $(IBINS) $(LIB)
PATCH 1/1 xenpaging: add XEN_PAGING_DIR / libxl_xenpaging_dir_path()
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653620 -7200
# Node ID 916749c1775b4435629c747afa4b38c8cbb7dd5b # Parent f9b5da9bcffdd96dcae4a26ead0b9c26507711e4
xenpaging: add XEN_PAGING_DIR / libxl_xenpaging_dir_path()
Config.mk +1 -1
@@ -138,7 +138,7 @@ define buildmakevars2file-closure $(foreach var, \ SBINDIR BINDIR LIBEXEC LIBDIR SHAREDIR PRIVATE_BINDIR \ XENFIRMWAREDIR XEN_CONFIG_DIR XEN_SCRIPT_DIR XEN_LOCK_DIR \ - XEN_RUN_DIR, \ + XEN_RUN_DIR XEN_PAGING_DIR, \ echo "$(var)=\"$($(var))\"" >>$(1).tmp;) \ $(call move-if-changed,$(1).tmp,$(1)) endef
config/StdGNU.mk +2 -0
@@ -53,10 +53,12 @@ ifeq ($(PREFIX),/usr) CONFIG_DIR = /etc XEN_LOCK_DIR = /var/lock XEN_RUN_DIR = /var/run/xen +XEN_PAGING_DIR = /var/lib/xen/xenpaging else CONFIG_DIR = $(PREFIX)/etc XEN_LOCK_DIR = $(PREFIX)/var/lock XEN_RUN_DIR = $(PREFIX)/var/run/xen +XEN_PAGING_DIR = $(PREFIX)/var/lib/xen/xenpaging endif SYSCONFIG_DIR = $(CONFIG_DIR)/$(CONFIG_LEAF_DIR)
tools/libxl/libxl.h +1 -0
@@ -538,6 +538,7 @@ const char *libxl_xen_config_dir_path(voconst char *libxl_xen_script_dir_path (void );const char *libxl_lock_dir_path (void );const char *libxl_run_dir_path (void ); +const char *libxl_xenpaging_dir_path (void );#endif /* LIBXL_H */
tools/libxl/libxl_paths.c +5 -0
@@ -69,3 +69,8 @@ const char *libxl_run_dir_path(void) {return XEN_RUN_DIR ; } + +const char *libxl_xenpaging_dir_path (void ) +{ +return XEN_PAGING_DIR ; +}
tools/xenpaging/Makefile +1 -1
@@ -23,7 +23,7 @@ xenpaging: $(OBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) install: all - $(INSTALL_DIR) $(DESTDIR)/var/lib/xen/xenpaging + $(INSTALL_DIR) $(DESTDIR)$(XEN_PAGING_DIR) $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC) $(INSTALL_PROG) $(IBINS) $(DESTDIR)$(LIBEXEC)
PATCH 1/1 xenpaging: use guests tot_pages as working target
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653622 -7200
# Node ID 8fa2067ed61105a0ae31939f0ca58b8921fc55d4 # Parent 916749c1775b4435629c747afa4b38c8cbb7dd5b
xenpaging: use guests tot_pages as working target
tools/xenpaging/policy_default.c +0 -1
@@ -71,7 +71,6 @@ int policy_init(xenpaging_t *paging)/* Start in the middle to avoid paging during BIOS startup */ current_gfn = max_pages /2 ; - current_gfn -= paging->num_pages /2 ; rc =0 ; out:
tools/xenpaging/xenpaging.c +60 -18
133 lines not on this page · raw message
tools/xenpaging/xenpaging.h +1 -1
@@ -50,7 +50,7 @@ typedef struct xenpaging {/* number of pages for which data structures were allocated */ int max_pages;int num_paged_out; -int num_pages; +int target_tot_pages;int policy_mru_size;unsigned long pagein_queue[XENPAGING_PAGEIN_QUEUE_SIZE ]; } xenpaging_t;
PATCH 1/1 xenpaging: watch the guests memory/target-tot_pages xenstore value
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317656685 -7200
# Node ID 59303aeb11d96c5c94da2e9feb2ef9728236f90d
# Parent 8fa2067ed61105a0ae31939f0ca58b8921fc55d4
xenpaging: watch the guests memory/target-tot_pages xenstore value
Subsequent patches will use xenstored to store the numbers of pages xenpaging is suppose to page-out.
Remove num_pages and use target_pages instead.
tools/xenpaging/xenpaging.c +50 -1
@@ -19,8 +19,10 @@*/ #define _XOPEN_SOURCE 600 +#define _GNU_SOURCE#include <inttypes.h> +#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h>
@@ -35,6 +37,10 @@#include "policy.h" #include "xenpaging.h" +/* Defines number of mfns a guest should use at a time, in KiB */ +#define WATCH_TARGETPAGES "memory/target-tot_pages" +static char *watch_target_tot_pages; +static char *dom_path;static char watch_token[16 ];static char filename[80 ];static int interrupted;
@@ -72,7 +78,7 @@ static int xenpaging_wait_for_event_or_t {xc_interface *xch = paging->xc_handle;xc_evtchn *xce = paging->mem_event.xce_handle; -char **vec; +char **vec, *val;unsigned int num;struct pollfd fd[2 ];int port;
@@ -112,6 +118,25 @@ static int xenpaging_wait_for_event_or_t rc =0 ; } } +else if (strcmp (vec[XS_WATCH_PATH ], watch_target_tot_pages) ==0 ) + { +int ret, target_tot_pages; + val =xs_read (paging->xs_handle,XBT_NULL , vec[XS_WATCH_PATH ],NULL ); +if ( val ) + { + ret =sscanf (val,"%d" , &target_tot_pages); +if ( ret >0 ) + { +/* KiB to pages */ + target_tot_pages >>=2 ; +if ( target_tot_pages <0 || target_tot_pages > paging->max_pages ) + target_tot_pages = paging->max_pages; + paging->target_tot_pages = target_tot_pages; +DPRINTF ("new target_tot_pages %d\n" , target_tot_pages); + } +free (val); + } + }free (vec); } }
@@ -217,6 +242,25 @@ static xenpaging_t *xenpaging_init(domid goto err; } +/* watch guests xenpaging directory */ + dom_path =xs_get_domain_path (paging->xs_handle, domain_id); +if ( !dom_path ) + { +PERROR ("Could not find domain path\n" ); + goto err; + } +if (asprintf (&watch_target_tot_pages,"%s/%s" , dom_path,WATCH_TARGETPAGES ) <0 ) + { +PERROR ("Could not alloc watch path\n" ); + goto err; + } +DPRINTF ("watching '%s'\n" , watch_target_tot_pages); +if (xs_watch (paging->xs_handle, watch_target_tot_pages,"" ) == false ) + { +PERROR ("Could not bind to xenpaging watch\n" ); + goto err; + } + p =getenv ("XENPAGING_POLICY_MRU_SIZE" );if ( p && *p ) {
@@ -340,6 +384,8 @@ static xenpaging_t *xenpaging_init(domidfree (paging->mem_event.ring_page); } +free (dom_path); +free (watch_target_tot_pages);free (paging->bitmap);free (paging); }
@@ -355,6 +401,9 @@ static int xenpaging_teardown(xenpaging_if ( paging ==NULL )return 0 ; +xs_unwatch (paging->xs_handle, watch_target_tot_pages,"" ); +xs_unwatch (paging->xs_handle,"@releaseDomain" , watch_token); + xch = paging->xc_handle; paging->xc_handle =NULL ;/* Tear down domain paging in Xen */
PATCH 1/1 xenpaging: add cmdline interface for pager
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317656694 -7200
# Node ID 5dd8e13e8222486bc09894dc3245c28a7e654d0a # Parent 59303aeb11d96c5c94da2e9feb2ef9728236f90d
xenpaging: add cmdline interface for pager
Introduce a cmdline handling for the pager. This simplifies libxl support, debug and mru_size are not passed via the environment anymore. The new interface looks like this:
xenpaging [options] -f <pagefile> <domain_id>
options:
-f <file> --pagefile=<file> pagefile to use. This option is required. -m <max_memkb> --max_memkb=<max_memkb> maximum amount of memory to handle. -r <num> --mru_size=<num> number of paged-in pages to keep in memory. -d --debug enable debug output. -h --help this output.
tools/xenpaging/xenpaging.c +106 -37
@@ -31,6 +31,7 @@#include <poll.h> #include <xc_private.h> #include <xs.h> +#include <getopt.h> #include "xc_bitops.h" #include "file_ops.h"
@@ -42,12 +43,12 @@static char *watch_target_tot_pages;static char *dom_path;static char watch_token[16 ]; -static char filename[80 ]; +static char *filename;static int interrupted;static void unlink_pagefile (void ) { -if ( filename[0 ] ) +if ( filename && filename[0 ] ) {unlink (filename); filename[0 ] ='\0' ;
@@ -202,11 +203,89 @@ static void *init_page(void)return NULL ; } -static xenpaging_t *xenpaging_init (domid_t domain_id,int target_tot_pages) +static void usage (void ) +{ +printf ("usage:\n\n" ); + +printf (" xenpaging [options] -f <pagefile> <domain_id>\n\n" ); + +printf ("options:\n" ); +printf (" -f <file> --pagefile=<file> pagefile to use. This option is required.\n" ); +printf (" -m <max_memkb> --max_memkb=<max_memkb> maximum amount of memory to handle.\n" ); +printf (" -r <num> --mru_size=<num> number of paged-in pages to keep in memory.\n" ); +printf (" -d --debug enable debug output.\n" ); +printf (" -h --help this output.\n" ); +} + +static int xenpaging_getopts (xenpaging_t *paging,int argc,char *argv[]) +{ +int ch; +static const char sopts[] ="hdf:m:r:" ; +static const struct option lopts[] = { + {"help" ,0 ,NULL ,'h' }, + {"debug" ,0 ,NULL ,'d' }, + {"pagefile" ,1 ,NULL ,'f' }, + {"mru_size" ,1 ,NULL ,'m' }, + { } + }; + +while ((ch =getopt_long (argc, argv, sopts, lopts,NULL )) !=-1 ) + { +switch (ch) { +case 'f' : + filename =strdup (optarg); +break ; +case 'm' : +/* KiB to pages */ + paging->max_pages =atoi (optarg) >>2 ; +break ; +case 'r' : + paging->policy_mru_size =atoi (optarg); +break ; +case 'd' : + paging->debug =1 ; +break ; +case 'h' : +case '?' : +usage (); +return 1 ; + } + } + + argv += optind; argc -= optind; + +/* Remaining argument is guest domain_id */ +if ( argc !=1 ) + { +printf ("Numerical <domain_id> value missing!\n" ); +usage (); +return 1 ; + } + +/* Path to pagefile is required */ +if ( !filename ) + { +printf ("Filename for pagefile missing!\n" ); +usage (); +return 1 ; + } + +/* Set domain id */ + paging->mem_event.domain_id =atoi (argv[0 ]); +if ( paging->mem_event.domain_id ==0 ) + { +printf ("Cannot page dom0!\n" ); +return 1 ; + } + +return 0 ; +} + +static xenpaging_t *xenpaging_init (int argc,char *argv[]) {xenpaging_t *paging;xc_domaininfo_t domain_info; -xc_interface *xch; +xc_interface *xch =NULL ;xentoollog_logger *dbg =NULL ;char *p;int rc;
@@ -216,7 +295,12 @@ static xenpaging_t *xenpaging_init(domidif ( !paging ) goto err; -if (getenv ("XENPAGING_DEBUG" ) ) +/* Get cmdline options and domain_id */ +if (xenpaging_getopts (paging, argc, argv) ) + goto err; + +/* Enable debug output */ +if ( paging->debug ) dbg = (xentoollog_logger *)xtl_createlogger_stdiostream (stderr,XTL_DEBUG ,0 );/* Open connection to xen */
@@ -235,7 +319,7 @@ static xenpaging_t *xenpaging_init(domid }/* write domain ID to watch so we can ignore other domain shutdowns */ -snprintf (watch_token,sizeof (watch_token),"%u" , domain_id); +snprintf (watch_token,sizeof (watch_token),"%u" , paging->mem_event.domain_id);if (xs_watch (paging->xs_handle,"@releaseDomain" , watch_token) == false ) {PERROR ("Could not bind to shutdown watch\n" );
@@ -243,7 +327,7 @@ static xenpaging_t *xenpaging_init(domid }/* watch guests xenpaging directory */ - dom_path =xs_get_domain_path (paging->xs_handle, domain_id); + dom_path =xs_get_domain_path (paging->xs_handle, paging->mem_event.domain_id);if ( !dom_path ) {PERROR ("Could not find domain path\n" );
@@ -261,16 +345,6 @@ static xenpaging_t *xenpaging_init(domid goto err; } - p =getenv ("XENPAGING_POLICY_MRU_SIZE" ); -if ( p && *p ) - { - paging->policy_mru_size =atoi (p); -DPRINTF ("Setting policy mru_size to %d\n" , paging->policy_mru_size); - } - -/* Set domain id */ - paging->mem_event.domain_id = domain_id; -/* Initialise shared page */ paging->mem_event.shared_page =init_page ();if ( paging->mem_event.shared_page ==NULL )
@@ -333,17 +407,21 @@ static xenpaging_t *xenpaging_init(domid paging->mem_event.port = rc; - rc =xc_domain_getinfolist (xch, paging->mem_event.domain_id,1 , - &domain_info); -if ( rc !=1 ) +/* Get max_pages from guest if not provided via cmdline */ +if ( !paging->max_pages ) { -PERROR ("Error getting domain info" ); - goto err; + rc =xc_domain_getinfolist (xch, paging->mem_event.domain_id,1 , + &domain_info); +if ( rc !=1 ) + { +PERROR ("Error getting domain info" ); + goto err; + } + +/* Record number of max_pages */ + paging->max_pages = domain_info.max_pages; } -/* Record number of max_pages */ - paging->max_pages = domain_info.max_pages; -/* Allocate bitmap for tracking pages that have been paged out */ paging->bitmap =bitmap_alloc (paging->max_pages);if ( !paging->bitmap )
@@ -353,8 +431,6 @@ static xenpaging_t *xenpaging_init(domid }DPRINTF ("max_pages = %d\n" , paging->max_pages); - paging->target_tot_pages = target_tot_pages; -/* Initialise policy */ rc =policy_init (paging);if ( rc !=0 )
@@ -719,25 +795,18 @@ int main(int argc, char *argv[])mode_t open_mode =S_IRUSR |S_IRGRP |S_IROTH |S_IWUSR |S_IWGRP |S_IWOTH ;int fd; -if ( argc !=3 ) - { -fprintf (stderr,"Usage: %s <domain_id> <tot_pages>\n" , argv[0 ]); -return -1 ; - } -/* Initialise domain paging */ - paging =xenpaging_init (atoi (argv[1 ]),atoi (argv[2 ])); + paging =xenpaging_init (argc, argv);if ( paging ==NULL ) { -fprintf (stderr,"Error initialising paging" ); +fprintf (stderr,"Error initialising paging\n" );return 1 ; } xch = paging->xc_handle; -DPRINTF ("starting %s %u %d\n" , argv[0 ], paging->mem_event.domain_id, paging->target_tot_pages); +DPRINTF ("starting %s for domain_id %u with pagefile %s\n" , argv[0 ], paging->mem_event.domain_id, filename);/* Open file */ -sprintf (filename,"page_cache_%u" , paging->mem_event.domain_id); fd =open (filename, open_flags, open_mode);if ( fd <0 ) {
tools/xenpaging/xenpaging.h +1 -0
@@ -52,6 +52,7 @@ typedef struct xenpaging {int num_paged_out;int target_tot_pages;int policy_mru_size; +int debug;unsigned long pagein_queue[XENPAGING_PAGEIN_QUEUE_SIZE ]; } xenpaging_t;
PATCH 1/1 xenpaging: libxl support
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317656695 -7200
# Node ID c37a41cf0bf05f183a9b167f307591ec69e770e4 # Parent 5dd8e13e8222486bc09894dc3245c28a7e654d0a
xenpaging: libxl support
Add support to libxl for starting xenpaging.
Its a huge patch and should be spit into totmem= and the actual xenpaging change.
The patch adds three new config options:
totmem=<int> , the number of pages
xenpaging_file=<string>, pagefile to use
xenpaging_extra=[ 'string', 'string' ], additional optional args for xenpaging
xl gets a new 'mem-tot_pages' command which modifies xenstore "memory/target-tot_pages" to notify the pager of a new target number and it instructs the xl monitor process to start the pager if the totmem= option was not in the config file.
tools/libxl/libxl.c +121 -0
@@ -626,6 +626,21 @@ out:return rc; } +int libxl_wait_for_target_tot_pages (libxl_ctx *ctx,uint32_t domid,libxl_waiter *waiter) +{ +libxl__gc gc =LIBXL_INIT_GC (ctx); +int rc =-1 ; +if (asprintf (&waiter->path,"%s/memory/target-tot_pages" ,libxl__xs_get_dompath (&gc, domid)) <0 ) + goto out; +if (asprintf (&waiter->token,"%d" ,LIBXL_EVENT_TYPE_XENPAGING ) <0 ) + goto out; +if (xs_watch (ctx->xsh, waiter->path, waiter->token) == true) + rc =0 ; +out: +libxl__free_all (&gc); +return rc; +} +int libxl_get_event (libxl_ctx *ctx,libxl_event *event) {unsigned int num;
@@ -2035,6 +2050,112 @@ out:return rc; } +int libxl_set_memory_tot_pages (libxl_ctx *ctx,uint32_t domid, +int32_t tot_pages_memkb,int relative) +{ +libxl__gc gc; +int rc, abort =0 ; +uint32_t memorykb, videoram; +uint32_t current_target_memkb =0 ; +uint32_t current_tot_pages_memkb, new_tot_pages_memkb; +char *memmax, *endptr, *videoram_s, *target, *tot_pages; +char *dompath; +xs_transaction_t t; + +if (domid ==0 ) { +LIBXL__LOG (ctx,LIBXL__LOG_ERROR ,"cannot set tot_pages for dom0.\n" ); +return ERROR_INVAL ; + } + + gc =LIBXL_INIT_GC (ctx); + dompath =libxl__xs_get_dompath (&gc, domid); + +retry_transaction: + rc =1 ; + t =xs_transaction_start (ctx->xsh); + + target =libxl__xs_read (&gc, t,libxl__sprintf (&gc, +"%s/memory/target" , dompath)); +if (!target) { +LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_ERROR , +"cannot get target memory info from %s/memory/target\n" , + dompath); + abort =1 ; + goto out; + }else { + current_target_memkb =strtoul (target, &endptr,10 ); +if (*endptr !='\0' ) { +LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_ERROR , +"invalid memory target %s from %s/memory/target\n" , + target, dompath); + abort =1 ; + goto out; + } + } + + videoram_s =libxl__xs_read (&gc, t,libxl__sprintf (&gc, +"%s/memory/videoram" , dompath)); + videoram = videoram_s ?atoi (videoram_s) :0 ; + + current_tot_pages_memkb = current_target_memkb + videoram; + tot_pages =libxl__xs_read (&gc, t,libxl__sprintf (&gc, +"%s/memory/target-tot_pages" , dompath)); +if (tot_pages) { + current_tot_pages_memkb =strtoul (tot_pages, &endptr,10 ); +if (*endptr !='\0' ) { +LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_ERROR , +"invalid tot_pages %s from %s/memory/target-tot_pages\n" , + tot_pages, dompath); + abort =1 ; + goto out; + } + } + memmax =libxl__xs_read (&gc, t,libxl__sprintf (&gc, +"%s/memory/static-max" , dompath)); +if (!memmax) { +LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_ERROR , +"cannot get memory info from %s/memory/static-max\n" , + dompath); + abort =1 ; + goto out; + } + memorykb =strtoul (memmax, &endptr,10 ); +if (*endptr !='\0' ) { +LIBXL__LOG_ERRNO (ctx,LIBXL__LOG_ERROR , +"invalid max memory %s from %s/memory/static-max\n" , + memmax, dompath); + abort =1 ; + goto out; + } + +if (relative) { +if (tot_pages_memkb <0 &&abs (tot_pages_memkb) > current_tot_pages_memkb) + new_tot_pages_memkb =0 ; +else + new_tot_pages_memkb = current_tot_pages_memkb + tot_pages_memkb; + }else + new_tot_pages_memkb = tot_pages_memkb; +if (new_tot_pages_memkb > memorykb) { +LIBXL__LOG (ctx,LIBXL__LOG_ERROR , +"memory_dynamic_max must be less than or equal to" +" memory_static_max\n" ); + abort =1 ; + goto out; + } + +libxl__xs_write (&gc, t,libxl__sprintf (&gc,"%s/memory/target-tot_pages" , + dompath),"%" PRIu32, new_tot_pages_memkb); + + rc =0 ; +out: +if (!xs_transaction_end (ctx->xsh, t, abort) && !abort) +if (errno ==EAGAIN ) + goto retry_transaction; + +libxl__free_all (&gc); +return rc; +} +int libxl_domain_need_memory (libxl_ctx *ctx,libxl_domain_build_info *b_info,libxl_device_model_info *dm_info,uint32_t *need_memkb) {
tools/libxl/libxl.h +4 -0
@@ -261,6 +261,7 @@ int libxl_init_dm_info(libxl_ctx *ctx,typedef int (*libxl_console_ready )(libxl_ctx *ctx,uint32_t domid,void *priv);int libxl_domain_create_new (libxl_ctx *ctx,libxl_domain_config *d_config,libxl_console_ready cb,void *priv,uint32_t *domid);int libxl_domain_create_restore (libxl_ctx *ctx,libxl_domain_config *d_config,libxl_console_ready cb,void *priv,uint32_t *domid,int restore_fd); +int libxl__create_xenpaging (libxl_ctx *ctx,libxl_domain_config *d_config,uint32_t domid,char *path);void libxl_domain_config_destroy (libxl_domain_config *d_config);int libxl_domain_suspend (libxl_ctx *ctx,libxl_domain_suspend_info *info,uint32_t domid,int fd);
@@ -312,6 +313,8 @@ int libxl_get_wait_fd(libxl_ctx *ctx, inint libxl_wait_for_domain_death (libxl_ctx *ctx,uint32_t domid,libxl_waiter *waiter);/* waiter is a preallocated array of num_disks libxl_waiter elements */ int libxl_wait_for_disk_ejects (libxl_ctx *ctx,uint32_t domid,libxl_device_disk *disks,int num_disks,libxl_waiter *waiter); +/* waiter is allocated by the caller */ +int libxl_wait_for_target_tot_pages (libxl_ctx *ctx,uint32_t domid,libxl_waiter *waiter);int libxl_get_event (libxl_ctx *ctx,libxl_event *event);int libxl_stop_waiting (libxl_ctx *ctx,libxl_waiter *waiter);int libxl_free_event (libxl_event *event);
@@ -352,6 +355,7 @@ int libxl_domain_core_dump(libxl_ctx *ctint libxl_domain_setmaxmem (libxl_ctx *ctx,uint32_t domid,uint32_t target_memkb);int libxl_set_memory_target (libxl_ctx *ctx,uint32_t domid,int32_t target_memkb,int relative,int enforce);int libxl_get_memory_target (libxl_ctx *ctx,uint32_t domid,uint32_t *out_target); +int libxl_set_memory_tot_pages (libxl_ctx *ctx,uint32_t domid,int32_t tot_pages_memkb,int relative);/* how much free memory in the system a domain needs to be built */ int libxl_domain_need_memory (libxl_ctx *ctx,libxl_domain_build_info *b_info,libxl_device_model_info *dm_info,uint32_t *need_memkb);
tools/libxl/libxl_create.c +144 -0
153 lines not on this page · raw message
tools/libxl/libxl_dom.c +5 -3
@@ -108,7 +108,7 @@ int libxl__build_post(libxl__gc *gc, uinif (info->cpuid !=NULL )libxl_cpuid_set (ctx, domid, info->cpuid); - ents =libxl__calloc (gc,12 + (info->max_vcpus *2 ) +2 ,sizeof (char *)); + ents =libxl__calloc (gc,14 + (info->max_vcpus *2 ) +2 ,sizeof (char *)); ents[0 ] ="memory/static-max" ; ents[1 ] =libxl__sprintf (gc,"%d" , info->max_memkb); ents[2 ] ="memory/target" ;
@@ -121,9 +121,11 @@ int libxl__build_post(libxl__gc *gc, uin ents[9 ] =libxl__sprintf (gc,"%" PRIu32, state->store_port); ents[10 ] ="store/ring-ref" ; ents[11 ] =libxl__sprintf (gc,"%lu" , state->store_mfn); + ents[12 ] ="memory/target-tot_pages" ; + ents[13 ] =libxl__sprintf (gc,"%d" , info->tot_memkb);for (i =0 ; i < info->max_vcpus; i++) { - ents[12 +(i*2 )] =libxl__sprintf (gc,"cpu/%d/availability" , i); - ents[12 +(i*2 )+1 ] = (i && info->cur_vcpus && !(info->cur_vcpus & (1 << i))) + ents[14 +(i*2 )] =libxl__sprintf (gc,"cpu/%d/availability" , i); + ents[14 +(i*2 )+1 ] = (i && info->cur_vcpus && !(info->cur_vcpus & (1 << i))) ?"offline" :"online" ; }
tools/libxl/libxl_types.idl +4 -0
@@ -78,6 +78,7 @@ libxl_action_on_shutdown = Enumeration(" libxl_event_type = Enumeration("event_type", [ (1, "DOMAIN_DEATH"), (2, "DISK_EJECT"), + (3, "XENPAGING"), ]) libxl_button = Enumeration("button", [
@@ -157,6 +158,7 @@ libxl_domain_build_info = Struct("domain ("tsc_mode", integer), ("max_memkb", uint32), ("target_memkb", uint32), + ("tot_memkb", uint32), ("video_memkb", uint32), ("shadow_memkb", uint32), ("disable_migrate", bool),
@@ -174,6 +176,8 @@ libxl_domain_build_info = Struct("domain ("vpt_align", bool), ("timer_mode", integer), ("nested_hvm", bool), + ("xenpaging_file", string), + ("xenpaging_extra", libxl_string_list), ])), ("pv", Struct(None, [("kernel", libxl_file_reference), ("slack_memkb", uint32),
tools/libxl/xl.h +1 -0
@@ -54,6 +54,7 @@ int main_vcpupin(int argc, char **argv);int main_vcpuset (int argc,char **argv);int main_memmax (int argc,char **argv);int main_memset (int argc,char **argv); +int main_mem_tot_pages (int argc,char **argv);int main_sched_credit (int argc,char **argv);int main_domid (int argc,char **argv);int main_domname (int argc,char **argv);
tools/libxl/xl_cmdimpl.c +70 -1
140 lines not on this page · raw message
tools/libxl/xl_cmdtable.c +5 -0
@@ -158,6 +158,11 @@ struct cmd_spec cmd_table[] = {"Set the current memory usage for a domain" ,"<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>" , }, + { "mem-totpages", + &main_mem_tot_pages,0 , +"Set the how much memory is assigned to a domain" , +"<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>" , + }, { "button-press", &main_button_press,0 , "Indicate an ACPI button press to the domain",
tools/xenpaging/xenpaging.c +21 -0
@@ -40,6 +40,8 @@/* Defines number of mfns a guest should use at a time, in KiB */ #define WATCH_TARGETPAGES "memory/target-tot_pages" +/* Defines startup confirmation */ +#define WATCH_STARTUP "xenpaging/state"static char *watch_target_tot_pages;static char *dom_path;static char watch_token[16 ];
@@ -777,6 +779,22 @@ static int evict_pages(xenpaging_t *pagireturn num; } +static int xenpaging_confirm_startup (xenpaging_t *paging) +{ +xc_interface *xch = paging->xc_handle; +char *path; +int len; + + len =asprintf (&path,"%s/%s" , dom_path,WATCH_STARTUP ); +if ( len <0 ) +return -1 ; +DPRINTF ("confirm startup '%s'\n" , path); + len =xs_write (paging->xs_handle,XBT_NULL , path,"running" , len); +DPRINTF ("confirm startup returned %d\n" , len); +free (path); +return 0 ; +} +int main (int argc,char *argv[]) {struct sigaction act;
@@ -835,6 +853,9 @@ int main(int argc, char *argv[])/* listen for page-in events to stop pager */ create_page_in_thread (paging); +/* Confirm startup to caller */ +xenpaging_confirm_startup (paging); +/* Swap pages in and out */ while (1 ) {
Re: [PATCH 14 of 24] libxl: add pid path to libxl__spawner_starting
In reply to Olaf HeringQuoted 38 lines · Olaf Hering
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653612 -7200
# Node ID219ab93f22c0492595686a1cc34911e9d6775b07# Parentdf7be429654c62fb4c61f83549374d77b80ebea3
libxl: add pid path tolibxl__spawner_starting
libxl_spawner_record_pid()should be able to write the pid to arbitrary paths.Signed-off-by Olaf Hering <[email protected]>diff -r
df7be429654c-r219ab93f22c0tools/libxl/libxl_dm.ctools/libxl/libxl_dm.c +1
-0@@ -848,6 +848,7 @@ int libxl__create_device_model(libxl__gc p->domid = info->domid; p->dom_path =libxl__xs_get_dompath (gc, info->domid); + p->pid_path ="image/device-model-pid" ;if (!p->dom_path) { rc =ERROR_FAIL ; goto out_close;diff -r
df7be429654c-r219ab93f22c0tools/libxl/libxl_exec.ctools/libxl/libxl_exec.c +1
-1@@ -151,7 +151,7 @@ void libxl_spawner_record_pid(void *for_char *path =NULL , *pid =NULL ;int len; -if (asprintf (&path,"%s/%s" , starting->dom_path,"image/device-model-pid" ) <0 ) +if (asprintf (&path,"%s/%s" , starting->dom_path, starting->pid_path) <0 ) goto out; len =asprintf (&pid,"%d" , innerchild);diff -r
df7be429654c-r219ab93f22c0tools/libxl/libxl_internal.h
tools/libxl/libxl_internal.h typedef struct { · line 253
Quoted 4 lines
tools/libxl/libxl_internal.h +1
-0@@ -250,6 +250,7 @@ typedef struct { typedef struct { char *dom_path; /* from libxl_malloc, only for libxl_spawner_record_pid */ + char *pid_path; /* from libxl_malloc, only for libxl_spawner_record_pid */
Either this new comment is true and you need a strdup() up above where you set it and a free() somewhere else (or use libxl__strdup()) or it is false and it should be removed and pid_path should be const char *.
I think the second option is sufficient for the current and new user you are about to add?
Ian.
Quoted 8 lines
tools/libxl/libxl_internal.h +0
-0int domid;libxl__spawn_starting *for_spawn; } libxl__spawner_starting;_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 14 of 24] libxl: add pid path to libxl__spawner_starting
Quoted 13 lines · Ian Campbell
tools/libxl/libxl_internal.h typedef struct { · line 253
Quoted 6 lines · Olaf Hering
+++
b/tools/libxl/libxl_internal.htools/libxl/libxl_internal.h +1
-0@@ -250,6 +250,7 @@ typedef struct { typedef struct { char *dom_path; /* from libxl_malloc, only for libxl_spawner_record_pid */ + char *pid_path; /* from libxl_malloc, only for libxl_spawner_record_pid */Either this new comment is true and you need a
strdup()up above where you set it and afree()somewhere else (or uselibxl__strdup()) or it is false and it should be removed andpid_pathshould be const char *.
Quoted 2 lines
I think the second option is sufficient for the current and new user you are about to add?
I duplicated the dom_path line without paying attention to the comment. A const char *pid_path; is sufficient.
Olaf
Quoted 7 lines · Olaf Hering
The following series adds support for xenpaging to libxl and the xl command. A few code cleanup changes are also part of this series.
The logic of xenpaging was reversed.
It does now monitor the gueststot_pagesvalue and work toward that number by either paging out more pages, or write pages back into the guest.
Quoted 8 lines
Three new configuration file options specific for xenpaging were added:
totmem=<int>
xenpaging_file=<string>
xenpaging_extra=[ 'string', 'string' ]A new xl command 'mem-tot_pages' instructs xenpaging to adjust its pagefile size, and it instructs the xl monitor process to actually start xenpaging if totmem= was not specified in the config file.
In general xl commands do not contain "_" but rather use "-". We also sometimes use a "-set" suffix too.
totmem is unfortunately not all that descriptive to an end user of what it does (which I think is a general problem we have with the memory related options).
Currently the xl config file options are:
memory = actual start of day RAM maxmem = max ram guest could balloon to (?)
How does POD fit in? Is it just maxmem-memory for HVM domains? (not really relevant for this discussion, more for completeness).
The associated command line options are:
mem-set (runtime equivalent of memory?)
mem-max (runtime equivalent of maxmem?)
Hmm, I was hoping that enumerating the existing options would make the name and semantics of the paging option magically pop into my head, I was wrong :-(
BTW tools/libxl/libxl_memory.txt should be patched by this series too, once we figure out what to call things.
The phrase "actual memory" is used in that document -- perhaps that is suitable terminology for totmem?
Ian.
Quoted 34 lines
Please review and apply.
Olaf
Config.mk | 2 config/StdGNU.mk | 2 tools/libxc/xc_bitops.h | 6 tools/libxl/libxl.c | 121 +++++++++ tools/libxl/libxl.h | 5 tools/libxl/libxl_create.c | 146 +++++++++++ tools/libxl/libxl_device.c | 84 ------ tools/libxl/libxl_dm.c | 65 +---- tools/libxl/libxl_dom.c | 8 tools/libxl/libxl_exec.c | 142 +++++++++++ tools/libxl/libxl_internal.h | 33 ++ tools/libxl/libxl_paths.c | 5 tools/libxl/libxl_types.idl | 4 tools/libxl/xl.h | 1 tools/libxl/xl_cmdimpl.c | 71 +++++ tools/libxl/xl_cmdtable.c | 5 tools/xenpaging/Makefile | 6 tools/xenpaging/file_ops.c | 6 tools/xenpaging/policy_default.c | 23 + tools/xenpaging/xenpaging.c | 479 ++++++++++++++++++++++++++++----------- tools/xenpaging/xenpaging.h | 8 21 files changed, 934 insertions(+), 288 deletions(-)_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Quoted 19 lines · Ian Campbell
totmem is unfortunately not all that descriptive to an end user of what it does (which I think is a general problem we have with the memory related options).
Currently the xl config file options are:
memory = actual start of day RAM maxmem = max ram guest could balloon to (?)How does POD fit in? Is it just maxmem-memory for HVM domains? (not really relevant for this discussion, more for completeness).
The associated command line options are:
mem-set (runtime equivalent of memory?)
mem-max (runtime equivalent of maxmem?)Hmm, I was hoping that enumerating the existing options would make the name and semantics of the paging option magically pop into my head, I was wrong :-(
Quoted 5 lines
BTW
tools/libxl/libxl_memory.txtshould be patched by this series too, once we figure out what to call things.The phrase "actual memory" is used in that document -- perhaps that is suitable terminology for totmem?
The naming of the various numbers is confusing, so far I could not come up with a better name than tot_pages.
"actual target" is close to what xenpaging leaves for the guest, the amount of video ram has to be substracted.
I think the code in libxl, xenstore and in my changes is not 100% consistent with the figure below. I have to wade through the individual members again and check if the math is correct in all places.
Olaf
/* === Domain memory breakdown: HVM guests ==================================
+ +----------+ +
| | shadow | |
| +----------+ |
overhead | | extra | |
| | external | |
| +----------+ + |
| | extra | | |
| | internal | | |
+ +----------+ + | | footprint
| | video | | | |
| +----------+ + + + | | xen |
| | | | guest OS | | | actual | maximum |
| | guest | | real RAM | | | target | |
| | | | | | build | | |
| +----------+ + | | start + | |
static | | paging | | | | |
maximum | +----------+ | + + +
| | | |
| | | |
| | balloon | | build
| | | | maximum
| | | |
+ +----------+ + extra internal = LIBXL_MAXMEM_CONSTANT extra external = LIBXL_HVM_EXTRA_MEMORY shadow = libxl_domain_build_info.shadow_memkb static maximum = libxl_domain_build_info.max_memkb video = libxl_domain_build_info.video_memkb build start = libxl_domain_build_info.target_memkb libxl_domain_setmaxmem -> xen maximum libxl_set_memory_target -> actual target
build maximum = RAM as seen inside the virtual machine
Increase/Decrease via memory hotplug of virtual hardware (?) xl mem-max (?)
build start = RAM usable by the guest OS
guest OS sees balloon driver as memory hog (?) Increase/Decrease via commands to the balloon driver xl mem-set
real RAM = RAM allocated for the guest
Increase/Decrease via commands to paging daemon xl mem-FOO
guest = real RAM
paging = virtual RAM / swap
balloon = will become real or virtual RAM after mem-set command
Quoted 2 lines · Ian Campbell
How does POD fit in? Is it just maxmem-memory for HVM domains? (not really relevant for this discussion, more for completeness).
I dont have much experince with PoD, and started just last week some testing with a ballooned guest. In my limited testing I found no obvious bugs. But I have to check the code what PoD really means for paged pages.
Olaf
Re: [PATCH 03 of 24] xenpaging: use PERROR to print errno
In reply to Olaf HeringQuoted 15 lines · Olaf Hering
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1317653597 -7200
# Node IDee4c4c7699e0de2b6bddce1e816d35f36ffb0470# Parent 21b7c9a6545ac1ec9d91fce83d46aab0b5808b05
xenpaging: use PERROR to print errnoAlso catch
lseek()errors infile_op().Signed-off-by Olaf Hering <[email protected]>diff -r
21b7c9a6545a-ree4c4c7699e0tools/xenpaging/file_ops.c
tools/xenpaging/file_ops.c static int file_op(int fd, void *page, i · line 44
Quoted 8 lines
tools/xenpaging/file_ops.c +5
-0@@ -37,6 +37,11 @@ static int file_op(int fd, void *page, i int ret; seek_ret = lseek(fd, i << PAGE_SHIFT, SEEK_SET); + if (seek_ret == -1) + { + ret = -errno; + goto err; + }
Wouldn't it be more idiomatic to make both this check and the other check in the function:
* check for seek_ret < 0 (rather than -1)
* make file_op() return -1
* Let the caller read errno? (Rather than returning -errno)?
Quoted 281 lines
tools/xenpaging/file_ops.c +0
-0total = 0; while ( total < PAGE_SIZE )diff -r
21b7c9a6545a-ree4c4c7699e0tools/xenpaging/xenpaging.ctools/xenpaging/xenpaging.c +3
-3@@ -90,7 +90,7 @@ static int xenpaging_wait_for_event_or_t if (errno == EINTR) return 0; - ERROR("Poll exited with an error"); + PERROR("Poll exited with an error"); return -errno; }@@ -121,7 +121,7 @@ static int xenpaging_wait_for_event_or_t port = xc_evtchn_pending(xce); if ( port == -1 ) { - ERROR("Failed to read port from event channel"); + PERROR("Failed to read port from event channel"); rc = -1; goto err; }@@ -129,7 +129,7 @@ static int xenpaging_wait_for_event_or_t rc = xc_evtchn_unmask(xce, port); if ( rc < 0 ) { - ERROR("Failed to unmask event channel port"); + PERROR("Failed to unmask event channel port"); } }err:
tools/xenpaging/xenpaging.c +4
-4@@ -185,7 +185,7 @@ static xenpaging_t *xenpaging_init(domid paging->xs_handle = xs_open(0); if ( paging->xs_handle == NULL ) { - ERROR("Error initialising xenstore connection"); + PERROR("Error initialising xenstore connection"); goto err; }@@ -193,7 +193,7 @@ static xenpaging_t *xenpaging_init(domid snprintf(watch_token, sizeof(watch_token), "%u", domain_id); if ( xs_watch(paging->xs_handle, "@releaseDomain", watch_token) == false ) { - ERROR("Could not bind to shutdown watch\n"); + PERROR("Could not bind to shutdown watch\n"); goto err; }@@ -214,7 +214,7 @@ static xenpaging_t *xenpaging_init(domid paging->mem_event.shared_page = init_page(); if ( paging->mem_event.shared_page == NULL ) { - ERROR("Error initialising shared page"); + PERROR("Error initialising shared page"); goto err; }@@ -222,7 +222,7 @@ static xenpaging_t *xenpaging_init(domid paging->mem_event.ring_page = init_page(); if ( paging->mem_event.ring_page == NULL ) { - ERROR("Error initialising ring page"); + PERROR("Error initialising ring page"); goto err; }@@ -240,13 +240,13 @@ static xenpaging_t *xenpaging_init(domid { switch ( errno ) {case EBUSY:
- ERROR("xenpaging is (or was) active on this domain");
+ PERROR("xenpaging is (or was) active on this domain"); break;
case ENODEV:
- ERROR("EPT not supported for this guest");
+ PERROR("EPT not supported for this guest"); break;
default:
- ERROR("Error initialising shared page: %s", strerror(errno));
+ PERROR("Error initialising shared page: %s", strerror(errno)); break;
}
goto err;tools/xenpaging/xenpaging.c +21
-21@@ -256,7 +256,7 @@ static xenpaging_t *xenpaging_init(domid paging->mem_event.xce_handle = xc_evtchn_open(NULL, 0); if ( paging->mem_event.xce_handle == NULL ) { - ERROR("Failed to open event channel"); + PERROR("Failed to open event channel"); goto err; }@@ -266,7 +266,7 @@ static xenpaging_t *xenpaging_init(domid paging->mem_event.shared_page->port); if ( rc < 0 ) { - ERROR("Failed to bind event channel"); + PERROR("Failed to bind event channel"); goto err; }@@ -276,7 +276,7 @@ static xenpaging_t *xenpaging_init(domid paging->domain_info = malloc(sizeof(xc_domaininfo_t)); if ( paging->domain_info == NULL ) { - ERROR("Error allocating memory for domain info"); + PERROR("Error allocating memory for domain info"); goto err; }@@ -284,7 +284,7 @@ static xenpaging_t *xenpaging_init(domid paging->domain_info); if ( rc != 1 ) { - ERROR("Error getting domain info"); + PERROR("Error getting domain info"); goto err; }@@ -292,7 +292,7 @@ static xenpaging_t *xenpaging_init(domid paging->bitmap = bitmap_alloc(paging->domain_info->max_pages); if ( !paging->bitmap ) { - ERROR("Error allocating bitmap"); + PERROR("Error allocating bitmap"); goto err; } DPRINTF("max_pages = %"PRIx64"\n", paging->domain_info->max_pages);@@ -308,7 +308,7 @@ static xenpaging_t *xenpaging_init(domid rc = policy_init(paging); if ( rc != 0 ) { - ERROR("Error initialising policy"); + PERROR("Error initialising policy"); goto err; }@@ -355,14 +355,14 @@ static int xenpaging_teardown(xenpaging_ rc = xc_mem_paging_disable(xch, paging->mem_event.domain_id); if ( rc != 0 ) { - ERROR("Error tearing down domain paging in xen"); + PERROR("Error tearing down domain paging in xen"); } /* Unbind VIRQ */ rc = xc_evtchn_unbind(paging->mem_event.xce_handle, paging->mem_event.port); if ( rc != 0 ) { - ERROR("Error unbinding event port"); + PERROR("Error unbinding event port"); } paging->mem_event.port = -1;@@ -370,7 +370,7 @@ static int xenpaging_teardown(xenpaging_ rc = xc_evtchn_close(paging->mem_event.xce_handle); if ( rc != 0 ) { - ERROR("Error closing event channel"); + PERROR("Error closing event channel"); } paging->mem_event.xce_handle = NULL;@@ -381,7 +381,7 @@ static int xenpaging_teardown(xenpaging_ rc = xc_interface_close(xch); if ( rc != 0 ) { - ERROR("Error closing connection to xen"); + PERROR("Error closing connection to xen"); } return 0;@@ -441,7 +441,7 @@ static int xenpaging_evict_page(xenpagin PROT_READ | PROT_WRITE, &gfn, 1); if ( page == NULL ) { - ERROR("Error mapping page"); + PERROR("Error mapping page"); goto out; }@@ -449,8 +449,8 @@ static int xenpaging_evict_page(xenpagin ret = write_page(fd, page, i); if ( ret != 0 ) { + PERROR("Error copying page"); munmap(page, PAGE_SIZE); - ERROR("Error copying page"); goto out; }@@ -464,7 +464,7 @@ static int xenpaging_evict_page(xenpagin victim->gfn); if ( ret != 0 ) { - ERROR("Error evicting page"); + PERROR("Error evicting page"); goto out; }@@ -520,7 +520,7 @@ static int xenpaging_populate_page(xenpa sleep(1); continue; } - ERROR("Error preparing for page in"); + PERROR("Error preparing for page in"); goto out_map; } }@@ -532,7 +532,7 @@ static int xenpaging_populate_page(xenpa PROT_READ | PROT_WRITE, &gfn, 1); if ( page == NULL ) { - ERROR("Error mapping page: page is null"); + PERROR("Error mapping page: page is null"); goto out_map; }@@ -540,7 +540,7 @@ static int xenpaging_populate_page(xenpa ret = read_page(fd, page, i); if ( ret != 0 ) { - ERROR("Error reading page"); + PERROR("Error reading page"); goto out; }@@ -579,7 +579,7 @@ static int evict_victim(xenpaging_t *pag { if ( j++ % 1000 == 0 ) if ( xenpaging_mem_paging_flush_ioemu_cache(paging) ) - ERROR("Error flushing ioemu cache"); + PERROR("Error flushing ioemu cache"); } } while ( ret );@@ -670,7 +670,7 @@ int main(int argc, char *argv[]) rc = xenpaging_wait_for_event_or_timeout(paging); if ( rc < 0 ) { - ERROR("Error getting event"); + PERROR("Error getting event"); goto out; } else if ( rc != 0 )@@ -710,7 +710,7 @@ int main(int argc, char *argv[]) rc = xenpaging_populate_page(paging, req.gfn, fd, i); if ( rc != 0 ) { - ERROR("Error populating page"); + PERROR("Error populating page"); goto out; } }@@ -723,7 +723,7 @@ int main(int argc, char *argv[]) rc = xenpaging_resume_page(paging, &rsp, 1); if ( rc != 0 ) { - ERROR("Error resuming page"); + PERROR("Error resuming page"); goto out; }@@ -752,7 +752,7 @@ int main(int argc, char *argv[]) rc = xenpaging_resume_page(paging, &rsp, 0); if ( rc != 0 ) { - ERROR("Error resuming"); + PERROR("Error resuming"); goto out; } }_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 03 of 24] xenpaging: use PERROR to print errno
Quoted 9 lines · George Dunlap
Quoted 6 lines · Olaf Hering
seek_ret=lseek(fd, i << PAGE_SHIFT, SEEK_SET);
+ if (seek_ret== -1)
+ {
+ ret = -errno;
+ goto err;
+ }
Quoted 3 lines
Wouldn't it be more idiomatic to make both this check and the other check in the function:
* check forseek_ret< 0 (rather than -1)
The man page said its -1, now that I read it again it says (off_t)-1, so my change above should be updated to comply with the man page.
Quoted 2 lines
* make
file_op()return -1
* Let the caller read errno? (Rather than returning -errno)?
Yes, I will change this in a new patch.
Olaf
Re: [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup
In reply to Olaf HeringOlaf Hering writes ("[Xen-devel] [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup"):
Quoted 4 lines
libxl: add
libxl__spawn_confirm_offspring_startup
libxl__spawn_confirm_offspring_startup()is a generic version oflibxl__confirm_device_model_startup().
Thanks but I think it would be better to refactor this to avoid the duplication of this code.
Ian.
Re: [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup
Quoted 8 lines · Ian Jackson
Olaf Hering writes ("[Xen-devel] [PATCH 17 of 24] libxl: add
libxl__spawn_confirm_offspring_startup"):Quoted 4 lines
libxl: add
libxl__spawn_confirm_offspring_startup
libxl__spawn_confirm_offspring_startup()is a generic version oflibxl__confirm_device_model_startup().Thanks but I think it would be better to refactor this to avoid the duplication of this code.
The new function is used in patch #18 of this series. Or do you have some other changes in mind?
Olaf
Re: [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup
Olaf Hering writes ("Re: [Xen-devel] [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup"):
Quoted 12 lines · Ian Jackson
Quoted 8 lines
Olaf Hering writes ("[Xen-devel] [PATCH 17 of 24] libxl: add
libxl__spawn_confirm_offspring_startup"):Quoted 4 lines
libxl: add
libxl__spawn_confirm_offspring_startup
libxl__spawn_confirm_offspring_startup()is a generic version oflibxl__confirm_device_model_startup().Thanks but I think it would be better to refactor this to avoid the duplication of this code.
The new function is used in patch #18 of this series. Or do you have some other changes in mind?
I mean that you should arrange to replace libxl__confirm_device_model_startup with your new function libxl__spawn_confirm_offspring_startup.
As it is you have made a copy of libxl__confirm_device_model_startup and lightly edited it. This is a cardinal sin in programming, known as "clone and hack".
Ian.
Re: [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup
Quoted 14 lines · Ian Jackson
Olaf Hering writes ("Re: [Xen-devel] [PATCH 17 of 24] libxl: add
libxl__spawn_confirm_offspring_startup"):Quoted 12 lines · Ian Jackson
Quoted 8 lines
Olaf Hering writes ("[Xen-devel] [PATCH 17 of 24] libxl: add
libxl__spawn_confirm_offspring_startup"):Quoted 4 lines
libxl: add
libxl__spawn_confirm_offspring_startup
libxl__spawn_confirm_offspring_startup()is a generic version oflibxl__confirm_device_model_startup().Thanks but I think it would be better to refactor this to avoid the duplication of this code.
The new function is used in patch #18 of this series. Or do you have some other changes in mind?
Quoted 7 lines
I mean that you should arrange to replace
libxl__confirm_device_model_startupwith your new functionlibxl__spawn_confirm_offspring_startup.As it is you have made a copy of
libxl__confirm_device_model_startupand lightly edited it. This is a cardinal sin in programming, known as "clone and hack".
I moved the device model specific functions and made them generic. Perhaps I should have merged the add+use patches (15+16 / 17+18) into a single change. Once all patches are applied I see no code duplication.
If you prefer I can send a series just for the spawn related changes in libxl.
Olaf
Re: [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup
Olaf Hering writes ("Re: [Xen-devel] [PATCH 17 of 24] libxl: add libxl__spawn_confirm_offspring_startup"):
Quoted 3 lines
I moved the device model specific functions and made them generic. Perhaps I should have merged the add+use patches (15+16 / 17+18) into a single change. Once all patches are applied I see no code duplication.
Oh, I see; I didn't spot that, I'm afraid. I'll look at it again.
Ian.