From: "Daniel P. Berrange" <berrange@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2] qemu-char: add logfile facility to all chardev backends
Date: Wed, 23 Dec 2015 11:32:14 +0000 [thread overview]
Message-ID: <20151223113214.GH20028@redhat.com> (raw)
In-Reply-To: <56799F57.1080609@redhat.com>
On Tue, Dec 22, 2015 at 12:07:03PM -0700, Eric Blake wrote:
> On 12/22/2015 11:17 AM, Daniel P. Berrange wrote:
> > Typically a UNIX guest OS will log boot messages to a serial
> > port in addition to any graphical console. An admin user
> > may also wish to use the serial port for an interactive
> > console. A virtualization management system may wish to
> > collect system boot messages by logging the serial port,
> > but also wish to allow admins interactive access.
> >
>
> [code review, if we go with this design; see my other message for 2
> possible alternative qapi designs that may supersede this code review]
>
> > A simpler approach that is satisfactory for many use
> > cases is to allow the QEMU chardev backends to have a
> > "logfile" property associated with them.
> >
> > $QEMU -chardev socket,host=localhost,port=9000,\
> > server=on,nowait,id-charserial0,\
> > logfile=/var/log/libvirt/qemu/test-serial0.log
> > -device isa-serial,chardev=charserial0,id=serial0
> >
> > This patch introduces a 'ChardevCommon' struct which
> > is setup as a base for all the ChardevBackend types.
> > Ideally this would be registered directly as a base
> > against ChardevBackend, rather than each type, but
> > the QAPI generator doesn't allow that since the
> > ChardevBackend is a non-discriminated union. The
> > ChardevCommon struct provides the optional 'logfile'
> > parameter, as well as 'logappend' which controls
> > whether QEMU truncates or appends (default truncate).
> >
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >
>
> > +++ b/qapi-schema.json
> > @@ -3093,6 +3093,21 @@
> > ##
> > { 'command': 'screendump', 'data': {'filename': 'str'} }
> >
> > +
> > +##
> > +# @ChardevCommon:
> > +#
> > +# Configuration shared across all chardev backends
> > +#
> > +# @logfile: #optional The name of a logfile to save output
> > +# @logappend: #optional true to append instead of truncate
> > +# (default to false to truncate)
>
> Could shorten to:
>
> # @logappend: #optional true to append to @logfile (default false to
> truncate)
>
> > ##
> > # @ChardevBackend:
> > @@ -3243,7 +3269,8 @@
> > #
> > # Since: 1.4 (testdev since 2.2)
> > ##
> > -{ 'struct': 'ChardevDummy', 'data': { } }
> > +{ 'struct': 'ChardevDummy', 'data': { },
> > + 'base': 'ChardevCommon' }
>
> Instead of changing ChardevDummy, you could have deleted this type and done:
>
> >
> > { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
> > 'serial' : 'ChardevHostdev',
> ...
> 'pty': 'ChardevCommon',
> 'null': 'ChardevCommon',
>
> and so on. I don't know which is better.
Yep, me neither. Given the name it felt like some kind of placeholder
for future work, so I left it alone.
> > +/* Not reporting errors from writing to logfile, as logs are
> > + * defined to be "best effort" only */
> > +static void qemu_chr_fe_write_log(CharDriverState *s,
> > + const uint8_t *buf, size_t len)
> > +{
> > + size_t done = 0;
> > + ssize_t ret;
> > +
> > + if (s->logfd < 0) {
> > + return;
> > + }
> > +
> > + while (done < len) {
> > + do {
> > + ret = write(s->logfd, buf + done, len - done);
> > + if (ret == -1 && errno == EAGAIN) {
> > + g_usleep(100);
> > + }
>
> Do we really want to be sleeping here?
If logfile points to a plain file, you'll never get EAGAIN.
For that matter even if it doesn't point to a plain file
I realize that we've not called qemu_nonblock() on logfd,
so it'll never get EAGAIN for that reason either.
The qemu_chr_fe_write_all() currently has the same usleep
which is what I followed. The qemu_chr_fe_write() just
returns on EAGAIN. In the write_log() method we want to
try to write all the data the qemu_chr_fe_write/write_all
just sent. If we ignore EGAIN, we'll potentially loose
data from the log, but if we honour it, we have to sleep
a little or not set O_NONBLOCK.
>
> > + } while (ret == -1 && errno == EAGAIN);
> > +
> > + if (ret <= 0) {
>
> Why '<='? Shouldn't this be '<'?
Well there's no difference really since write() will never
return 0.
>
> > + return;
> > + }
> > + done += ret;
> > + }
> > +}
> > +
>
> >
> > +
> > +static int qemu_chr_open_common(CharDriverState *chr,
> > + ChardevBackend *backend,
> > + Error **errp)
> > +{
> > + ChardevCommon *common = backend->u.data;
>
> Phooey. This conflicts with my pending patches to get rid of 'data':
>
> http://repo.or.cz/qemu/ericb.git/commitdiff/84aaab99
>
> I mentioned above that you could do things like 'null':'ChardevCommon'
> instead of 'null':'ChardevDummy'; and we also know that qapi guarantees
> a layout where all base types occur at the front of the rest of the
> type. So you could write this as:
>
> ChardevCommon *common = backend->u.null;
>
> and things will work even when 'data' is gone. But maybe that argues
> more strongly that we should hoist the common members into the base
> fields of ChardevBackend struct, or even as separate parameters to the
> 'chardev-add' command (the two alternate qapi representations I
> described in my other message).
>
> > +
> > + if (common->has_logfile) {
> > + int flags = O_WRONLY | O_CREAT;
> > + if (!common->has_logappend ||
> > + !common->logappend) {
> > + flags |= O_TRUNC;
> > + }
>
> Umm, don't you need to set O_APPEND when common->logappend is true?
>
> > + chr->logfd = qemu_open(common->logfile, flags, 0666);
> ...
> > @@ -367,9 +432,16 @@ static CharDriverState *qemu_chr_open_null(const char *id,
> > CharDriverState *chr;
> >
> > chr = qemu_chr_alloc();
> > + if (qemu_chr_open_common(chr, backend, errp) < 0) {
> > + goto error;
> > + }
>
> The other thing we could do here is have qemu_chr_open_common() take a
> ChardevCommon* instead of a ChardevBackend*. Then each caller would do
> an appropriate upcast before calling the common code:
>
> ChardevCommon *common = qapi_ChardevDummy_base(backend->u.null);
> if (qemu_chr_open_common(chr, common, errp) {
Yep, I think this is the easiest thing todo, to avoid use of
backend->u.data.
> and so forth. That feels a bit more type-safe (and less reliant on qapi
> layout guarantees) than trying to rely on the backend->u.data that I'm
> trying to get rid of.
Agreed
> > +++ b/qemu-options.hx
> > @@ -2034,40 +2034,43 @@ The general form of a character device option is:
> > ETEXI
> >
> > DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
> > - "-chardev null,id=id[,mux=on|off]\n"
> > + "-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
>
> Do we want to allow logappend=on even when logfile is unspecified, or
> should we make that an error?
I figured it was harmless to just ignore it.
Regards,
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 :|
next prev parent reply other threads:[~2015-12-23 11:33 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-22 18:17 [Qemu-devel] [PATCH v2] qemu-char: add logfile facility to all chardev backends Daniel P. Berrange
2015-12-22 18:45 ` Eric Blake
2015-12-23 11:24 ` Daniel P. Berrange
2015-12-23 15:41 ` Eric Blake
2015-12-22 19:07 ` Eric Blake
2015-12-23 11:32 ` Daniel P. Berrange [this message]
2015-12-23 15:45 ` Eric Blake
2015-12-23 11:34 ` Paolo Bonzini
2015-12-23 11:43 ` Daniel P. Berrange
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151223113214.GH20028@redhat.com \
--to=berrange@redhat.com \
--cc=eblake@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).