From cfa9a5a2b4a96e0d6a9eeddd2622a6d7c173b7ac Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 6 Jun 2013 15:30:14 -0400 Subject: [PATCH] Fix: poll compat layer reallocation new size The size was doubled but in fact it should have been checked for the maximum between the number of fd doubled and the alloc size doubled (divised by two when shrinking the buffer). Same goes for the shrink process. For that, get_count_order_u32() is added to utils.c/.h. Signed-off-by: David Goulet --- src/common/compat/compat-epoll.c | 10 ++++- src/common/compat/compat-poll.c | 10 ++++- src/common/utils.c | 68 +++++++++++++++++++++++++++++++- src/common/utils.h | 1 + 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/common/compat/compat-epoll.c b/src/common/compat/compat-epoll.c index f014a0d78..903a9f825 100644 --- a/src/common/compat/compat-epoll.c +++ b/src/common/compat/compat-epoll.c @@ -27,6 +27,8 @@ #include #include +#include +#include #include "poll.h" @@ -201,11 +203,15 @@ int compat_epoll_wait(struct lttng_poll_event *events, int timeout) */ if (events->nb_fd > events->alloc_size) { /* Expand if the nb_fd is higher than the actual size. */ - new_size = events->alloc_size << 1UL; + new_size = max_t(uint32_t, + 1U << utils_get_count_order_u32(events->nb_fd), + events->alloc_size << 1UL); } else if ((events->nb_fd << 1UL) <= events->alloc_size && events->nb_fd >= events->init_size) { /* Shrink if nb_fd multiplied by two is <= than the actual size. */ - new_size = events->alloc_size >> 1UL; + new_size = max_t(uint32_t, + utils_get_count_order_u32(events->nb_fd) >> 1U, + events->alloc_size >> 1U); } else { /* Indicate that we don't want to resize. */ new_size = 0; diff --git a/src/common/compat/compat-poll.c b/src/common/compat/compat-poll.c index bc79eed0a..79fcb7d65 100644 --- a/src/common/compat/compat-poll.c +++ b/src/common/compat/compat-poll.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include "poll.h" @@ -168,7 +170,9 @@ int compat_poll_add(struct lttng_poll_event *events, int fd, /* Check for a needed resize of the array. */ if (current->nb_fd > current->alloc_size) { /* Expand it by a power of two of the current size. */ - new_size = current->alloc_size << 1UL; + new_size = max_t(int, + 1U << utils_get_count_order_u32(current->nb_fd), + current->alloc_size << 1UL); ret = resize_poll_event(current, new_size); if (ret < 0) { goto error; @@ -212,7 +216,9 @@ int compat_poll_del(struct lttng_poll_event *events, int fd) * Shrink if nb_fd multiplied by two is <= than the actual size and we * are above the initial size. */ - new_size = current->alloc_size >> 1UL; + new_size = max_t(int, + utils_get_count_order_u32(current->nb_fd) >> 1U, + current->alloc_size >> 1U); ret = resize_poll_event(current, new_size); if (ret < 0) { goto error; diff --git a/src/common/utils.c b/src/common/utils.c index f3718f00f..38f78a7e8 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -440,7 +440,7 @@ static void regex_print_error(int errcode, regex_t *regex) * * @param str The string to parse. * @param size Pointer to a size_t that will be filled with the - * resulting size. + * resulting size. * * @return 0 on success, -1 on failure. */ @@ -518,3 +518,69 @@ free: end: return ret; } + +/* + * fls: returns the position of the most significant bit. + * Returns 0 if no bit is set, else returns the position of the most + * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit). + */ +#if defined(__i386) || defined(__x86_64) +static inline unsigned int fls_u32(uint32_t x) +{ + int r; + + asm("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n\t" + "1:\n\t" + : "=r" (r) : "rm" (x)); + return r + 1; +} +#define HAS_FLS_U32 +#endif + +#ifndef HAS_FLS_U32 +static __attribute__((unused)) unsigned int fls_u32(uint32_t x) +{ + unsigned int r = 32; + + if (!x) { + return 0; + } + if (!(x & 0xFFFF0000U)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xFF000000U)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xF0000000U)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xC0000000U)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000U)) { + x <<= 1; + r -= 1; + } + return r; +} +#endif + +/* + * Return the minimum order for which x <= (1UL << order). + * Return -1 if x is 0. + */ +LTTNG_HIDDEN +int utils_get_count_order_u32(uint32_t x) +{ + if (!x) { + return -1; + } + + return fls_u32(x - 1); +} diff --git a/src/common/utils.h b/src/common/utils.h index d8a5321c7..083acef93 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -39,5 +39,6 @@ int utils_create_stream_file(char *path_name, char *file_name, uint64_t size, int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size, uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count); int utils_parse_size_suffix(char *str, uint64_t *size); +int utils_get_count_order_u32(uint32_t x); #endif /* _COMMON_UTILS_H */ -- 2.34.1