Mercurial > hg > octave-lyh > gnulib-hg
changeset 12172:52ebfd595434
utimens: cache whether utimensat syscall works
No need to repeatedly try utimensat on older Linux kernel.
* lib/utimens.c (utimensat_works_really): New cache variable.
(fdutimens, lutimens): Use it to avoid failing syscall.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Mon, 12 Oct 2009 14:56:22 -0600 |
parents | 47c9f1788846 |
children | efdb2ab5743f |
files | ChangeLog lib/utimens.c |
diffstat | 2 files changed, 75 insertions(+), 48 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-10-16 Eric Blake <ebb9@byu.net> + utimens: cache whether utimensat syscall works + * lib/utimens.c (utimensat_works_really): New cache variable. + (fdutimens, lutimens): Use it to avoid failing syscall. + test-stat-time, test-utimens: improve portability * tests/test-stat-time.c (nap): Lengthen delay to 20ms, for ext4 on alpha, and for cygwin.
--- a/lib/utimens.c +++ b/lib/utimens.c @@ -52,6 +52,13 @@ /* Avoid recursion with rpl_futimens. */ #undef futimens +#if HAVE_UTIMENSAT || HAVE_FUTIMENS +/* Cache variable for whether syscall works; used to avoid calling the + syscall if we know it will just fail with ENOSYS. 0 = unknown, 1 = + yes, -1 = no. */ +static int utimensat_works_really; +#endif /* HAVE_UTIMENSAT || HAVE_UTIMENSAT */ + /* Validate the requested timestamps. Return 0 if the resulting timespec can be used for utimensat (after possibly modifying it to work around bugs in utimensat). Return 1 if the timespec needs @@ -182,41 +189,53 @@ #endif /* POSIX 2008 added two interfaces to set file timestamps with - nanosecond resolution. We provide a fallback for ENOSYS (for - example, compiling against Linux 2.6.25 kernel headers and glibc - 2.7, but running on Linux 2.6.18 kernel). */ -#if HAVE_UTIMENSAT - if (fd < 0) + nanosecond resolution; newer Linux implements both functions via + a single syscall. We provide a fallback for ENOSYS (for example, + compiling against Linux 2.6.25 kernel headers and glibc 2.7, but + running on Linux 2.6.18 kernel). */ +#if HAVE_UTIMENSAT || HAVE_FUTIMENS + if (0 <= utimensat_works_really) { - int result = utimensat (AT_FDCWD, file, ts, 0); -# ifdef __linux__ - /* Work around a kernel bug: - http://bugzilla.redhat.com/442352 - http://bugzilla.redhat.com/449910 - It appears that utimensat can mistakenly return 280 rather - than -1 upon failure. - FIXME: remove in 2010 or whenever the offending kernels - are no longer in common use. */ - if (0 < result) - errno = ENOSYS; -# endif - - if (result == 0 || errno != ENOSYS) - return result; +# if HAVE_UTIMENSAT + if (fd < 0) + { + int result = utimensat (AT_FDCWD, file, ts, 0); +# ifdef __linux__ + /* Work around a kernel bug: + http://bugzilla.redhat.com/442352 + http://bugzilla.redhat.com/449910 + It appears that utimensat can mistakenly return 280 rather + than -1 upon ENOSYS failure. + FIXME: remove in 2010 or whenever the offending kernels + are no longer in common use. */ + if (0 < result) + errno = ENOSYS; +# endif /* __linux__ */ + if (result == 0 || errno != ENOSYS) + { + utimensat_works_really = 1; + return result; + } + } +# endif /* HAVE_UTIMENSAT */ +# if HAVE_FUTIMENS + { + int result = futimens (fd, timespec); +# ifdef __linux__ + /* Work around the same bug as above. */ + if (0 < result) + errno = ENOSYS; +# endif /* __linux__ */ + if (result == 0 || errno != ENOSYS) + { + utimensat_works_really = 1; + return result; + } + } +# endif /* HAVE_FUTIMENS */ } -#endif -#if HAVE_FUTIMENS - { - int result = futimens (fd, timespec); -# ifdef __linux__ - /* Work around the same bug as above. */ - if (0 < result) - errno = ENOSYS; -# endif - if (result == 0 || errno != ENOSYS) - return result; - } -#endif + utimensat_works_really = -1; +#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */ /* The platform lacks an interface to set file timestamps with nanosecond resolution, so do the best we can, discarding any @@ -352,23 +371,27 @@ worry about bogus return values. */ #if HAVE_UTIMENSAT - { - int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW); + if (0 <= utimensat_works_really) + { + int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW); # ifdef __linux__ - /* Work around a kernel bug: - http://bugzilla.redhat.com/442352 - http://bugzilla.redhat.com/449910 - It appears that utimensat can mistakenly return 280 rather - than -1 upon ENOSYS failure. - FIXME: remove in 2010 or whenever the offending kernels - are no longer in common use. */ - if (0 < result) - errno = ENOSYS; + /* Work around a kernel bug: + http://bugzilla.redhat.com/442352 + http://bugzilla.redhat.com/449910 + It appears that utimensat can mistakenly return 280 rather + than -1 upon ENOSYS failure. + FIXME: remove in 2010 or whenever the offending kernels + are no longer in common use. */ + if (0 < result) + errno = ENOSYS; # endif - - if (result == 0 || errno != ENOSYS) - return result; - } + if (result == 0 || errno != ENOSYS) + { + utimensat_works_really = 1; + return result; + } + } + utimensat_works_really = -1; #endif /* HAVE_UTIMENSAT */ /* The platform lacks an interface to set file timestamps with