[libvirt] [PATCH] xen: fix race in refresh of config cache
Richard W.M. Jones
rjones at redhat.com
Fri Sep 11 14:02:40 UTC 2015
On Fri, Sep 11, 2015 at 02:41:02PM +0100, Daniel P. Berrange wrote:
> The xenXMConfigCacheRefresh method scans /etc/xen and loads
> all config files it finds. It then scans its internal hash
> table and purges any (previously) loaded config files whose
> refresh timestamp does not match the timestamp recorded at
> the start of xenXMConfigCacheRefresh(). There is unfortunately
> a subtle flaw in this, because if loading the config files
> takes longer than 1 second, some of the config files will
> have a refresh timestamp that is 1 or more seconds different
> (newer) than is checked for. So we immediately purge a bunch
> of valid config files we just loaded.
>
> To avoid this flaw, we must pass the timestamp we record at
> the start of xenXMConfigCacheRefresh() into the
> xenXMConfigCacheAddFile() method, instead of letting the
> latter call time(NULL) again.
>
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
> src/xen/xen_inotify.c | 10 ++++++----
> src/xen/xm_internal.c | 7 +++----
> src/xen/xm_internal.h | 2 +-
> 3 files changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c
> index cd1e2df..d81a35d 100644
> --- a/src/xen/xen_inotify.c
> +++ b/src/xen/xen_inotify.c
> @@ -217,11 +217,11 @@ xenInotifyRemoveDomainConfigInfo(virConnectPtr conn, const char *fname)
> }
>
> static int
> -xenInotifyAddDomainConfigInfo(virConnectPtr conn, const char *fname)
> +xenInotifyAddDomainConfigInfo(virConnectPtr conn, const char *fname, time_t now)
> {
> xenUnifiedPrivatePtr priv = conn->privateData;
> return priv->useXenConfigCache ?
> - xenXMConfigCacheAddFile(conn, fname) :
> + xenXMConfigCacheAddFile(conn, fname, now) :
> xenInotifyXendDomainsDirAddEntry(conn, fname);
> }
>
> @@ -238,6 +238,7 @@ xenInotifyEvent(int watch ATTRIBUTE_UNUSED,
> char *tmp, *name;
> virConnectPtr conn = data;
> xenUnifiedPrivatePtr priv = NULL;
> + time_t now = time(NULL);
>
> VIR_DEBUG("got inotify event");
>
> @@ -300,7 +301,7 @@ xenInotifyEvent(int watch ATTRIBUTE_UNUSED,
> }
> } else if (e->mask & (IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO)) {
> virObjectEventPtr event;
> - if (xenInotifyAddDomainConfigInfo(conn, fname) < 0) {
> + if (xenInotifyAddDomainConfigInfo(conn, fname, now) < 0) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> "%s", _("Error adding file to config cache"));
> goto cleanup;
> @@ -344,6 +345,7 @@ xenInotifyOpen(virConnectPtr conn,
> char *path;
> xenUnifiedPrivatePtr priv = conn->privateData;
> int direrr;
> + time_t now = time(NULL);
>
> virCheckFlags(VIR_CONNECT_RO, -1);
>
> @@ -374,7 +376,7 @@ xenInotifyOpen(virConnectPtr conn,
> return -1;
> }
>
> - if (xenInotifyAddDomainConfigInfo(conn, path) < 0) {
> + if (xenInotifyAddDomainConfigInfo(conn, path, now) < 0) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> "%s", _("Error adding file to config list"));
> closedir(dh);
> diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
> index 59b1cd4..07b9eb4 100644
> --- a/src/xen/xm_internal.c
> +++ b/src/xen/xm_internal.c
> @@ -191,15 +191,14 @@ xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename)
> * calling this function
> */
> int
> -xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
> +xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename, time_t now)
> {
> xenUnifiedPrivatePtr priv = conn->privateData;
> xenXMConfCachePtr entry;
> struct stat st;
> int newborn = 0;
> - time_t now = time(NULL);
>
> - VIR_DEBUG("Adding file %s", filename);
> + VIR_DEBUG("Adding file %s %lld", filename, (long long)now);
>
> /* Get modified time */
> if ((stat(filename, &st) < 0)) {
> @@ -373,7 +372,7 @@ xenXMConfigCacheRefresh(virConnectPtr conn)
>
> /* If we already have a matching entry and it is not
> modified, then carry on to next one*/
> - if (xenXMConfigCacheAddFile(conn, path) < 0) {
> + if (xenXMConfigCacheAddFile(conn, path, now) < 0) {
> /* Ignoring errors, since a lot of stuff goes wrong in /etc/xen */
> }
>
> diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h
> index 25b4fd5..0246895 100644
> --- a/src/xen/xm_internal.h
> +++ b/src/xen/xm_internal.h
> @@ -31,7 +31,7 @@
> # include "domain_conf.h"
>
> int xenXMConfigCacheRefresh (virConnectPtr conn);
> -int xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename);
> +int xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename, time_t now);
> int xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename);
>
> int xenXMOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags);
Good one :-)
ACK.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine. Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/
More information about the libvir-list
mailing list