diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/error.c | 20 | ||||
| -rw-r--r-- | util/hbitmap.c | 51 | ||||
| -rw-r--r-- | util/oslib-posix.c | 66 | ||||
| -rw-r--r-- | util/oslib-win32.c | 24 | ||||
| -rw-r--r-- | util/qemu-coroutine-lock.c | 35 | ||||
| -rw-r--r-- | util/qemu-error.c | 106 | ||||
| -rw-r--r-- | util/qemu-sockets.c | 105 |
7 files changed, 256 insertions, 151 deletions
diff --git a/util/error.c b/util/error.c index 020b86b9f0..3efdd69162 100644 --- a/util/error.c +++ b/util/error.c @@ -232,6 +232,15 @@ void error_report_err(Error *err) error_free(err); } +void warn_report_err(Error *err) +{ + warn_report("%s", error_get_pretty(err)); + if (err->hint) { + error_printf_unless_qmp("%s", err->hint->str); + } + error_free(err); +} + void error_reportf_err(Error *err, const char *fmt, ...) { va_list ap; @@ -242,6 +251,17 @@ void error_reportf_err(Error *err, const char *fmt, ...) error_report_err(err); } + +void warn_reportf_err(Error *err, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_vprepend(&err, fmt, ap); + va_end(ap); + warn_report_err(err); +} + void error_free(Error *err) { if (err) { diff --git a/util/hbitmap.c b/util/hbitmap.c index 35088e19c4..21535cc90b 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -13,6 +13,7 @@ #include "qemu/hbitmap.h" #include "qemu/host-utils.h" #include "trace.h" +#include "crypto/hash.h" /* HBitmaps provides an array of bits. The bits are stored as usual in an * array of unsigned longs, but HBitmap is also optimized to provide fast @@ -106,8 +107,9 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) unsigned long cur; do { - cur = hbi->cur[--i]; + i--; pos >>= BITS_PER_LEVEL; + cur = hbi->cur[i] & hb->levels[i][pos]; } while (cur == 0); /* Check for end of iteration. We always use fewer than BITS_PER_LONG @@ -139,6 +141,26 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) return cur; } +int64_t hbitmap_iter_next(HBitmapIter *hbi) +{ + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] & + hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos]; + int64_t item; + + if (cur == 0) { + cur = hbitmap_iter_skip_words(hbi); + if (cur == 0) { + return -1; + } + } + + /* The next call will resume work from the next bit. */ + hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur); + + return item << hbi->granularity; +} + void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) { unsigned i, bit; @@ -530,6 +552,23 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count, } } +void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count, + bool finish) +{ + uint64_t el_count; + unsigned long *first; + + if (!count) { + return; + } + serialization_chunk(hb, start, count, &first, &el_count); + + memset(first, 0xff, el_count * sizeof(unsigned long)); + if (finish) { + hbitmap_deserialize_finish(hb); + } +} + void hbitmap_deserialize_finish(HBitmap *bitmap) { int64_t i, size, prev_size; @@ -689,3 +728,13 @@ void hbitmap_free_meta(HBitmap *hb) hbitmap_free(hb->meta); hb->meta = NULL; } + +char *hbitmap_sha256(const HBitmap *bitmap, Error **errp) +{ + size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long); + char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1]; + char *hash = NULL; + qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp); + + return hash; +} diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 5e8b4b39ed..b2dea48f40 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -414,72 +414,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, } -static struct termios oldtty; - -static void term_exit(void) -{ - tcsetattr(0, TCSANOW, &oldtty); -} - -static void term_init(void) -{ - struct termios tty; - - tcgetattr(0, &tty); - oldtty = tty; - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr(0, TCSANOW, &tty); - - atexit(term_exit); -} - -int qemu_read_password(char *buf, int buf_size) -{ - uint8_t ch; - int i, ret; - - printf("password: "); - fflush(stdout); - term_init(); - i = 0; - for (;;) { - ret = read(0, &ch, 1); - if (ret == -1) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } else if (ret == 0) { - ret = -1; - break; - } else { - if (ch == '\r' || - ch == '\n') { - ret = 0; - break; - } - if (i < (buf_size - 1)) { - buf[i++] = ch; - } - } - } - term_exit(); - buf[i] = '\0'; - printf("\n"); - return ret; -} - - char *qemu_get_pid_name(pid_t pid) { char *name = NULL; diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 3de9e7777e..69a6286d50 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -552,30 +552,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, } -/* XXX: put correct support for win32 */ -int qemu_read_password(char *buf, int buf_size) -{ - int c, i; - - printf("Password: "); - fflush(stdout); - i = 0; - for (;;) { - c = getchar(); - if (c < 0) { - buf[i] = '\0'; - return -1; - } else if (c == '\n') { - break; - } else if (i < (buf_size - 1)) { - buf[i++] = c; - } - } - buf[i] = '\0'; - return 0; -} - - char *qemu_get_pid_name(pid_t pid) { /* XXX Implement me */ diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index b44b5d55eb..846ff9167f 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -402,6 +402,21 @@ void qemu_co_rwlock_unlock(CoRwlock *lock) qemu_co_mutex_unlock(&lock->mutex); } +void qemu_co_rwlock_downgrade(CoRwlock *lock) +{ + Coroutine *self = qemu_coroutine_self(); + + /* lock->mutex critical section started in qemu_co_rwlock_wrlock or + * qemu_co_rwlock_upgrade. + */ + assert(lock->reader == 0); + lock->reader++; + qemu_co_mutex_unlock(&lock->mutex); + + /* The rest of the read-side critical section is run without the mutex. */ + self->locks_held++; +} + void qemu_co_rwlock_wrlock(CoRwlock *lock) { qemu_co_mutex_lock(&lock->mutex); @@ -416,3 +431,23 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock) * There is no need to update self->locks_held. */ } + +void qemu_co_rwlock_upgrade(CoRwlock *lock) +{ + Coroutine *self = qemu_coroutine_self(); + + qemu_co_mutex_lock(&lock->mutex); + assert(lock->reader > 0); + lock->reader--; + lock->pending_writer++; + while (lock->reader) { + qemu_co_queue_wait(&lock->queue, &lock->mutex); + } + lock->pending_writer--; + + /* The rest of the write-side critical section is run with + * the mutex taken, similar to qemu_co_rwlock_wrlock. Do + * not account for the lock twice in self->locks_held. + */ + self->locks_held--; +} diff --git a/util/qemu-error.c b/util/qemu-error.c index b331f8f4a4..c557c6ae47 100644 --- a/util/qemu-error.c +++ b/util/qemu-error.c @@ -14,6 +14,16 @@ #include "monitor/monitor.h" #include "qemu/error-report.h" +/* + * @report_type is the type of message: error, warning or + * informational. + */ +typedef enum { + REPORT_TYPE_ERROR, + REPORT_TYPE_WARNING, + REPORT_TYPE_INFO, +} report_type; + void error_printf(const char *fmt, ...) { va_list ap; @@ -146,7 +156,7 @@ const char *error_get_progname(void) /* * Print current location to current monitor if we have one, else to stderr. */ -static void error_print_loc(void) +static void print_loc(void) { const char *sep = ""; int i; @@ -179,17 +189,29 @@ static void error_print_loc(void) bool enable_timestamp_msg; /* - * Print an error message to current monitor if we have one, else to stderr. + * Print a message to current monitor if we have one, else to stderr. + * @report_type is the type of message: error, warning or informational. * Format arguments like vsprintf(). The resulting message should be * a single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. * It's wrong to call this in a QMP monitor. Use error_setg() there. */ -void error_vreport(const char *fmt, va_list ap) +static void vreport(report_type type, const char *fmt, va_list ap) { GTimeVal tv; gchar *timestr; + switch (type) { + case REPORT_TYPE_ERROR: + break; + case REPORT_TYPE_WARNING: + error_printf("warning: "); + break; + case REPORT_TYPE_INFO: + error_printf("info: "); + break; + } + if (enable_timestamp_msg && !cur_mon) { g_get_current_time(&tv); timestr = g_time_val_to_iso8601(&tv); @@ -197,15 +219,52 @@ void error_vreport(const char *fmt, va_list ap) g_free(timestr); } - error_print_loc(); + print_loc(); error_vprintf(fmt, ap); error_printf("\n"); } /* * Print an error message to current monitor if we have one, else to stderr. - * Format arguments like sprintf(). The resulting message should be a - * single phrase, with no newline or trailing punctuation. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void error_vreport(const char *fmt, va_list ap) +{ + vreport(REPORT_TYPE_ERROR, fmt, ap); +} + +/* + * Print a warning message to current monitor if we have one, else to stderr. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void warn_vreport(const char *fmt, va_list ap) +{ + vreport(REPORT_TYPE_WARNING, fmt, ap); +} + +/* + * Print an information message to current monitor if we have one, else to + * stderr. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void info_vreport(const char *fmt, va_list ap) +{ + vreport(REPORT_TYPE_INFO, fmt, ap); +} + +/* + * Print an error message to current monitor if we have one, else to stderr. + * Format arguments like sprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. * It's wrong to call this in a QMP monitor. Use error_setg() there. */ @@ -214,6 +273,39 @@ void error_report(const char *fmt, ...) va_list ap; va_start(ap, fmt); - error_vreport(fmt, ap); + vreport(REPORT_TYPE_ERROR, fmt, ap); + va_end(ap); +} + +/* + * Print a warning message to current monitor if we have one, else to stderr. + * Format arguments like sprintf(). The resulting message should be a + * single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void warn_report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vreport(REPORT_TYPE_WARNING, fmt, ap); + va_end(ap); +} + +/* + * Print an information message to current monitor if we have one, else to + * stderr. + * Format arguments like sprintf(). The resulting message should be a + * single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void info_report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vreport(REPORT_TYPE_INFO, fmt, ap); va_end(ap); } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index d3e51089de..1358c81bcc 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -104,17 +104,16 @@ NetworkAddressFamily inet_netfamily(int family) * f t PF_INET6 * t - PF_INET * t f PF_INET - * t t PF_INET6 + * t t PF_INET6/PF_UNSPEC * * NB, this matrix is only about getting the necessary results * from getaddrinfo(). Some of the cases require further work * after reading results from getaddrinfo in order to fully - * apply the logic the end user wants. eg with the last case - * ipv4=t + ipv6=t + PF_INET6, getaddrinfo alone can only - * guarantee the ipv6=t part of the request - we need more - * checks to provide ipv4=t part of the guarantee. This is - * outside scope of this method and not currently handled by - * callers at all. + * apply the logic the end user wants. + * + * In the first and last cases, we must set IPV6_V6ONLY=0 + * when binding, to allow a single listener to potentially + * accept both IPv4+6 addresses. */ int inet_ai_family_from_address(InetSocketAddress *addr, Error **errp) @@ -124,6 +123,23 @@ int inet_ai_family_from_address(InetSocketAddress *addr, error_setg(errp, "Cannot disable IPv4 and IPv6 at same time"); return PF_UNSPEC; } + if ((addr->has_ipv6 && addr->ipv6) && (addr->has_ipv4 && addr->ipv4)) { + /* + * Some backends can only do a single listener. In that case + * we want empty hostname to resolve to "::" and then use the + * flag IPV6_V6ONLY==0 to get both protocols on 1 socket. This + * doesn't work for addresses other than "", so they're just + * inevitably broken until multiple listeners can be used, + * and thus we honour getaddrinfo automatic protocol detection + * Once all backends do multi-listener, remove the PF_INET6 + * branch entirely. + */ + if (!addr->host || g_str_equal(addr->host, "")) { + return PF_INET6; + } else { + return PF_UNSPEC; + } + } if ((addr->has_ipv6 && addr->ipv6) || (addr->has_ipv4 && !addr->ipv4)) { return PF_INET6; } @@ -208,22 +224,43 @@ static int inet_listen_saddr(InetSocketAddress *saddr, } socket_set_fast_reuse(slisten); -#ifdef IPV6_V6ONLY - if (e->ai_family == PF_INET6) { - /* listen on both ipv4 and ipv6 */ - const int off = 0; - qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off, - sizeof(off)); - } -#endif port_min = inet_getport(e); port_max = saddr->has_to ? saddr->to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { +#ifdef IPV6_V6ONLY + /* + * Deals with first & last cases in matrix in comment + * for inet_ai_family_from_address(). + */ + int v6only = + ((!saddr->has_ipv4 && !saddr->has_ipv6) || + (saddr->has_ipv4 && saddr->ipv4 && + saddr->has_ipv6 && saddr->ipv6)) ? 0 : 1; +#endif inet_setport(e, p); +#ifdef IPV6_V6ONLY + rebind: + if (e->ai_family == PF_INET6) { + qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, + sizeof(v6only)); + } +#endif if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { goto listen; } + +#ifdef IPV6_V6ONLY + /* If we got EADDRINUSE from an IPv6 bind & V6ONLY is unset, + * it could be that the IPv4 port is already claimed, so retry + * with V6ONLY set + */ + if (e->ai_family == PF_INET6 && errno == EADDRINUSE && !v6only) { + v6only = 1; + goto rebind; + } +#endif + if (p == port_max) { if (!e->ai_next) { error_setg_errno(errp, errno, "Failed to bind socket"); @@ -603,16 +640,12 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) error_setg(errp, "error parsing IPv6 address '%s'", str); return -1; } - addr->ipv6 = addr->has_ipv6 = true; } else { /* hostname or IPv4 addr */ if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) { error_setg(errp, "error parsing address '%s'", str); return -1; } - if (host[strspn(host, "0123456789.")] == '\0') { - addr->ipv4 = addr->has_ipv4 = true; - } } addr->host = g_strdup(host); @@ -1325,40 +1358,6 @@ SocketAddress *socket_remote_address(int fd, Error **errp) return socket_sockaddr_to_address(&ss, sslen, errp); } -char *socket_address_to_string(struct SocketAddress *addr, Error **errp) -{ - char *buf; - InetSocketAddress *inet; - - switch (addr->type) { - case SOCKET_ADDRESS_TYPE_INET: - inet = &addr->u.inet; - if (strchr(inet->host, ':') == NULL) { - buf = g_strdup_printf("%s:%s", inet->host, inet->port); - } else { - buf = g_strdup_printf("[%s]:%s", inet->host, inet->port); - } - break; - - case SOCKET_ADDRESS_TYPE_UNIX: - buf = g_strdup(addr->u.q_unix.path); - break; - - case SOCKET_ADDRESS_TYPE_FD: - buf = g_strdup(addr->u.fd.str); - break; - - case SOCKET_ADDRESS_TYPE_VSOCK: - buf = g_strdup_printf("%s:%s", - addr->u.vsock.cid, - addr->u.vsock.port); - break; - - default: - abort(); - } - return buf; -} SocketAddress *socket_address_flatten(SocketAddressLegacy *addr_legacy) { |