From owner-freebsd-bugs@FreeBSD.ORG Thu Jun 21 16:20:13 2012 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 72EA9106566C for ; Thu, 21 Jun 2012 16:20:13 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 522208FC1A for ; Thu, 21 Jun 2012 16:20:13 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5LGKDsV017771 for ; Thu, 21 Jun 2012 16:20:13 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5LGKDXm017770; Thu, 21 Jun 2012 16:20:13 GMT (envelope-from gnats) Date: Thu, 21 Jun 2012 16:20:13 GMT Message-Id: <201206211620.q5LGKDXm017770@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Bruce Evans Cc: Subject: Re: kern/169282: utimes does not update st_mtim.tv_nsec when utimes(file, NULL) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Bruce Evans List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Jun 2012 16:20:13 -0000 The following reply was made to PR kern/169282; it has been noted by GNATS. From: Bruce Evans To: Shinji KOBAYASHI Cc: freebsd-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org Subject: Re: kern/169282: utimes does not update st_mtim.tv_nsec when utimes(file, NULL) Date: Fri, 22 Jun 2012 02:10:19 +1000 (EST) 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 > #include > #include > #include > > 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 > #include > #include > #include > > 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