This is backport from upstream, this version of the patch requires glibc and kernel >= 2.5.48. The stat.st_mtim availability is not checked to avoid changes to ./configure script. It should be fine for Fedora/RHEL. --kzak 18-Mar-2010 commit message from the original patch: commit 6c2f2b9d62b196296e827f8bb7336a39e80695a9 Author: Karel Zak <kzak@redhat.com> Date: Wed Mar 17 14:49:14 2010 +0100 libblkid: add microsecond resolution for cache entries The libblkid library uses stat.st_mtine to detect changes on the device. The last update time of of the device in the cache is stored as TIME= tag in the /etc/blkid.tab file. Linux since 2.5.48 supports nanosecond resolution and more precise time is available in the stat.st_mtim timespec struct. This patch add microsecond precision to TIME= tag in the cache file, old format: TIME="<sec>" the new format: TIME="<sec>.<usec>" This change is backwardly compatible. Now, the blkid_verify() function checks stat.st_mtime and stat.st_mtim.tv_nsec/1000. Test: # e2label /dev/sdb1 AAAA old version: # blkid -s LABEL /dev/sdb1; e2label /dev/sdb1 BBBB; blkid -s LABEL /dev/sdb1 /dev/sdb1: LABEL="AAAA" /dev/sdb1: LABEL="AAAA" new version: # blkid -s LABEL /dev/sdb1; e2label /dev/sdb1 BBBB; blkid -s LABEL /dev/sdb1 /dev/sdb1: LABEL="AAAA" /dev/sdb1: LABEL="BBBB" Signed-off-by: Karel Zak <kzak@redhat.com> diff -up util-linux-ng-2.17.1/shlibs/blkid/src/blkidP.h.kzak util-linux-ng-2.17.1/shlibs/blkid/src/blkidP.h --- util-linux-ng-2.17.1/shlibs/blkid/src/blkidP.h.kzak 2010-03-18 14:48:12.000000000 +0100 +++ util-linux-ng-2.17.1/shlibs/blkid/src/blkidP.h 2010-03-18 15:01:36.000000000 +0100 @@ -19,6 +19,7 @@ #include <sys/types.h> #include <dirent.h> #include <sys/stat.h> +#include <sys/types.h> #include <stdio.h> #include <stdarg.h> @@ -28,6 +29,9 @@ #include "blkid.h" #include "list.h" +/* enable microsecond resolution for the cache */ +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 + /* * This describes the attributes of a specific device. * We can traverse all of the tags by bid_tags (linking to the tag bit_names). @@ -44,6 +48,7 @@ struct blkid_struct_dev int bid_pri; /* Device priority */ dev_t bid_devno; /* Device major/minor number */ time_t bid_time; /* Last update time of device */ + suseconds_t bid_utime; /* Last update time (microseconds) */ unsigned int bid_flags; /* Device status bitflags */ char *bid_label; /* Shortcut to device LABEL */ char *bid_uuid; /* Shortcut to binary UUID */ diff -up util-linux-ng-2.17.1/shlibs/blkid/src/dev.c.kzak util-linux-ng-2.17.1/shlibs/blkid/src/dev.c --- util-linux-ng-2.17.1/shlibs/blkid/src/dev.c.kzak 2010-02-04 12:53:58.000000000 +0100 +++ util-linux-ng-2.17.1/shlibs/blkid/src/dev.c 2010-03-18 14:58:23.000000000 +0100 @@ -84,7 +84,7 @@ void blkid_debug_dump_dev(blkid_dev dev) printf(" dev: name = %s\n", dev->bid_name); printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); - printf(" dev: TIME=\"%ld\"\n", (long)dev->bid_time); + printf(" dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime); printf(" dev: PRI=\"%d\"\n", dev->bid_pri); printf(" dev: flags = 0x%08X\n", dev->bid_flags); diff -up util-linux-ng-2.17.1/shlibs/blkid/src/read.c.kzak util-linux-ng-2.17.1/shlibs/blkid/src/read.c --- util-linux-ng-2.17.1/shlibs/blkid/src/read.c.kzak 2010-02-04 12:53:58.000000000 +0100 +++ util-linux-ng-2.17.1/shlibs/blkid/src/read.c 2010-03-18 14:58:23.000000000 +0100 @@ -49,7 +49,8 @@ static void debug_dump_dev(blkid_dev dev * * The following tags are required for each entry: * <ID="id"> unique (within this file) ID number of this device - * <TIME="time"> (ascii time_t) time this entry was last read from disk + * <TIME="sec.usec"> (time_t and suseconds_t) time this entry was last + * read from disk * <TYPE="type"> (detected) type of filesystem/data for this partition * * The following tags may be present, depending on the device contents @@ -318,9 +319,12 @@ static int parse_tag(blkid_cache cache, dev->bid_devno = STRTOULL(value, 0, 0); else if (!strcmp(name, "PRI")) dev->bid_pri = strtol(value, 0, 0); - else if (!strcmp(name, "TIME")) - dev->bid_time = STRTOULL(value, 0, 0); - else + else if (!strcmp(name, "TIME")) { + char *end = NULL; + dev->bid_time = STRTOULL(value, &end, 0); + if (end && *end == '.') + dev->bid_utime = STRTOULL(end + 1, 0, 0); + } else ret = blkid_set_tag(dev, name, value, strlen(value)); DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value)); @@ -455,7 +459,7 @@ static void debug_dump_dev(blkid_dev dev printf(" dev: name = %s\n", dev->bid_name); printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); - printf(" dev: TIME=\"%lld\"\n", (long long)dev->bid_time); + printf(" dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime); printf(" dev: PRI=\"%d\"\n", dev->bid_pri); printf(" dev: flags = 0x%08X\n", dev->bid_flags); diff -up util-linux-ng-2.17.1/shlibs/blkid/src/save.c.kzak util-linux-ng-2.17.1/shlibs/blkid/src/save.c --- util-linux-ng-2.17.1/shlibs/blkid/src/save.c.kzak 2010-02-22 09:41:12.000000000 +0100 +++ util-linux-ng-2.17.1/shlibs/blkid/src/save.c 2010-03-18 14:58:23.000000000 +0100 @@ -37,9 +37,11 @@ static int save_dev(blkid_dev dev, FILE printf("device %s, type %s\n", dev->bid_name, dev->bid_type ? dev->bid_type : "(null)")); - fprintf(file, - "<device DEVNO=\"0x%04lx\" TIME=\"%ld\"", - (unsigned long) dev->bid_devno, (long) dev->bid_time); + fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%ld.%ld\"", + (unsigned long) dev->bid_devno, + (long) dev->bid_time, + (long) dev->bid_utime); + if (dev->bid_pri) fprintf(file, " PRI=\"%d\"", dev->bid_pri); list_for_each(p, &dev->bid_tags) { diff -up util-linux-ng-2.17.1/shlibs/blkid/src/verify.c.kzak util-linux-ng-2.17.1/shlibs/blkid/src/verify.c --- util-linux-ng-2.17.1/shlibs/blkid/src/verify.c.kzak 2010-02-04 12:53:58.000000000 +0100 +++ util-linux-ng-2.17.1/shlibs/blkid/src/verify.c 2010-03-18 14:58:23.000000000 +0100 @@ -11,6 +11,7 @@ #include <unistd.h> #include <fcntl.h> #include <time.h> +#include <sys/time.h> #include <sys/types.h> #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> @@ -73,19 +74,34 @@ blkid_dev blkid_verify(blkid_cache cache return NULL; } - if ((now >= dev->bid_time) && - (st.st_mtime <= dev->bid_time) && - ((diff < BLKID_PROBE_MIN) || - (dev->bid_flags & BLKID_BID_FL_VERIFIED && - diff < BLKID_PROBE_INTERVAL))) + if (now >= dev->bid_time && +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + (st.st_mtime < dev->bid_time || + (st.st_mtime == dev->bid_time && + st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) && +#else + st.st_mtime <= dev->bid_time && +#endif + (diff < BLKID_PROBE_MIN || + (dev->bid_flags & BLKID_BID_FL_VERIFIED && + diff < BLKID_PROBE_INTERVAL))) return dev; +#ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC DBG(DEBUG_PROBE, printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" "time since last check %lu)\n", dev->bid_name, (unsigned long)dev->bid_time, (unsigned long)st.st_mtime, (unsigned long)diff)); - +#else + DBG(DEBUG_PROBE, + printf("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\n\t" + "time since last check %lu)\n", + dev->bid_name, + (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime, + (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000, + (unsigned long)diff)); +#endif if (!cache->probe) { cache->probe = blkid_new_probe(); @@ -156,8 +172,16 @@ blkid_dev blkid_verify(blkid_cache cache found_type: if (dev) { +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + struct timeval tv; + if (!gettimeofday(&tv, NULL)) { + dev->bid_time = tv.tv_sec; + dev->bid_utime = tv.tv_usec; + } else +#endif + dev->bid_time = time(0); + dev->bid_devno = st.st_rdev; - dev->bid_time = time(0); dev->bid_flags |= BLKID_BID_FL_VERIFIED; cache->bic_flags |= BLKID_BIC_FL_CHANGED;