If g_file_get_contents fails (AppArmor, etc), use a more conservative default max size for the idle coroutine pool.
This avoids any possibility of the failure described in 86a637e48104 unless the host kernel is configured with a lower-than-default vm.max_map_count. This change is motivated by a discussion of backport risk: https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/2168803/comments/8 Fixes: 86a637e48104 ("coroutine: cap per-thread local pool size") Suggested-by: Daniel P. Berrangé <[email protected]> Reviewed-by: Stefan Hajnoczi <[email protected]> Signed-off-by: Wesley Hershberger <[email protected]> --- util/qemu-coroutine.c | 73 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 5af61995437..fc9ed66f475 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -361,42 +361,61 @@ void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size) global_pool_max_size -= removing_pool_size; } -static unsigned int get_global_pool_hard_max_size(void) -{ #ifdef __linux__ - g_autofree char *contents = NULL; - int max_map_count; +/* + * include/linux/mm.h + */ +#define DEFAULT_MAX_MAP_COUNT 65530 - /* - * Linux processes can have up to max_map_count virtual memory areas - * (VMAs). mmap(2), mprotect(2), etc fail with ENOMEM beyond this limit. We - * must limit the coroutine pool to a safe size to avoid running out of - * VMAs. - */ - if (g_file_get_contents("/proc/sys/vm/max_map_count", &contents, NULL, - NULL)) { +static unsigned int get_max_map_count(void) +{ + g_autofree char *contents = NULL; + unsigned int max_map_count = 0; + if (g_file_get_contents("/proc/sys/vm/max_map_count", &contents, + NULL, NULL)) { /* contents has trailing newline, remove it before conversion */ g_strchomp(contents); - if (qemu_strtoi(contents, NULL, 10, &max_map_count) != 0) { - return UINT_MAX; - } - /* - * This is an upper bound that avoids exceeding max_map_count. Leave a - * fixed amount for non-coroutine users like library dependencies, - * vhost-user, etc. Each coroutine takes up 2 VMAs so halve the - * remaining amount. - */ - if (max_map_count > 5000) { - return (max_map_count - 5000) / 2; - } else { - /* Disable the global pool but threads still have local pools */ - return 0; + if (qemu_strtoui(contents, NULL, 10, &max_map_count) == 0) { + return max_map_count; } } -#endif + /* + * Read from /proc might fail due to mandatory access control (AppArmor, + * SELinux, etc). Use the kernel's default in that case. + */ + return DEFAULT_MAX_MAP_COUNT; +} + +/* + * Linux processes can have up to max_map_count virtual memory areas + * (VMAs). mmap(2), mprotect(2), etc fail with ENOMEM beyond this limit. We + * must limit the coroutine pool to a safe size to avoid running out of + * VMAs. + */ +static unsigned int get_global_pool_hard_max_size(void) +{ + unsigned int max_map_count = get_max_map_count(); + + /* + * This is an upper bound that avoids exceeding max_map_count. Leave a + * fixed amount for non-coroutine users like library dependencies, + * vhost-user, etc. Each coroutine takes up 2 VMAs so halve the + * remaining amount. + */ + if (max_map_count > 5000) { + return (max_map_count - 5000) / 2; + } else { + /* Disable the global pool but threads still have local pools */ + return 0; + } +} +#else +static unsigned int get_global_pool_hard_max_size(void) +{ return UINT_MAX; } +#endif static void __attribute__((constructor)) qemu_coroutine_init(void) { -- 2.53.0
