[libvirt] [PATCH 17/23] Introduce basic infrastructure for virtlockd daemon

Eric Blake eblake at redhat.com
Fri Aug 17 12:45:20 UTC 2012


On 08/09/2012 09:20 AM, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
> 
> The virtlockd daemon will maintain locks on behalf of libvirtd.
> There are two reasons for it to be separate
> 
>  - Avoid risk of other libvirtd threads accidentally
>    releasing fcntl() locks by opening + closing a file
>    that is locked
>  - Ensure locks can be preserved across libvirtd restarts.
>    virtlockd will need to be able to re-exec itself while
>    maintaining locks. This is simpler to achieve if its
>    sole job is maintaining locks
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
>  .gitignore                    |   2 +
>  cfg.mk                        |   6 +-
>  libvirt.spec.in               |   7 +
>  po/POTFILES.in                |   1 +
>  src/Makefile.am               |  86 ++++-
>  src/locking/lock_daemon.c     | 750 ++++++++++++++++++++++++++++++++++++++++++
>  src/locking/lock_daemon.h     |  43 +++
>  src/locking/virtlockd.init.in |  93 ++++++
>  src/locking/virtlockd.sysconf |   3 +
>  9 files changed, 987 insertions(+), 4 deletions(-)
>  create mode 100644 src/locking/lock_daemon.c
>  create mode 100644 src/locking/lock_daemon.h
>  create mode 100644 src/locking/virtlockd.init.in
>  create mode 100644 src/locking/virtlockd.sysconf

I had a merge failure trying to apply this; you'll need a minor context
rebase in cfg.mk to use this.

> +++ b/cfg.mk
> @@ -636,6 +636,8 @@ sc_prohibit_cross_inclusion:
>  	@for dir in $(cross_dirs); do					\
>  	  case $$dir in							\
>  	    util/) safe="util";;					\
> +	    locking/)							\
> +	      safe="($$dir|util|conf|rpc)";;				\

You added a new branch for locking...

>  	    cpu/ | locking/ | network/ | rpc/ | security/)		\

...so this branch won't be reached, so you should clean it up while here.

> +++ b/src/Makefile.am

> +
> +install-sysconfig:
> +	mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig

Shouldn't we be using $(MKDIR_P) instead?

> +	$(INSTALL_DATA) $(srcdir)/locking/virtlockd.sysconf \
> +	  $(DESTDIR)$(sysconfdir)/sysconfig/virtlockd
> +
> +uninstall-sysconfig:
> +	rm -f $(DESTDIR)$(sysconfdir)/sysconfig/virtlockd
> +
> +EXTRA_DIST += locking/virtlockd.init.in
> +
> +if WITH_LIBVIRTD
> +if LIBVIRT_INIT_SCRIPT_RED_HAT
> +install-init:: virtlockd.init install-sysconfig
> +	mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d

and again.

> +++ b/src/locking/lock_daemon.c

> +enum {
> +    VIR_LOCK_DAEMON_ERR_NONE = 0,
> +    VIR_LOCK_DAEMON_ERR_PIDFILE,
> +    VIR_LOCK_DAEMON_ERR_RUNDIR,
> +    VIR_LOCK_DAEMON_ERR_INIT,
> +    VIR_LOCK_DAEMON_ERR_SIGNAL,
> +    VIR_LOCK_DAEMON_ERR_PRIVS,
> +    VIR_LOCK_DAEMON_ERR_NETWORK,
> +    VIR_LOCK_DAEMON_ERR_CONFIG,
> +    VIR_LOCK_DAEMON_ERR_HOOKS,

Is it worth using '= 1', '= 2', and so forth, to make future extensions
aware that they must not be in the middle, since this is tied to RPC
protocol?

> +static int
> +virLockDaemonForkIntoBackground(const char *argv0)
> +{
> +    int statuspipe[2];
> +    if (pipe(statuspipe) < 0)
> +        return -1;
> +
> +    pid_t pid = fork();
> +    switch (pid) {
> +    case 0:
> +        {
> +            int stdinfd = -1;
> +            int stdoutfd = -1;
> +            int nextpid;
> +
> +            VIR_FORCE_CLOSE(statuspipe[0]);
> +
> +            if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
> +                goto cleanup;
> +            if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
> +                goto cleanup;
> +            if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
> +                goto cleanup;
> +            if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
> +                goto cleanup;
> +            if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
> +                goto cleanup;
> +            if (VIR_CLOSE(stdinfd) < 0)
> +                goto cleanup;
> +            if (VIR_CLOSE(stdoutfd) < 0)
> +                goto cleanup;

Oops - this can blindly re-close stdin or stdout or stderr if the parent
process had those fds closed.  It must be:

if (stdinfd > STDERR_FILENO && VIR_CLOSE(stdinfd) < 0)
    goto cleanup;
stdinfd = -1;
if (stdoutfd > STDERR_FILENO && VIR_CLOSE(stdoutfd) < 0)
    goto cleanup;
stdoutfd = -1;

> +
> +            if (setsid() < 0)
> +                goto cleanup;
> +
> +            nextpid = fork();
> +            switch (nextpid) {
> +            case 0:
> +                return statuspipe[1];
> +            case -1:
> +                return -1;
> +            default:
> +                _exit(0);

_exit(EXIT_SUCCESS) (I thought we had a syntax check for this - oh, I
see - that rule checked for 'exit' but not '_exit' or '_Exit'. Gnulib
patch coming up).

> +            if (ret == 1 && status != 0) {
> +                fprintf(stderr,
> +                        _("%s: error: %s. Check /var/log/messages or run without "
> +                          "--daemon for more info.\n"), argv0,
> +                        virDaemonErrTypeToString(status));
> +            }
> +            _exit(ret == 1 && status == 0 ? 0 : 1);

Another case where EXIT_{SUCCESS,FAILURE} looks better.

> +
> +    /*
> +     * Command line override for --verbose
> +     */
> +    if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))

Copy and paste, but these are redundant ().  Why are we copying so much
code? Should some of this live in a common file under util, to be used
by both this file and daemon/libvirtd.c?

> +static int
> +virLockDaemonSetupSignals(virNetServerPtr srv)
> +{
> +    if (virNetServerAddSignalHandler(srv, SIGINT, virLockDaemonShutdownHandler, NULL) < 0)
> +        return -1;
> +    if (virNetServerAddSignalHandler(srv, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0)
> +        return -1;
> +    if (virNetServerAddSignalHandler(srv, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0)
> +        return -1;

Do we need to worry about setting SIGPIPE to a known state?

> +static void
> +virLockDaemonUsage(const char *argv0)
> +{
> +    fprintf (stderr,
> +             _("\n\
> +Usage:\n\
> +  %s [options]\n\
> +\n\
> +Options:\n\
> +  -v | --verbose         Verbose messages.\n\
> +  -d | --daemon          Run as a daemon & write PID file.\n\
> +  -t | --timeout <secs>  Exit after timeout period.\n\
> +  -f | --config <file>   Configuration file.\n\
> +     | --version         Display version information.\n\
> +  -p | --pid-file <file> Change name of PID file.\n\

Shouldn't we also list '--help' as an option?

> +
> +enum {
> +    OPT_VERSION = 129

129 is still a valid character in single-byte locales, which someone
could pass in from the command line via a short option and possibly mess
up getopt_long.  I think you want it to be 256 or greater.

> +    struct option opts[] = {
> +        { "verbose", no_argument, &verbose, 1},
> +        { "daemon", no_argument, &godaemon, 1},

Why do these two use the non-NULL flag argument, instead of the more
typical "NULL, 'd'" layout...

> +        { "config", required_argument, NULL, 'f'},
> +        { "timeout", required_argument, NULL, 't'},
> +        { "pid-file", required_argument, NULL, 'p'},
> +        { "version", no_argument, NULL, OPT_VERSION },
> +        { "help", no_argument, NULL, '?' },
> +        {0, 0, 0, 0}
> +    };
> +

> +        switch (c) {
> +        case 0:
> +            /* Got one of the flags */
> +            break;
> +        case 'v':
> +            verbose = 1;
> +            break;
> +        case 'd':
> +            godaemon = 1;
> +            break;

...especially since here you also handle short options for the same
task, which do the same work?  (I know, copy and paste from a bad
example in libvirtd.c)

> +
> +        case '?':
> +            virLockDaemonUsage(argv[0]);
> +            return 2;

That says that 'virtlockd --help' will fail with status 2, even when it
successfully printed the usage message.  I think you need to route
--help slightly differently than the default handling of getopt_long
error handling, if only to control the exit status differently (again,
copying from a bad example).

Looks mostly reasonable.

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120817/6db32c5b/attachment-0001.sig>


More information about the libvir-list mailing list