exec: ram_block_discard_range
Create ram_block_discard_range in exec.c to replace postcopy_ram_discard_range and most of ram_discard_range. Those two routines are a bit of a weird combination, and ram_discard_range is about to get more complex for hugepages. It's OS dependent code (so shouldn't be in migration/ram.c) but it needs quite a bit of the innards of RAMBlock so doesn't belong in the os*.c. Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Reviewed-by: Laurent Vivier <lvivier@redhat.com> Message-Id: <20170224182844.32452-5-dgilbert@redhat.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
		
							parent
							
								
									29c5917201
								
							
						
					
					
						commit
						d3a5038c46
					
				
							
								
								
									
										54
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								exec.c
									
									
									
									
									
								
							| @ -45,6 +45,7 @@ | ||||
| #include "exec/address-spaces.h" | ||||
| #include "sysemu/xen-mapcache.h" | ||||
| #include "trace-root.h" | ||||
| 
 | ||||
| #endif | ||||
| #include "exec/cpu-all.h" | ||||
| #include "qemu/rcu_queue.h" | ||||
| @ -3294,4 +3295,57 @@ int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque) | ||||
|     rcu_read_unlock(); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Unmap pages of memory from start to start+length such that | ||||
|  * they a) read as 0, b) Trigger whatever fault mechanism | ||||
|  * the OS provides for postcopy. | ||||
|  * The pages must be unmapped by the end of the function. | ||||
|  * Returns: 0 on success, none-0 on failure | ||||
|  * | ||||
|  */ | ||||
| int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) | ||||
| { | ||||
|     int ret = -1; | ||||
| 
 | ||||
|     uint8_t *host_startaddr = rb->host + start; | ||||
| 
 | ||||
|     if ((uintptr_t)host_startaddr & (rb->page_size - 1)) { | ||||
|         error_report("ram_block_discard_range: Unaligned start address: %p", | ||||
|                      host_startaddr); | ||||
|         goto err; | ||||
|     } | ||||
| 
 | ||||
|     if ((start + length) <= rb->used_length) { | ||||
|         uint8_t *host_endaddr = host_startaddr + length; | ||||
|         if ((uintptr_t)host_endaddr & (rb->page_size - 1)) { | ||||
|             error_report("ram_block_discard_range: Unaligned end address: %p", | ||||
|                          host_endaddr); | ||||
|             goto err; | ||||
|         } | ||||
| 
 | ||||
|         errno = ENOTSUP; /* If we are missing MADVISE etc */ | ||||
| 
 | ||||
| #if defined(CONFIG_MADVISE) | ||||
|         /* Note: We need the madvise MADV_DONTNEED behaviour of definitely
 | ||||
|          * freeing the page. | ||||
|          */ | ||||
|         ret = madvise(host_startaddr, length, MADV_DONTNEED); | ||||
| #endif | ||||
|         if (ret) { | ||||
|             ret = -errno; | ||||
|             error_report("ram_block_discard_range: Failed to discard range " | ||||
|                          "%s:%" PRIx64 " +%zx (%d)", | ||||
|                          rb->idstr, start, length, ret); | ||||
|         } | ||||
|     } else { | ||||
|         error_report("ram_block_discard_range: Overrun block '%s' (%" PRIu64 | ||||
|                      "/%zx/" RAM_ADDR_FMT")", | ||||
|                      rb->idstr, start, length, rb->used_length); | ||||
|     } | ||||
| 
 | ||||
| err: | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -105,6 +105,7 @@ typedef int (RAMBlockIterFunc)(const char *block_name, void *host_addr, | ||||
|     ram_addr_t offset, ram_addr_t length, void *opaque); | ||||
| 
 | ||||
| int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque); | ||||
| int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| @ -34,13 +34,6 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages); | ||||
|  */ | ||||
| int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis); | ||||
| 
 | ||||
| /*
 | ||||
|  * Discard the contents of 'length' bytes from 'start' | ||||
|  * We can assume that if we've been called postcopy_ram_hosttest returned true | ||||
|  */ | ||||
| int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start, | ||||
|                                size_t length); | ||||
| 
 | ||||
| /*
 | ||||
|  * Userfault requires us to mark RAM as NOHUGEPAGE prior to discard | ||||
|  * however leaving it until after precopy means that most of the precopy | ||||
|  | ||||
| @ -200,27 +200,6 @@ out: | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * postcopy_ram_discard_range: Discard a range of memory. | ||||
|  * We can assume that if we've been called postcopy_ram_hosttest returned true. | ||||
|  * | ||||
|  * @mis: Current incoming migration state. | ||||
|  * @start, @length: range of memory to discard. | ||||
|  * | ||||
|  * returns: 0 on success. | ||||
|  */ | ||||
| int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start, | ||||
|                                size_t length) | ||||
| { | ||||
|     trace_postcopy_ram_discard_range(start, length); | ||||
|     if (madvise(start, length, MADV_DONTNEED)) { | ||||
|         error_report("%s MADV_DONTNEED: %s", __func__, strerror(errno)); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Setup an area of RAM so that it *can* be used for postcopy later; this | ||||
|  * must be done right at the start prior to pre-copy. | ||||
| @ -239,7 +218,7 @@ static int init_range(const char *block_name, void *host_addr, | ||||
|      * - we're going to get the copy from the source anyway. | ||||
|      * (Precopy will just overwrite this data, so doesn't need the discard) | ||||
|      */ | ||||
|     if (postcopy_ram_discard_range(mis, host_addr, length)) { | ||||
|     if (ram_discard_range(mis, block_name, 0, length)) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
| @ -658,13 +637,6 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start, | ||||
|                                size_t length) | ||||
| { | ||||
|     assert(0); | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| int postcopy_ram_prepare_discard(MigrationIncomingState *mis) | ||||
| { | ||||
|     assert(0); | ||||
|  | ||||
| @ -1890,6 +1890,8 @@ int ram_discard_range(MigrationIncomingState *mis, | ||||
| { | ||||
|     int ret = -1; | ||||
| 
 | ||||
|     trace_ram_discard_range(block_name, start, length); | ||||
| 
 | ||||
|     rcu_read_lock(); | ||||
|     RAMBlock *rb = qemu_ram_block_by_name(block_name); | ||||
| 
 | ||||
| @ -1899,27 +1901,7 @@ int ram_discard_range(MigrationIncomingState *mis, | ||||
|         goto err; | ||||
|     } | ||||
| 
 | ||||
|     uint8_t *host_startaddr = rb->host + start; | ||||
| 
 | ||||
|     if ((uintptr_t)host_startaddr & (qemu_host_page_size - 1)) { | ||||
|         error_report("ram_discard_range: Unaligned start address: %p", | ||||
|                      host_startaddr); | ||||
|         goto err; | ||||
|     } | ||||
| 
 | ||||
|     if ((start + length) <= rb->used_length) { | ||||
|         uint8_t *host_endaddr = host_startaddr + length; | ||||
|         if ((uintptr_t)host_endaddr & (qemu_host_page_size - 1)) { | ||||
|             error_report("ram_discard_range: Unaligned end address: %p", | ||||
|                          host_endaddr); | ||||
|             goto err; | ||||
|         } | ||||
|         ret = postcopy_ram_discard_range(mis, host_startaddr, length); | ||||
|     } else { | ||||
|         error_report("ram_discard_range: Overrun block '%s' (%" PRIu64 | ||||
|                      "/%zx/" RAM_ADDR_FMT")", | ||||
|                      block_name, start, length, rb->used_length); | ||||
|     } | ||||
|     ret = ram_block_discard_range(rb, start, length); | ||||
| 
 | ||||
| err: | ||||
|     rcu_read_unlock(); | ||||
|  | ||||
| @ -68,6 +68,7 @@ get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, uint64_t | ||||
| migration_bitmap_sync_start(void) "" | ||||
| migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 | ||||
| migration_throttle(void) "" | ||||
| ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx" | ||||
| ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x" | ||||
| ram_postcopy_send_discard_bitmap(void) "" | ||||
| ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx" | ||||
| @ -176,7 +177,6 @@ rdma_start_outgoing_migration_after_rdma_source_init(void) "" | ||||
| # migration/postcopy-ram.c | ||||
| postcopy_discard_send_finish(const char *ramblock, int nwords, int ncmds) "%s mask words sent=%d in %d commands" | ||||
| postcopy_discard_send_range(const char *ramblock, unsigned long start, unsigned long length) "%s:%lx/%lx" | ||||
| postcopy_ram_discard_range(void *start, size_t length) "%p,+%zx" | ||||
| postcopy_cleanup_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx" | ||||
| postcopy_init_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx" | ||||
| postcopy_nhp_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dr. David Alan Gilbert
						Dr. David Alan Gilbert