Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Jun 2012 02:10:19 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Shinji KOBAYASHI <skoba@moss.gr.jp>
Cc:        freebsd-bugs@FreeBSD.org, freebsd-gnats-submit@FreeBSD.org
Subject:   Re: kern/169282: utimes does not update st_mtim.tv_nsec when utimes(file, NULL)
Message-ID:  <20120622012931.W2954@besplex.bde.org>
In-Reply-To: <201206210340.q5L3eWPn081664@red.freebsd.org>
References:  <201206210340.q5L3eWPn081664@red.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 21 Jun 2012, Shinji KOBAYASHI wrote:

>> Description:
> man utimes 2 shows that utimes(file, NULL) updates file modified time to current time. But the sample code shows tv_mtim.tv_nsec equals 0, after utimes(file, NULL).

It sets tv_mtim to the current time in the current timestamp precision.
The default timestamp precision is 1 second, and you apparently didn't
change this, so tv_nsec should be 0 for all times.  See vfs_timestamp(9).
The correct man page (a user one for the vfs.timestamp_precision sysctl)
unfortunately doesn't exist.

> filetest.c
> ----
> include <sys/time.h>
> #include <sys/stat.h>
> #include <stdio.h>
> #include <unistd.h>
>
> int main(void) {
>  char *name;
>  struct stat filestatus;
>  int fd;
>  int second;
>  int nanosecond;
>  name = "t.log";
>
>  fd = creat(name, 0666);
>  fstat(fd, &filestatus);
>  second = filestatus.st_mtim.tv_sec;
>  nanosecond = filestatus.st_mtim.tv_nsec;
>  printf("File created time %d sec,%d nsec\n", second, nanosecond);
>  usleep(1000100);
>  utimes(name, NULL);
>  fstat(fd, &filestatus);
>  printf("File modified time %d sec, %dnsec\n", filestatus.st_mtim.tv_sec, filestatus.st_mtim.tv_nsec);
>  usleep(1000100);
>  creat(name);
>  fstat(fd, &filestatus);
>  printf("File modified time %d sec, %dnsec\n", filestatus.st_mtim.tv_sec, filestatus.st_mtim.tv_nsec);
>  return 0;
> }
> ---
> The result:
> shuttle% ./filetest                                                       ~/src
> File created time 1340243920 sec,662186384 nsec
> File modified time 1340243921 sec, 0nsec
> File modified time 1340243922 sec, 666190831nsec
>
>> How-To-Repeat:
> filetest.c
> ----
> include <sys/time.h>
> #include <sys/stat.h>
> #include <stdio.h>
> #include <unistd.h>
>
> int main(void) {
>  char *name;
>  struct stat filestatus;
>  int fd;
>  int second;
>  int nanosecond;
>  name = "t.log";
>
>  fd = creat(name, 0666);
>  fstat(fd, &filestatus);
>  second = filestatus.st_mtim.tv_sec;
>  nanosecond = filestatus.st_mtim.tv_nsec;
>  printf("File created time %d sec,%d nsec\n", second, nanosecond);
>  usleep(1000100);
>  utimes(name, NULL);
>  fstat(fd, &filestatus);
>  printf("File modified time %d sec, %dnsec\n", filestatus.st_mtim.tv_sec, filestatus.st_mtim.tv_nsec);
>  usleep(1000100);
>  creat(name);
>  fstat(fd, &filestatus);
>  printf("File modified time %d sec, %dnsec\n", filestatus.st_mtim.tv_sec, filestatus.st_mtim.tv_nsec);
>  return 0;
> }
> ---
> The result:
> shuttle% cc -o filetest filetest.c
> shuttle% ./filetest                                                       ~/src
> File created time 1340243920 sec,662186384 nsec
> File modified time 1340243921 sec, 0nsec
> File modified time 1340243922 sec, 666190831nsec

The bug is in the other times.  They should have a nanoseconds part that
is consistently 0.

You didn't say which file system you run these test on, but I don't
know of any except zfs and maybe msdosfs which would give this bug.

zfs seems to hard-code the timestamp precision as index 1, by using
gethrestime() to get the time, where gethrestime() is implemented as
getnanotime().  It should be implemented as vfs_timestamp() (at least
if it is only used for file times).

msdosfs harder-codes timestamp calls as getnanotime(), but usually the
problem isn't noticeable with it since its timestamp resolution is
usually even less than 1 second.

Related bugs:

1. vfs_timestamp(9) documents precision index 1 as being accurate to
    within 1/HZ.  Precision index 1 actually gives accuraty of $(sysctl
    kern.timecounter.tick)/hz.  This is about 1/hz or 1 msec, whichever
    is least.  The sysctl description and the comments and enum names
    in the source code for vfs.timestamp_precision have the same bug.)

2. vfs_timestamp() with precision index 1 gives garbage in the low
    digits of the nanoseconds part.  Since its precision with this
    index is at most 1 msec, at least 6 of the 9 digits are garbage.
    The garbage might be useful in some contexts, but not for file
    times.  File times can't even be written without clearing the 3
    low digits in the nanoseconds part.  All other indexes give
    rounding of the nanoseconds part down to a multiple of the
    precision.  For example, index 2 gives a precision of 1 usec with
    rounding down, so although it is much more precise and accurate
    than index 1, the garbage makes index 1 look more precise and
    accurate.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120622012931.W2954>