On Sun, 9 May 2004, Akinori MUSHA wrote: > At Sun, 9 May 2004 00:48:27 +1000 (EST), > Bruce Evans wrote: > > ffs uses vfs_timestamp() which gives a timestamp with the precision > > specified by vfs.timestamp_precision. The default is 0 (TSP_SEC), > > which means that timestamps on files are normally in seconds with > > nanoseconds part 0. This can be changed easily using sysctl, but > > changing the precision to the highest (nanoseconds) gives the bugs > > being discussed. Changing it to microseconds precision is safer, > > since utimes(2) (but not utime(2) supports this precision. > > > > The only other way to get ffs timestamps with a nonzero nanseconds > > part is to use utimes(), but this gives microseconds precision which > > utimes() can copy later. > > Hm, I never changed vfs.timestamp_precision to anything other than the > default (nor even knew of it), but I acutually observed some files > having ...032 and ...256 nanoseconds on an NFS exported FFS on > 4-STABLE. I'm not sure if the files were created directly on FFS or > via NFS. > > Does that mean there could be a bug somewhere around nanotime() calls? The most obvious bug is that nfsclient has no reference to VA_UTIMES_NULL. I think this cause it to use stack garbage for tv_nsec. This seems to be fixed in NetBSD. Demonstration of the bug: %%% Script started on Sun May 9 17:29:21 2004 ttyv2:bde_at_gamplex:/c/z> cat foo.c main(int argc, char **argv) { utimes(argv[1], 0); } ttyv2:bde_at_gamplex:/c/z> cc -o foo foo.c ttyv2:bde_at_gamplex:/c/z> /usr/bin/stat -f "%N %Fm" foo foo 1084087769.000000000 ttyv2:bde_at_gamplex:/c/z> ./foo foo ttyv2:bde_at_gamplex:/c/z> /usr/bin/stat -f "%N %Fm" foo foo 1084087802.503363000 ttyv2:bde_at_gamplex:/c/z> ./foo foo ttyv2:bde_at_gamplex:/c/z> /usr/bin/stat -f "%N %Fm" foo foo 1084087824.912722647 ttyv2:bde_at_gamplex:/c/z> exit Script done on Sun May 9 17:30:36 2004 %%% After cc -o foo, foo has a normal mtime set by writing on the server (-current nfsv3 server with vfs.timestamp_precision=0). Then running utimes("foo", 0) on the client messes up foo's st_mtime.tv_nsec. Somehow it avoids messing up foo's st_mtime.tv_sec, and on the first run it rounds to the nearest usec (this behaviour seems to be consistent). I think utimes("foo", 0) should run on the client and set the times to the current time on the client just like utimes("foo", non_null) would set to times obtained from somewhere on the client. However, I think the times should always be rounded (by the server) according to the server's vfs.timestamp_precision. Clients can't be expected to do this since they might not support a timestamp precision. More precision than the server would set for writes would be less than useful. Here is part of the NetBSD code for supporting VA_UTIMES_NULL (atimes are handled similarly for TOSERVER, but not for TOCLIENT -- VA_UTIMES_NULL Is not used then): nfsm_subs.h 1.36: % #define nfsm_srvsattr(a) \ % ... \ % switch (fxdr_unsigned(int, *tl)) { \ % case NFSV3SATTRTIME_TOCLIENT: \ % nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ % fxdr_nfsv3time(tl, &(a)->va_mtime); \ % (a)->va_vaflags &= ~VA_UTIMES_NULL; \ % break; \ % case NFSV3SATTRTIME_TOSERVER: \ % (a)->va_mtime.tv_sec = time.tv_sec; \ % (a)->va_mtime.tv_nsec = time.tv_usec * 1000; \ % (a)->va_vaflags |= VA_UTIMES_NULL; \ % break; \ % }; } The corresponding code in -current is: nfs_srvsubs.c: % int % nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) % ... % switch (fxdr_unsigned(int, *tl)) { % case NFSV3SATTRTIME_TOCLIENT: % tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); % if (tl == NULL) % return EBADRPC; % fxdr_nfsv3time(tl, &(a)->va_mtime); % break; % case NFSV3SATTRTIME_TOSERVER: % getnanotime(&(a)->va_mtime); % break; % } Looks like I was wrong about the client handling VA_UTIMES_NULL -- the above seems to run on the server. I don't understand what it is doing with VA_UTIMES_NULL. Other aspects of the bug are clearer: using getnanotime() instead of vfs_timestamp() breaks the policy set in vfs.timestamp_precision. It wrong anyway since it gives excessive precision -- getnanotime() has at most 1/HZ accuracy. `time' used to have the same accuracy and perhaps still does in NetBSD, but using it gives 3 fewer digits of excessive precision and is friendlier with utimes(). THe quick fix is to replace the above getnanotime() with vfs_timestamp(). Unfortunately, nfs has 16 other calls to getnanotime(), 2 calls to microtime() and 3 calls to getmicrotime() that need to be checked. BruceReceived on Sat May 08 2004 - 23:24:55 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:53 UTC