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>
This commit is contained in:
Karel Zak 2010-03-17 14:49:14 +01:00
parent abbd79ac35
commit 6c2f2b9d62
6 changed files with 51 additions and 16 deletions

View File

@ -601,6 +601,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_CHECK_MEMBERS([struct termios.c_line],,,
[[#include <termios.h>]])
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec],,,
[#include <sys/stat.h>])
AC_CHECK_DECLS([
ADDR_NO_RANDOMIZE,
FDPIC_FUNCPTRS,

View File

@ -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>
#include <stdint.h>
@ -45,6 +46,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 */

View File

@ -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);

View File

@ -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, blkid_dev dev, char **cp)
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);

View File

@ -37,9 +37,11 @@ static int save_dev(blkid_dev dev, FILE *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) {

View File

@ -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, blkid_dev dev)
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, blkid_dev dev)
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;