[libvirt] [PATCH 3/5] Use helper functions to format the journal iov array
Daniel P. Berrange
berrange at redhat.com
Wed Nov 14 15:30:01 UTC 2012
On Wed, Oct 17, 2012 at 08:17:16PM +0200, Miloslav Trmač wrote:
> This simplifies the top-level code, at the cost of using a little more
> stack space. The primary benefit is being able to send more fields
> without knowing in advance how many of them, and of which types, these
> fields will be, and without having to individually add buffer variables.
>
> The code imposes an upper limit on the total number of iovs/buffers
> used, and fields that wouldn't fit are silently dropped. This is not
> significant in this patch, but will affect the following one.
>
> Signed-off-by: Miloslav Trmač <mitr at redhat.com>
> ---
> src/util/logging.c | 144 ++++++++++++++++++++++++++++++++---------------------
> 1 file changed, 87 insertions(+), 57 deletions(-)
>
> diff --git a/src/util/logging.c b/src/util/logging.c
> index a41ae8b..a6d00c9 100644
> --- a/src/util/logging.c
> +++ b/src/util/logging.c
> @@ -1043,19 +1043,78 @@ virLogAddOutputToSyslog(virLogPriority priority,
>
>
> # if USE_JOURNALD
> -# define IOVEC_SET_STRING(iov, str) \
> - do { \
> - struct iovec *_i = &(iov); \
> - _i->iov_base = (char*)str; \
> - _i->iov_len = strlen(str); \
> +# define IOVEC_SET(iov, data, size) \
> + do { \
> + struct iovec *_i = &(iov); \
> + _i->iov_base = (void*)(data); \
> + _i->iov_len = (size); \
> } while (0)
>
> -# define IOVEC_SET_INT(iov, buf, val) \
> - do { \
> - struct iovec *_i = &(iov); \
> - _i->iov_base = virFormatIntDecimal(buf, sizeof(buf), val); \
> - _i->iov_len = strlen(buf); \
> - } while (0)
> +# define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str))
> +
> +/* Used for conversion of numbers to strings, and for length of binary data */
> +#define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t)))
> +
> +struct journalState
> +{
> + struct iovec *iov, *iov_end;
> + char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE];
> +};
> +
> +static void
> +journalAddString(struct journalState *state, const char *field,
> + const char *value)
> +{
> + static const char newline = '\n', equals = '=';
> +
> + if (strchr(value, '\n') != NULL) {
> + uint64_t nstr;
> +
> + /* If 'str' contains a newline, then we must
> + * encode the string length, since we can't
> + * rely on the newline for the field separator
> + */
> + if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end)
> + return; /* Silently drop */
> + nstr = htole64(strlen(value));
> + memcpy(state->bufs[0], &nstr, sizeof(nstr));
> +
> + IOVEC_SET_STRING(state->iov[0], field);
> + IOVEC_SET(state->iov[1], &newline, sizeof(newline));
> + IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr));
> + state->bufs++;
> + state->iov += 3;
> + } else {
> + if (state->iov_end - state->iov < 4)
> + return; /* Silently drop */
> + IOVEC_SET_STRING(state->iov[0], field);
> + IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
> + state->iov += 2;
> + }
> + IOVEC_SET_STRING(state->iov[0], value);
> + IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline));
> + state->iov += 2;
> +}
> +
> +static void
> +journalAddInt(struct journalState *state, const char *field, int value)
> +{
> + static const char newline = '\n', equals = '=';
> +
> + char *num;
> +
> + if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end)
> + return; /* Silently drop */
> +
> + num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value);
> +
> + IOVEC_SET_STRING(state->iov[0], field);
> + IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
> + IOVEC_SET_STRING(state->iov[2], num);
> + IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline));
> + state->bufs++;
> + state->iov += 4;
> +}
>
> static int journalfd = -1;
>
> @@ -1074,7 +1133,6 @@ virLogOutputToJournald(virLogSource source,
> {
> virCheckFlags(VIR_LOG_STACK_TRACE,);
> int buffd = -1;
> - size_t niov = 0;
> struct msghdr mh;
> struct sockaddr_un sa;
> union {
> @@ -1086,52 +1144,24 @@ virLogOutputToJournald(virLogSource source,
> * be a tmpfs, and one that is available from early boot on
> * and where unprivileged users can create files. */
> char path[] = "/dev/shm/journal.XXXXXX";
> - char priostr[INT_BUFSIZE_BOUND(priority)];
> - char linestr[INT_BUFSIZE_BOUND(linenr)];
> -
> - /* First message takes up to 4 iovecs, and each
> - * other field needs 3, assuming they don't have
> - * newlines in them
> - */
> -# define IOV_SIZE (4 + (5 * 3))
> - struct iovec iov[IOV_SIZE];
> -
> - if (strchr(rawstr, '\n')) {
> - uint64_t nstr;
> - /* If 'str' contains a newline, then we must
> - * encode the string length, since we can't
> - * rely on the newline for the field separator
> - */
> - IOVEC_SET_STRING(iov[niov++], "MESSAGE\n");
> - nstr = htole64(strlen(rawstr));
> - iov[niov].iov_base = (char*)&nstr;
> - iov[niov].iov_len = sizeof(nstr);
> - niov++;
> - } else {
> - IOVEC_SET_STRING(iov[niov++], "MESSAGE=");
> - }
> - IOVEC_SET_STRING(iov[niov++], rawstr);
> - IOVEC_SET_STRING(iov[niov++], "\n");
> -
> - IOVEC_SET_STRING(iov[niov++], "PRIORITY=");
> - IOVEC_SET_INT(iov[niov++], priostr, priority);
> - IOVEC_SET_STRING(iov[niov++], "\n");
> -
> - IOVEC_SET_STRING(iov[niov++], "LIBVIRT_SOURCE=");
> - IOVEC_SET_STRING(iov[niov++], virLogSourceTypeToString(source));
> - IOVEC_SET_STRING(iov[niov++], "\n");
>
> - IOVEC_SET_STRING(iov[niov++], "CODE_FILE=");
> - IOVEC_SET_STRING(iov[niov++], filename);
> - IOVEC_SET_STRING(iov[niov++], "\n");
> +# define NUM_FIELDS 6
> + struct iovec iov[NUM_FIELDS * 5];
> + char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
> + struct journalState state;
>
> - IOVEC_SET_STRING(iov[niov++], "CODE_LINE=");
> - IOVEC_SET_INT(iov[niov++], linestr, linenr);
> - IOVEC_SET_STRING(iov[niov++], "\n");
> + state.iov = iov;
> + state.iov_end = iov + ARRAY_CARDINALITY(iov);
> + state.bufs = iov_bufs;
> + state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs);
>
> - IOVEC_SET_STRING(iov[niov++], "CODE_FUNC=");
> - IOVEC_SET_STRING(iov[niov++], funcname);
> - IOVEC_SET_STRING(iov[niov++], "\n");
> + journalAddString(&state ,"MESSAGE", rawstr);
> + journalAddInt(&state, "PRIORITY", priority);
> + journalAddString(&state, "LIBVIRT_SOURCE",
> + virLogSourceTypeToString(source));
> + journalAddString(&state, "CODE_FILE", filename);
> + journalAddInt(&state, "CODE_LINE", linenr);
> + journalAddString(&state, "CODE_FUNC", funcname);
>
> memset(&sa, 0, sizeof(sa));
> sa.sun_family = AF_UNIX;
> @@ -1142,7 +1172,7 @@ virLogOutputToJournald(virLogSource source,
> mh.msg_name = &sa;
> mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
> mh.msg_iov = iov;
> - mh.msg_iovlen = niov;
> + mh.msg_iovlen = state.iov - iov;
>
> if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0)
> return;
> @@ -1166,7 +1196,7 @@ virLogOutputToJournald(virLogSource source,
> if (unlink(path) < 0)
> goto cleanup;
>
> - if (writev(buffd, iov, niov) < 0)
> + if (writev(buffd, iov, state.iov - iov) < 0)
> goto cleanup;
>
> mh.msg_iov = NULL;
ACK
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list