1be07b0acSJuan Quintela /* 2be07b0acSJuan Quintela * Postcopy migration for RAM 3be07b0acSJuan Quintela * 4be07b0acSJuan Quintela * Copyright 2013 Red Hat, Inc. and/or its affiliates 5be07b0acSJuan Quintela * 6be07b0acSJuan Quintela * Authors: 7be07b0acSJuan Quintela * Dave Gilbert <dgilbert@redhat.com> 8be07b0acSJuan Quintela * 9be07b0acSJuan Quintela * This work is licensed under the terms of the GNU GPL, version 2 or later. 10be07b0acSJuan Quintela * See the COPYING file in the top-level directory. 11be07b0acSJuan Quintela * 12be07b0acSJuan Quintela */ 13be07b0acSJuan Quintela #ifndef QEMU_POSTCOPY_RAM_H 14be07b0acSJuan Quintela #define QEMU_POSTCOPY_RAM_H 15be07b0acSJuan Quintela 16be07b0acSJuan Quintela /* Return true if the host supports everything we need to do postcopy-ram */ 1774c38cf7SPeter Xu bool postcopy_ram_supported_by_host(MigrationIncomingState *mis, 1874c38cf7SPeter Xu Error **errp); 19be07b0acSJuan Quintela 20be07b0acSJuan Quintela /* 21be07b0acSJuan Quintela * Make all of RAM sensitive to accesses to areas that haven't yet been written 22be07b0acSJuan Quintela * and wire up anything necessary to deal with it. 23be07b0acSJuan Quintela */ 242a7eb148SWei Yang int postcopy_ram_incoming_setup(MigrationIncomingState *mis); 25be07b0acSJuan Quintela 26be07b0acSJuan Quintela /* 27be07b0acSJuan Quintela * Initialise postcopy-ram, setting the RAM to a state where we can go into 28be07b0acSJuan Quintela * postcopy later; must be called prior to any precopy. 29be07b0acSJuan Quintela * called from ram.c's similarly named ram_postcopy_incoming_init 30be07b0acSJuan Quintela */ 31c136180cSDavid Hildenbrand int postcopy_ram_incoming_init(MigrationIncomingState *mis); 32be07b0acSJuan Quintela 33be07b0acSJuan Quintela /* 34be07b0acSJuan Quintela * At the end of a migration where postcopy_ram_incoming_init was called. 35be07b0acSJuan Quintela */ 36be07b0acSJuan Quintela int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis); 37be07b0acSJuan Quintela 38be07b0acSJuan Quintela /* 39be07b0acSJuan Quintela * Userfault requires us to mark RAM as NOHUGEPAGE prior to discard 40be07b0acSJuan Quintela * however leaving it until after precopy means that most of the precopy 41be07b0acSJuan Quintela * data is still THPd 42be07b0acSJuan Quintela */ 43be07b0acSJuan Quintela int postcopy_ram_prepare_discard(MigrationIncomingState *mis); 44be07b0acSJuan Quintela 45be07b0acSJuan Quintela /* 46be07b0acSJuan Quintela * Called at the start of each RAMBlock by the bitmap code. 47be07b0acSJuan Quintela */ 48810cf2bbSWei Yang void postcopy_discard_send_init(MigrationState *ms, const char *name); 49be07b0acSJuan Quintela 50be07b0acSJuan Quintela /* 51be07b0acSJuan Quintela * Called by the bitmap code for each chunk to discard. 52be07b0acSJuan Quintela * May send a discard message, may just leave it queued to 53be07b0acSJuan Quintela * be sent later. 54be07b0acSJuan Quintela * @start,@length: a range of pages in the migration bitmap in the 55be07b0acSJuan Quintela * RAM block passed to postcopy_discard_send_init() (length=1 is one page) 56be07b0acSJuan Quintela */ 57810cf2bbSWei Yang void postcopy_discard_send_range(MigrationState *ms, unsigned long start, 58810cf2bbSWei Yang unsigned long length); 59be07b0acSJuan Quintela 60be07b0acSJuan Quintela /* 61be07b0acSJuan Quintela * Called at the end of each RAMBlock by the bitmap code. 62810cf2bbSWei Yang * Sends any outstanding discard messages. 63be07b0acSJuan Quintela */ 64810cf2bbSWei Yang void postcopy_discard_send_finish(MigrationState *ms); 65be07b0acSJuan Quintela 66be07b0acSJuan Quintela /* 67be07b0acSJuan Quintela * Place a page (from) at (host) efficiently 68be07b0acSJuan Quintela * There are restrictions on how 'from' must be mapped, in general best 69be07b0acSJuan Quintela * to use other postcopy_ routines to allocate. 70be07b0acSJuan Quintela * returns 0 on success 71be07b0acSJuan Quintela */ 72be07b0acSJuan Quintela int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from, 738be4620bSAlexey Perevalov RAMBlock *rb); 74be07b0acSJuan Quintela 75be07b0acSJuan Quintela /* 76be07b0acSJuan Quintela * Place a zero page at (host) atomically 77be07b0acSJuan Quintela * returns 0 on success 78be07b0acSJuan Quintela */ 79be07b0acSJuan Quintela int postcopy_place_page_zero(MigrationIncomingState *mis, void *host, 808be4620bSAlexey Perevalov RAMBlock *rb); 81be07b0acSJuan Quintela 82bac3b212SJuan Quintela /* The current postcopy state is read/set by postcopy_state_get/set 83bac3b212SJuan Quintela * which update it atomically. 84bac3b212SJuan Quintela * The state is updated as postcopy messages are received, and 85bac3b212SJuan Quintela * in general only one thread should be writing to the state at any one 86bac3b212SJuan Quintela * time, initially the main thread and then the listen thread; 87bac3b212SJuan Quintela * Corner cases are where either thread finishes early and/or errors. 88bac3b212SJuan Quintela * The state is checked as messages are received to ensure that 89bac3b212SJuan Quintela * the source is sending us messages in the correct order. 90bac3b212SJuan Quintela * The state is also used by the RAM reception code to know if it 91bac3b212SJuan Quintela * has to place pages atomically, and the cleanup code at the end of 92bac3b212SJuan Quintela * the main thread to know if it has to delay cleanup until the end 93bac3b212SJuan Quintela * of postcopy. 94bac3b212SJuan Quintela */ 95bac3b212SJuan Quintela typedef enum { 96bac3b212SJuan Quintela POSTCOPY_INCOMING_NONE = 0, /* Initial state - no postcopy */ 97bac3b212SJuan Quintela POSTCOPY_INCOMING_ADVISE, 98bac3b212SJuan Quintela POSTCOPY_INCOMING_DISCARD, 99bac3b212SJuan Quintela POSTCOPY_INCOMING_LISTENING, 100bac3b212SJuan Quintela POSTCOPY_INCOMING_RUNNING, 101bac3b212SJuan Quintela POSTCOPY_INCOMING_END 102bac3b212SJuan Quintela } PostcopyState; 103bac3b212SJuan Quintela 104bac3b212SJuan Quintela PostcopyState postcopy_state_get(void); 105bac3b212SJuan Quintela /* Set the state and return the old state */ 106bac3b212SJuan Quintela PostcopyState postcopy_state_set(PostcopyState new_state); 107bac3b212SJuan Quintela 1089ab7ef9bSPeter Xu void postcopy_fault_thread_notify(MigrationIncomingState *mis); 1099ab7ef9bSPeter Xu 1101693c64cSDr. David Alan Gilbert /* 1111693c64cSDr. David Alan Gilbert * To be called once at the start before any device initialisation 1121693c64cSDr. David Alan Gilbert */ 1131693c64cSDr. David Alan Gilbert void postcopy_infrastructure_init(void); 1141693c64cSDr. David Alan Gilbert 1151693c64cSDr. David Alan Gilbert /* Add a notifier to a list to be called when checking whether the devices 1161693c64cSDr. David Alan Gilbert * can support postcopy. 1171693c64cSDr. David Alan Gilbert * It's data is a *PostcopyNotifyData 1181693c64cSDr. David Alan Gilbert * It should return 0 if OK, or a negative value on failure. 1191693c64cSDr. David Alan Gilbert * On failure it must set the data->errp to an error. 1201693c64cSDr. David Alan Gilbert * 1211693c64cSDr. David Alan Gilbert */ 1221693c64cSDr. David Alan Gilbert enum PostcopyNotifyReason { 1231693c64cSDr. David Alan Gilbert POSTCOPY_NOTIFY_PROBE = 0, 124d3dff7a5SDr. David Alan Gilbert POSTCOPY_NOTIFY_INBOUND_ADVISE, 1256864a7b5SDr. David Alan Gilbert POSTCOPY_NOTIFY_INBOUND_LISTEN, 12646343570SDr. David Alan Gilbert POSTCOPY_NOTIFY_INBOUND_END, 1271693c64cSDr. David Alan Gilbert }; 1281693c64cSDr. David Alan Gilbert 1291693c64cSDr. David Alan Gilbert struct PostcopyNotifyData { 1301693c64cSDr. David Alan Gilbert enum PostcopyNotifyReason reason; 1311693c64cSDr. David Alan Gilbert }; 1321693c64cSDr. David Alan Gilbert 1331693c64cSDr. David Alan Gilbert void postcopy_add_notifier(NotifierWithReturn *nn); 1341693c64cSDr. David Alan Gilbert void postcopy_remove_notifier(NotifierWithReturn *n); 1351693c64cSDr. David Alan Gilbert /* Call the notifier list set by postcopy_add_start_notifier */ 1361693c64cSDr. David Alan Gilbert int postcopy_notify(enum PostcopyNotifyReason reason, Error **errp); 1371693c64cSDr. David Alan Gilbert 138095c12a4SPeter Xu void postcopy_thread_create(MigrationIncomingState *mis, 139095c12a4SPeter Xu QemuThread *thread, const char *name, 140095c12a4SPeter Xu void *(*fn)(void *), int joinable); 141095c12a4SPeter Xu 14200fa4fc8SDr. David Alan Gilbert struct PostCopyFD; 14300fa4fc8SDr. David Alan Gilbert 14400fa4fc8SDr. David Alan Gilbert /* ufd is a pointer to the struct uffd_msg *TODO: more Portable! */ 14500fa4fc8SDr. David Alan Gilbert typedef int (*pcfdhandler)(struct PostCopyFD *pcfd, void *ufd); 146d488b349SDr. David Alan Gilbert /* Notification to wake, either on place or on reception of 147d488b349SDr. David Alan Gilbert * a fault on something that's already arrived (race) 148d488b349SDr. David Alan Gilbert */ 149d488b349SDr. David Alan Gilbert typedef int (*pcfdwake)(struct PostCopyFD *pcfd, RAMBlock *rb, uint64_t offset); 15000fa4fc8SDr. David Alan Gilbert 15100fa4fc8SDr. David Alan Gilbert struct PostCopyFD { 15200fa4fc8SDr. David Alan Gilbert int fd; 15300fa4fc8SDr. David Alan Gilbert /* Data to pass to handler */ 15400fa4fc8SDr. David Alan Gilbert void *data; 15500fa4fc8SDr. David Alan Gilbert /* Handler to be called whenever we get a poll event */ 15600fa4fc8SDr. David Alan Gilbert pcfdhandler handler; 157d488b349SDr. David Alan Gilbert /* Notification to wake shared client */ 158d488b349SDr. David Alan Gilbert pcfdwake waker; 15900fa4fc8SDr. David Alan Gilbert /* A string to use in error messages */ 16000fa4fc8SDr. David Alan Gilbert const char *idstr; 16100fa4fc8SDr. David Alan Gilbert }; 16200fa4fc8SDr. David Alan Gilbert 16300fa4fc8SDr. David Alan Gilbert /* Register a userfaultfd owned by an external process for 16400fa4fc8SDr. David Alan Gilbert * shared memory. 16500fa4fc8SDr. David Alan Gilbert */ 16600fa4fc8SDr. David Alan Gilbert void postcopy_register_shared_ufd(struct PostCopyFD *pcfd); 16700fa4fc8SDr. David Alan Gilbert void postcopy_unregister_shared_ufd(struct PostCopyFD *pcfd); 1683a4452d8Szhaolichang /* Call each of the shared 'waker's registered telling them of 169d488b349SDr. David Alan Gilbert * availability of a block. 170d488b349SDr. David Alan Gilbert */ 171d488b349SDr. David Alan Gilbert int postcopy_notify_shared_wake(RAMBlock *rb, uint64_t offset); 1725efc3564SDr. David Alan Gilbert /* postcopy_wake_shared: Notify a client ufd that a page is available 1735efc3564SDr. David Alan Gilbert * 1745efc3564SDr. David Alan Gilbert * Returns 0 on success 1755efc3564SDr. David Alan Gilbert * 1765efc3564SDr. David Alan Gilbert * @pcfd: Structure with fd, handler and name as above 1775efc3564SDr. David Alan Gilbert * @client_addr: Address in the client program, not QEMU 1785efc3564SDr. David Alan Gilbert * @rb: The RAMBlock the page is in 1795efc3564SDr. David Alan Gilbert */ 1805efc3564SDr. David Alan Gilbert int postcopy_wake_shared(struct PostCopyFD *pcfd, uint64_t client_addr, 1815efc3564SDr. David Alan Gilbert RAMBlock *rb); 182096bf4c8SDr. David Alan Gilbert /* Callback from shared fault handlers to ask for a page */ 183096bf4c8SDr. David Alan Gilbert int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb, 184096bf4c8SDr. David Alan Gilbert uint64_t client_addr, uint64_t offset); 18500fa4fc8SDr. David Alan Gilbert 18636f62f11SPeter Xu /* Hard-code channels for now for postcopy preemption */ 18736f62f11SPeter Xu enum PostcopyChannels { 18836f62f11SPeter Xu RAM_CHANNEL_PRECOPY = 0, 18936f62f11SPeter Xu RAM_CHANNEL_POSTCOPY = 1, 19036f62f11SPeter Xu RAM_CHANNEL_MAX, 19136f62f11SPeter Xu }; 19236f62f11SPeter Xu 1936720c2b3Smanish.mishra void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file); 194fc063a7bSPeter Xu void postcopy_preempt_setup(MigrationState *s); 1955655aab0SPeter Xu int postcopy_preempt_establish_channel(MigrationState *s); 19636f62f11SPeter Xu 197be07b0acSJuan Quintela #endif 198