From cc731cb6da2f45cdff221f298cf0c7b1131f63d3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 30 Jan 2014 13:57:45 +0400 Subject: [PATCH] irmap: Revalidate irmap entries if required We will load some irmap entries in cache from image file, thus producing potentially stale data in irmap cache. To handle this, make it possible to mark the entries with need-revalidation mark and do fstat + numbers comparison when meeting the entry in cache. Signed-off-by: Pavel Emelyanov --- irmap.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/irmap.c b/irmap.c index aca773d4d..7d326c403 100644 --- a/irmap.c +++ b/irmap.c @@ -39,7 +39,7 @@ struct irmap { unsigned long ino; char *path; struct irmap *next; - + bool revalidate; int nr_kids; struct irmap *kids; }; @@ -69,6 +69,7 @@ static int irmap_update_stat(struct irmap *i) return -1; } + i->revalidate = false; i->dev = st.st_dev; i->ino = st.st_ino; if (!S_ISDIR(st.st_mode)) @@ -172,28 +173,65 @@ static struct irmap *irmap_scan(struct irmap *t, unsigned int dev, unsigned long return NULL; } +static int irmap_revalidate(struct irmap *c, struct irmap **p) +{ + struct stat st; + + pr_debug("Revalidate stat for %s\n", c->path); + if (fstatat(mntns_root, c->path + 1, &st, AT_SYMLINK_NOFOLLOW)) { + /* File can be (re)moved, so just treat it as invalid */ + pr_perror("Can't stat %s", c->path); + goto invalid; + } + + if (c->dev != st.st_dev) + goto invalid; + if (c->ino != st.st_ino) + goto invalid; + + c->revalidate = false; + return 0; + +invalid: + pr_debug("\t%x:%lx is invalid\n", c->dev, c->ino); + *p = c->next; + xfree(c->path); + xfree(c); + return 1; +} + char *irmap_lookup(unsigned int s_dev, unsigned long i_ino) { - struct irmap *c, *h; + struct irmap *c, *h, **p; + char *path = NULL; int hv; pr_debug("Resolving %x:%lx path\n", s_dev, i_ino); hv = irmap_hashfn(s_dev, i_ino); - for (c = cache[hv]; c; c = c->next) - if (c->dev == s_dev && c->ino == i_ino) { - pr_debug("\tFound %s in cache\n", c->path); - return c->path; - } + for (p = &cache[hv]; *p; p = &(*p)->next) { + c = *p; + if (!(c->dev == s_dev && c->ino == i_ino)) + continue; + + if (c->revalidate && irmap_revalidate(c, p)) + continue; + + pr_debug("\tFound %s in cache\n", c->path); + path = c->path; + goto out; + } for (h = hints; h->path; h++) { pr_debug("Scanning %s hint\n", h->path); c = irmap_scan(h, s_dev, i_ino); if (c) { pr_debug("\tScanned %s\n", c->path); - return c->path; + path = c->path; + goto out; } } - return NULL; +out: + return path; }