* libamu/xutil.c (clocktime): newly implemented routine. Uses after-clocktime-fixes
authorErez Zadok <ezk@cs.sunysb.edu>
Sat, 17 Sep 2005 22:16:36 +0000 (22:16 +0000)
committerErez Zadok <ezk@cs.sunysb.edu>
Sat, 17 Sep 2005 22:16:36 +0000 (22:16 +0000)
gettimeofday() each time to return a high-resolution clock time,
and does not "cache" the last time.  Returns time in seconds, just
like the old implementation.  If passed a non-null argument, will
fill it in with the current time in seconds+microseconds.

* libamu/xutil.c: remove actual declaration of clock_valid, and
another never-used declaration for xclock_valid.

* include/am_utils.h: remove defunct definition of clocktime()
macro and clock_valid variable.  Add extern for new definition.

* libamu/mount_fs.c (mount_fs), hlfsd/homedir.c (homedir,
hlfsd_diskspace, hlfsd_getpwent, plt_reset, table_add),
hlfsd/hlfsd.c (main, hlfsd_init, reload, cleanup),
conf/mtab/mtab_mach3.c (open_locked_mtab), conf/mtab/mtab_file.c
(open_locked_mtab), amd/nfs_start.c (do_select, run_rpc),
amd/autil.c (host_normalize): remove defunct clock_valid.

* amd/nfs_subr.c (nfsproc_getattr_2_svc): Print microseconds for
node's mtime.
(fh_to_mp3): use new clocktime() to update mtime and get a better
time resolution.

* amd/mapc.c (mapc_reload_map): change prototype from returning
void to returning an int.  If reloading was needed and succeeded,
return 1; else return 0.
(mapc_sync): update mtime of parent node if needed.  This is a
CRITICAL FIX, to ensure that the kernel flushes its DNLC/dcache
when we run "amq -f" manually or when a map is reloaded.

* amd/map.c (new_ttl): update am_ttl and na_atime in one shot.
(init_map): use new clocktime().
(unmount_mp): if the OS doesn't support a "symttl" option, then
update the mtime of the parent node using the clocktime(); but if
the time hasn't gotten changed because of rapid Amd accesses on
systems that don't have a micro-second NFS-client resolution, then
increment mtime by one arbitrarily (this could, on some systems
and under pathological cases, result in mtime's that are in the
future).

* amd/autil.c (forcibly_timeout_mp): MAJOR BUG FIX: force mtime
update of parent dir, to prevent DNLC/dcache from caching the old
entry, which could result in ESTALE errors, bad symlinks, and
more.
(am_mounted): record mount time, and update am_stats at the same
time, using the double-action redone clocktime() routine.
(am_mounted): update parent's mtime from that of the child.
(am_unmounted): when unmounting an entry, update mtime of parent
node.

* amd/amfs_generic.c (amfs_bgmount): now that clocktime() doesn't
remember it's last non-zero value, save it in a temporary variable
to avoid a TOCTOU problem (between an "if" and a "dlog").

* libamu/xutil.c (show_time_host_and_name),
conf/autofs/autofs_linux.c (autofs_mounted, autofs_timeout_mp),
amd/srvr_nfs.c (nfs_keepalive_callback, nfs_keepalive_timeout)
(find_nfs_srvr), amd/rpc_fwd.c (fwd_alloc), amd/nfs_subr.c
(nfsproc_getattr_2_svc), amd/nfs_start.c (do_select, run_rpc),
amd/mapc.c (root_init), amd/map.c(map_flush_srvr, timeout_mp),
amd/info_ndbm.c (ndbm_init), amd/info_ldap.c (amu_ldap_rebind),
amd/info_file.c (file_open), amd/info_exec.c (fgets_timed,
exec_search), amd/clock.c (timeout, softclock), amd/autil.c
(forcibly_timeout_mp), amd/amfs_generic.c (amfs_retry,
amfs_bgmount, amfs_generic_mount_child), amd/amd.c (main): pass
NULL to clocktime().

24 files changed:
ChangeLog
NEWS
amd/amd.c
amd/amfs_generic.c
amd/autil.c
amd/clock.c
amd/info_exec.c
amd/info_file.c
amd/info_ldap.c
amd/info_ndbm.c
amd/map.c
amd/mapc.c
amd/nfs_start.c
amd/nfs_subr.c
amd/rpc_fwd.c
amd/srvr_nfs.c
conf/autofs/autofs_linux.c
conf/mtab/mtab_file.c
conf/mtab/mtab_mach3.c
hlfsd/hlfsd.c
hlfsd/homedir.c
include/am_utils.h
libamu/mount_fs.c
libamu/xutil.c

index 0cdbc26c34cc192e50b739d19ca53cbc6e5d36fd..91e469a19a175fab911087747ed4fe58d09ec290 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,73 @@
+2005-09-17  Erez Zadok  <ezk@cs.sunysb.edu>
+
+       * libamu/xutil.c (clocktime): newly implemented routine.  Uses
+       gettimeofday() each time to return a high-resolution clock time,
+       and does not "cache" the last time.  Returns time in seconds, just
+       like the old implementation.  If passed a non-null argument, will
+       fill it in with the current time in seconds+microseconds.
+
+       * libamu/xutil.c: remove actual declaration of clock_valid, and
+       another never-used declaration for xclock_valid.
+
+       * include/am_utils.h: remove defunct definition of clocktime()
+       macro and clock_valid variable.  Add extern for new definition.
+
+       * libamu/mount_fs.c (mount_fs), hlfsd/homedir.c (homedir,
+       hlfsd_diskspace, hlfsd_getpwent, plt_reset, table_add),
+       hlfsd/hlfsd.c (main, hlfsd_init, reload, cleanup),
+       conf/mtab/mtab_mach3.c (open_locked_mtab), conf/mtab/mtab_file.c
+       (open_locked_mtab), amd/nfs_start.c (do_select, run_rpc),
+       amd/autil.c (host_normalize): remove defunct clock_valid.
+
+       * amd/nfs_subr.c (nfsproc_getattr_2_svc): Print microseconds for
+       node's mtime.
+       (fh_to_mp3): use new clocktime() to update mtime and get a better
+       time resolution.
+
+       * amd/mapc.c (mapc_reload_map): change prototype from returning
+       void to returning an int.  If reloading was needed and succeeded,
+       return 1; else return 0.
+       (mapc_sync): update mtime of parent node if needed.  This is a
+       CRITICAL FIX, to ensure that the kernel flushes its DNLC/dcache
+       when we run "amq -f" manually or when a map is reloaded.
+
+       * amd/map.c (new_ttl): update am_ttl and na_atime in one shot.
+       (init_map): use new clocktime().
+       (unmount_mp): if the OS doesn't support a "symttl" option, then
+       update the mtime of the parent node using the clocktime(); but if
+       the time hasn't gotten changed because of rapid Amd accesses on
+       systems that don't have a micro-second NFS-client resolution, then
+       increment mtime by one arbitrarily (this could, on some systems
+       and under pathological cases, result in mtime's that are in the
+       future).
+
+       * amd/autil.c (forcibly_timeout_mp): MAJOR BUG FIX: force mtime
+       update of parent dir, to prevent DNLC/dcache from caching the old
+       entry, which could result in ESTALE errors, bad symlinks, and
+       more.
+       (am_mounted): record mount time, and update am_stats at the same
+       time, using the double-action redone clocktime() routine.
+       (am_mounted): update parent's mtime from that of the child.
+       (am_unmounted): when unmounting an entry, update mtime of parent
+       node.
+
+       * amd/amfs_generic.c (amfs_bgmount): now that clocktime() doesn't
+       remember it's last non-zero value, save it in a temporary variable
+       to avoid a TOCTOU problem (between an "if" and a "dlog").
+
+       * libamu/xutil.c (show_time_host_and_name),
+       conf/autofs/autofs_linux.c (autofs_mounted, autofs_timeout_mp),
+       amd/srvr_nfs.c (nfs_keepalive_callback, nfs_keepalive_timeout)
+       (find_nfs_srvr), amd/rpc_fwd.c (fwd_alloc), amd/nfs_subr.c
+       (nfsproc_getattr_2_svc), amd/nfs_start.c (do_select, run_rpc),
+       amd/mapc.c (root_init), amd/map.c(map_flush_srvr, timeout_mp),
+       amd/info_ndbm.c (ndbm_init), amd/info_ldap.c (amu_ldap_rebind),
+       amd/info_file.c (file_open), amd/info_exec.c (fgets_timed,
+       exec_search), amd/clock.c (timeout, softclock), amd/autil.c
+       (forcibly_timeout_mp), amd/amfs_generic.c (amfs_retry,
+       amfs_bgmount, amfs_generic_mount_child), amd/amd.c (main): pass
+       NULL to clocktime().
+
 2005-09-15  Erez Zadok  <ezk@cs.sunysb.edu>
 
        * amd/nfs_subr.c (nfsproc_getattr_2_svc): initialize 'retry', just
diff --git a/NEWS b/NEWS
index 6f7581f07ff7d1b5d650753029fe673295f88f8a..b55dfe5f18b952cf98e1df413eff8a2bbff63876 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,28 @@
 *** Notes specific to am-utils version 6.2a1
 
+MAJOR BUG FIXES: Synchronize Amd's view of its file systems with the
+kernel's NFS client-side DNLC/dcache.  Amd changes its view when it reloads
+maps (automatically or via "amq -f") because new map entries could be added,
+old one removed, or existing ones changed.  Amd also changes its view when a
+simple entry has expired and was flushed, or was forced out via "amq -u".
+Amd was not updating the mtime of its parent directory (often the amd
+automount point): this resulted in the kernel re-using cached entries, which
+are now possibly stale.  Many users had seen this problem in the form of
+occasional ESTALE errors, or dangling/broken automounted symlinks,
+especially on systems under heavy use.  To tell the kernel to ignore (flush)
+its old entries for an directory, the mtime of the directory must be updated
+(monotonically incremented).  Amd was indeed doing so in several places, but
+unfortunately it was using time(2) which only provides a one-second
+resolution clock: this was fine a decade ago, but not good enough on today's
+fast systems; using only a one-second resolution clock meant that on busy
+systems that invoke Amd many times a second, some rapidly changing entries
+do not get flushed from the kernel, and the kernel thus uses stale entries.
+The solution to all of these was to rework the whole clock timer updates to
+use gettimeofday(), using a micro-second resolution timer, and to use that
+time whenever Amd needs to update an mtime/atime/ctime of any node.
+Finally, we now update the mtime in places that were never updated before
+(when a whole map is flushed or a single entry times out).
+
 - minor new ports:
        i386-pc-linux-deb3.1
        powerpc-apple-darwin8.2.0
index 32314445f71eb13330e130c39a40255e0bbce080..e87d4d87bc3df1db3439c51ed71bfbeaa3bcdf7c 100644 (file)
--- a/amd/amd.c
+++ b/amd/amd.c
@@ -552,7 +552,7 @@ main(int argc, char *argv[])
     do_memory_locking();
   }
 
-  do_mapc_reload = clocktime() + gopt.map_reload_interval;
+  do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
 
   /*
    * Register automounter with system.
index 8aa47a38d253b0bbec8ba711ccafe8b8304ebe05..84a51315686b418009e5e178d1c130dcd2a4b99e 100644 (file)
@@ -598,7 +598,7 @@ amfs_retry(int rc, int term, opaque_t arg)
 
   new_ttl(mp);
 
-  if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
+  if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime(NULL)) {
     /*
      * The entire mount has timed out.  Set the error code and skip past all
      * the mntfs's so that amfs_bgmount will not have any more
@@ -788,8 +788,9 @@ amfs_bgmount(struct continuation *cp)
        * has not expired.
        */
       int i = atoi(mf->mf_fo->opt_delay);
-      if (i > 0 && clocktime() < (cp->start + i)) {
-       dlog("Mount of %s delayed by %lds", mf->mf_mount, (long) (i - clocktime() + cp->start));
+      time_t now = clocktime(NULL);
+      if (i > 0 && now < (cp->start + i)) {
+       dlog("Mount of %s delayed by %lds", mf->mf_mount, (long) (i - now + cp->start));
        goto retry;
       }
     }
@@ -854,7 +855,7 @@ amfs_bgmount(struct continuation *cp)
     cp->callout = timeout(RETRY_INTERVAL, wakeup,
                          (opaque_t) get_mntfs_wchan(mf));
 
-    mp->am_ttl = clocktime() + RETRY_INTERVAL;
+    mp->am_ttl = clocktime(NULL) + RETRY_INTERVAL;
 
     /*
      * Not done yet - so don't return anything
@@ -1072,7 +1073,7 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return)
   cp->callout = 0;
   cp->mp = new_mp;
   cp->retry = TRUE;
-  cp->start = clocktime();
+  cp->start = clocktime(NULL);
   cp->mf = new_mp->am_mfarray;
 
   /*
index 2f06a996b4d53628d4e8f489e1ff45cdf4e3435b..2435858a3ffe1e6ce5be4d65f35908dea613ed91 100644 (file)
@@ -131,7 +131,6 @@ host_normalize(char **chp)
    */
   if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) {
     struct hostent *hp;
-    clock_valid = 0;
     hp = gethostbyname(*chp);
     if (hp && hp->h_addrtype == AF_INET) {
       dlog("Hostname %s normalized to %s", *chp, hp->h_name);
@@ -174,7 +173,13 @@ forcibly_timeout_mp(am_node *mp)
   } else {
     plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
     mp->am_flags &= ~AMF_NOTIMEOUT;
-    mp->am_ttl = clocktime();
+    mp->am_ttl = clocktime(NULL);
+    /*
+     * Force mtime update of parent dir, to prevent DNLC/dcache from caching
+     * the old entry, which could result in ESTALE errors, bad symlinks, and
+     * more.
+     */
+    clocktime(&mp->am_parent->am_fattr.na_mtime);
     reschedule_timeout_mp();
   }
 }
@@ -308,16 +313,16 @@ am_mounted(am_node *mp)
     mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount);
 
   /*
-   * Record mount time
+   * Record mount time, and update am_stats at the same time.
    */
-  mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime();
+  mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime);
   new_ttl(mp);
 
   /*
-   * Update mtime of parent node
+   * Update mtime of parent node (copying "struct nfstime" in '=' below)
    */
   if (mp->am_parent && mp->am_parent->am_mnt)
-    mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime;
+    mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime;
 
   /*
    * This is ugly, but essentially unavoidable
@@ -701,7 +706,7 @@ am_unmounted(am_node *mp)
    * Update mtime of parent node
    */
   if (mp->am_parent && mp->am_parent->am_mnt)
-    mp->am_parent->am_fattr.na_mtime.nt_seconds = clocktime();
+    clocktime(&mp->am_parent->am_fattr.na_mtime);
 
   if (mp->am_flags & AMF_REMOUNT) {
     char *fname = strdup(mp->am_name);
index ff4adf2f01fc386daa0122b0bcdefd8fa9637eb8..bc5f7d9311b050761675b4a4c37079c7e742330a 100644 (file)
@@ -119,13 +119,13 @@ free_callout(callout *cp)
 /*
  * Schedule a callout.
  *
- * (*fn)(fn_arg) will be called at clocktime() + secs
+ * (*fn)(fn_arg) will be called at clocktime(NULL) + secs
  */
 int
 timeout(u_int secs, callout_fun *fn, opaque_t fn_arg)
 {
   callout *cp, *cp2;
-  time_t t = clocktime() + secs;
+  time_t t = clocktime(NULL) + secs;
 
   /*
    * Allocate and fill in a new callout structure
@@ -208,7 +208,7 @@ softclock(void)
     if (task_notify_todo)
       do_task_notify();
 
-    now = clocktime();
+    now = clocktime(NULL);
 
     /*
      * While there are more callouts waiting...
index cebd91d949dcddca163628801ab34a653c476187..f7dc4d6fb438f93071d5896a1f2486fab7288233 100644 (file)
@@ -78,7 +78,7 @@ fgets_timed(char *s, int size, int rdfd, int secs)
   if (size == 0)
     return s;
 
-  start = clocktime();
+  start = clocktime(NULL);
   while (s[i] != '\n'  &&  i < size-1) {
     s[i+1] = '\0'; /* places the requisite trailing '\0' */
 
@@ -99,7 +99,7 @@ fgets_timed(char *s, int size, int rdfd, int secs)
     }
 
     timeo.tv_usec = 0;
-    now = clocktime() - start;
+    now = clocktime(NULL) - start;
     if (secs <= 0)
       timeo.tv_sec = 0;
     else if (now < secs)
@@ -416,7 +416,7 @@ exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
 
   if (mapfd >= 0) {
     if (tp)
-      *tp = clocktime();
+      *tp = clocktime(NULL);
 
     return exec_parse_qanswer(m, mapfd, map, key, pval, tp);
   }
index db0192408a83df6bcad23f35627355c099c99233..a3a904638a2bb90f468125e64fd20bca0f7dee93 100644 (file)
@@ -202,7 +202,7 @@ file_open(char *map, time_t *tp)
   if (mapf && tp) {
     struct stat stb;
     if (fstat(fileno(mapf), &stb) < 0)
-      *tp = clocktime();
+      *tp = clocktime(NULL);
     else
       *tp = stb.st_mtime;
   }
index 376a04622298c07cbcb7c9a031022c2bd4766826..50e638caf67320192b6fcb877ca50bd54aa9dcac 100644 (file)
@@ -277,7 +277,7 @@ amu_ldap_rebind(ALD *a)
   LDAP *ld;
   HE_ENT *h;
   CR *c = a->credentials;
-  time_t now = clocktime();
+  time_t now = clocktime(NULL);
   int try;
 
   dlog("-> amu_ldap_rebind\n");
index 5eac3c89769eb630ef1a3df06d3cc6169e1f2edf..c197a27690d234c01767a2cfea5549a2171399aa 100644 (file)
@@ -127,7 +127,7 @@ ndbm_init(mnt_map *m, char *map, time_t *tp)
     error = fstat(dbm_pagfno(db), &stb);
 #endif /* not DBM_SUFFIX */
     if (error < 0)
-      *tp = clocktime();
+      *tp = clocktime(NULL);
     else
       *tp = stb.st_mtime;
     dbm_close(db);
index 11578069f2ecbd4b237465a641a4b0a5d94b1473..f1993ec4c0a4f1ecce2e78598522a6c786b39710 100644 (file)
--- a/amd/map.c
+++ b/amd/map.c
@@ -367,8 +367,7 @@ void
 new_ttl(am_node *mp)
 {
   mp->am_timeo_w = 0;
-  mp->am_ttl = clocktime();
-  mp->am_fattr.na_atime.nt_seconds = mp->am_ttl;
+  mp->am_ttl = clocktime(&mp->am_fattr.na_atime);
   mp->am_ttl += mp->am_timeo;  /* sun's -tl option */
 }
 
@@ -423,8 +422,8 @@ init_map(am_node *mp, char *dir)
   mp->am_fattr = gen_fattr;
   mp->am_fattr.na_fsid = 42;
   mp->am_fattr.na_fileid = mp->am_gen;
-  mp->am_fattr.na_atime.nt_seconds = clocktime();
-  mp->am_fattr.na_atime.nt_useconds = 0;
+  clocktime(&mp->am_fattr.na_atime);
+  /* next line copies a "struct nfstime" among several fields */
   mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime;
 
   new_ttl(mp);
@@ -587,7 +586,7 @@ map_flush_srvr(fserver *fs)
     am_node *mp = exported_ap[i];
     if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) {
       plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host);
-      mp->am_ttl = clocktime();
+      mp->am_ttl = clocktime(NULL);
       done = 1;
     }
   }
@@ -894,11 +893,16 @@ unmount_mp(am_node *mp)
      * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
      *
      * Additionally, Linux currently ignores the nt_useconds field,
-     * so we must update the nt_seconds field every time.
+     * so we must update the nt_seconds field every time if clocktime(NULL)
+     * didn't return a new number of seconds.
      */
-  if (mp->am_parent)
+  if (mp->am_parent) {
+    time_t last = mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds;
+    clocktime(&mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime);
     /* defensive programming... can't we assert the above condition? */
-    mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds++;
+    if (last == mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds)
+      mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds++;
+  }
 #endif /* not MNT2_NFS_OPT_SYMTTL */
 
   if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
@@ -942,7 +946,7 @@ timeout_mp(opaque_t v)                              /* argument not used?! */
 {
   int i;
   time_t t = NEVER;
-  time_t now = clocktime();
+  time_t now = clocktime(NULL);
   int backoff = NumChildren / 4;
 
   dlog("Timing out automount points...");
index 4aab31a0dedaa7b12db219e66fbc4b3ed3589d42..9dec3fea4c339455dab42737fe108960e2bcef5f 100644 (file)
@@ -568,11 +568,12 @@ mapc_find_wildcard(mnt_map *m)
  * Do a map reload.
  * Attempt to reload without losing current data by switching the hashes
  * round.
+ * If reloading was needed and succeeded, return 1; else return 0.
  */
-static void
+static int
 mapc_reload_map(mnt_map *m)
 {
-  int error;
+  int error, ret = 0;
   kv *maphash[NKVHASH], *tmphash[NKVHASH];
   time_t t;
 
@@ -590,7 +591,7 @@ mapc_reload_map(mnt_map *m)
       plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
       dlog("map %s last load time is %d, last modify time is %d",
           m->map_name, (int) m->modify, (int) t);
-      return;
+      return ret;
     }
   }
 
@@ -619,6 +620,7 @@ mapc_reload_map(mnt_map *m)
     mapc_clear(m);
     memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash));
     m->modify = t;
+    ret = 1;
   }
   m->wildcard = NULL;
 
@@ -626,6 +628,7 @@ mapc_reload_map(mnt_map *m)
   error = mapc_search(m, wildcard, &m->wildcard);
   if (error)
     m->wildcard = NULL;
+  return ret;
 }
 
 
@@ -981,25 +984,42 @@ mapc_search(mnt_map *m, char *key, char **pval)
 static void
 mapc_sync(mnt_map *m)
 {
-  if (m->alloc != MAPC_ROOT) {
+  int need_mtime_update = 0;
 
-    /* do not clear map if map service is down */
-    if (m->isup) {
-      if (!((*m->isup)(m, m->map_name))) {
-       plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
-       return;
-      }
+  if (m->alloc == MAPC_ROOT)
+    return;                    /* nothing to do */
+
+  /* do not clear map if map service is down */
+  if (m->isup) {
+    if (!((*m->isup)(m, m->map_name))) {
+      plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
+      return;
     }
+  }
 
-    if (m->alloc >= MAPC_ALL) {
-      /* mapc_reload_map() always works */
-      mapc_reload_map(m);
+  if (m->alloc >= MAPC_ALL) {
+    /* mapc_reload_map() always works */
+    need_mtime_update = mapc_reload_map(m);
+  } else {
+    mapc_clear(m);
+    /*
+     * Attempt to find the wildcard entry
+     */
+    mapc_find_wildcard(m);
+    need_mtime_update = 1;     /* because mapc_clear always works */
+  }
+
+  /*
+   * To be safe, update the mtime of the mnt_map's own node, so that the
+   * kernel will flush all of its cached entries.
+   */
+  if (need_mtime_update && m->cfm) {
+    am_node *mp = find_ap(m->cfm->cfm_dir);
+    if (mp) {
+      clocktime(&mp->am_fattr.na_mtime);
     } else {
-      mapc_clear(m);
-      /*
-       * Attempt to find the wildcard entry
-       */
-      mapc_find_wildcard(m);
+      plog(XLOG_ERROR, "cannot find map %s to update its mtime",
+          m->cfm->cfm_dir);
     }
   }
 }
@@ -1036,7 +1056,7 @@ mapc_reload(void)
 static int
 root_init(mnt_map *m, char *map, time_t *tp)
 {
-  *tp = clocktime();
+  *tp = clocktime(NULL);
   return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
 }
 
index 86ef19c38088039592b0dd50a5fd995d079c13da..617f9a3951de2a588162797939408638bc95e937 100644 (file)
@@ -120,10 +120,6 @@ do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
     errno = EINTR;
   } else {
     select_intr_valid = 1;
-    /*
-     * Invalidate the current clock value
-     */
-    clock_valid = 0;
     /*
      * Allow interrupts.  If a signal
      * occurs, then it will cause a longjmp
@@ -151,9 +147,9 @@ do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
   /*
    * Perhaps reload the cache?
    */
-  if (do_mapc_reload < clocktime()) {
+  if (do_mapc_reload < clocktime(NULL)) {
     mapc_reload();
-    do_mapc_reload = clocktime() + gopt.map_reload_interval;
+    do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
   }
   return nsel;
 }
@@ -194,7 +190,7 @@ run_rpc(void)
   int smask = sigblock(MASKED_SIGS);
 #endif /* not HAVE_SIGACTION */
 
-  next_softclock = clocktime();
+  next_softclock = clocktime(NULL);
 
   amd_state = Run;
 
@@ -227,7 +223,7 @@ run_rpc(void)
      * If the full timeout code is not called,
      * then recompute the time delta manually.
      */
-    now = clocktime();
+    now = clocktime(NULL);
 
     if (next_softclock <= now) {
       if (amd_state == Finishing)
index 099e0b945c1e2762540237eae1121fd1069dc27e..336054cbb3eece48f7d737dbf561942e59af5352 100644 (file)
@@ -131,7 +131,7 @@ nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
   static nfsattrstat res;
   am_node *mp;
   int retry = 0;
-  time_t now = clocktime();
+  time_t now = clocktime(NULL);
 
   if (amuDebug(D_TRACE))
     plog(XLOG_DEBUG, "getattr:");
@@ -151,10 +151,11 @@ nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
 
   res = mp->am_attr;
   if (amuDebug(D_TRACE))
-    plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld",
+    plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld.%ld",
         mp->am_path,
         (int) res.ns_u.ns_attr_u.na_size,
-        (long) res.ns_u.ns_attr_u.na_mtime.nt_seconds);
+        (long) res.ns_u.ns_attr_u.na_mtime.nt_seconds,
+        (long) res.ns_u.ns_attr_u.na_mtime.nt_useconds);
 
   /* Delay unmount of what was looked up */
   if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
@@ -698,7 +699,7 @@ fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
      * With any luck the kernel will re-stat
      * the child node and get new information.
      */
-    orig_ap->am_fattr.na_mtime.nt_seconds = clocktime();
+    clocktime(&orig_ap->am_fattr.na_mtime);
 
     /*
      * Call the parent's lookup routine for an object
index ffd9031e09a68f5cf94d83db48c99fa9aca6c74b..35af422d32e2f9d9da82c8d5e52cbff6193b9f8c 100644 (file)
@@ -93,7 +93,7 @@ static u_int xid;
 static rpc_forward *
 fwd_alloc(void)
 {
-  time_t now = clocktime();
+  time_t now = clocktime(NULL);
   rpc_forward *p = NULL, *p2;
 
   /*
index dae83f1a3eb836cb8fcb34c33393c75df39e613e..c7c73f15551bacb49c571c4b4c5f6b1221419067 100644 (file)
@@ -409,7 +409,7 @@ nfs_keepalive_callback(voidp pkt, int len, struct sockaddr_in *sp, struct sockad
       /*
        * Update ttl for this server
        */
-      np->np_ttl = clocktime() +
+      np->np_ttl = clocktime(NULL) +
        (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1;
 
       /*
@@ -503,7 +503,7 @@ nfs_keepalive_timeout(voidp v)
   /*
    * If ttl has expired then guess that it is dead
    */
-  if (np->np_ttl < clocktime()) {
+  if (np->np_ttl < clocktime(NULL)) {
     int oflags = fs->fs_flags;
     dlog("ttl has expired");
     if ((fs->fs_flags & FSF_DOWN) == 0) {
@@ -970,7 +970,7 @@ no_dns:
         * after MAX_ALLOWED_PINGS of the fast variety
         * have failed.
         */
-       np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime() - 1;
+       np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime(NULL) - 1;
        start_nfs_pings(fs, pingval);
        if (fserver_is_down)
          fs->fs_flags |= FSF_VALID | FSF_DOWN;
@@ -1021,7 +1021,7 @@ no_dns:
    * Initially the server will be deemed dead after
    * MAX_ALLOWED_PINGS of the fast variety have failed.
    */
-  np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1;
+  np->np_ttl = clocktime(NULL) + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1;
   fs->fs_private = (voidp) np;
   fs->fs_prfree = (void (*)(voidp)) free;
 
index 11b680f6b781d7a3c969b31218ac106b5e6e647b..22bf42152cb5a464e9bf2e9a6ff3ec419a1a4a5d 100644 (file)
@@ -182,7 +182,7 @@ autofs_mounted(am_node *mp)
     plog(XLOG_ERROR, "AUTOFS_IOC_SETTIMEOUT: %s", strerror(errno));
 
   /* tell the daemon to call us for expirations */
-  mp->am_autofs_ttl = clocktime() + gopt.am_timeo_w;
+  mp->am_autofs_ttl = clocktime(NULL) + gopt.am_timeo_w;
 }
 
 
@@ -810,7 +810,7 @@ static int autofs_timeout_mp_task(void *arg)
 void autofs_timeout_mp(am_node *mp)
 {
   autofs_fh_t *fh = mp->am_autofs_fh;
-  time_t now = clocktime();
+  time_t now = clocktime(NULL);
 
   /* update the ttl */
   mp->am_autofs_ttl = now + gopt.am_timeo_w;
index 0a97109c6d85e74aa0a78657570058706359fd6a..d2f7dba6dc35aa4ae7eb785947b285df3e2b3603 100644 (file)
@@ -129,7 +129,6 @@ again:
     endmntent(mfp);
     mfp = NULL;
   }
-  clock_valid = 0;
   if (stat(mnttabname, &st_before) < 0) {
     plog(XLOG_ERROR, "%s: stat: %m", mnttabname);
     if (errno == ESTALE) {
index faa3f150c6e6418e6be97d1132811f770a0f06c3..85a2c52ff2a6b54ca1e09317718200ac74cbfce5 100644 (file)
@@ -127,7 +127,6 @@ again:
     endmntent(mfp);
     mfp = NULL;
   }
-  clock_valid = 0;
   if (stat(mnttabname, &st_before) < 0) {
     plog(XLOG_ERROR, "%s: stat: %m", mnttabname);
     if (errno == ESTALE) {
index eb510a28695ec4e88cbcd7984189258ae8e91067..4549b5aa5a47147d916f247da9b625c2f2884277 100644 (file)
@@ -333,8 +333,6 @@ main(int argc, char *argv[])
     exit(3);
   }
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   if (!forcefast) {
     /* make sure mount point exists and is at least mode 555 */
     if (stat(dir_name, &stmodes) < 0)
@@ -568,8 +566,6 @@ main(int argc, char *argv[])
    *************************************************************************/
   compute_automounter_nfs_args(&nfs_args, &mnt);
 
-  clock_valid = 0;             /* invalidate logging clock */
-
 /*
  * For some reason, this mount may have to be done in the background, if I am
  * using -D daemon.  I suspect that the actual act of mounting requires
@@ -636,8 +632,6 @@ hlfsd_init(void)
   struct sigaction sa;
 #endif /* HAVE_SIGACTION */
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   /*
    * Initialize file handles.
    */
@@ -777,8 +771,6 @@ reload(int signum)
   int child;
   int status;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   if (getpid() != masterpid)
     return;
 
@@ -830,8 +822,6 @@ cleanup(int signum)
   struct stat stbuf;
   int umount_result;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   if (amuDebug(D_DAEMON)) {
     if (getpid() != masterpid)
       return;
index bef1d5a3d49a4c834dad88abd9d96274b517ab2d..347ec7aeedcec0712381b36ea7e97c40c713ae2e 100644 (file)
@@ -89,8 +89,6 @@ homedir(int userid, int groupid)
   struct stat homestat;
   int old_groupid, old_userid;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   if ((found = plt_search(userid)) == (uid2home_t *) NULL) {
     return alt_spooldir;       /* use alt spool for unknown uid */
   }
@@ -230,8 +228,6 @@ hlfsd_diskspace(char *path)
   char buf[MAXPATHLEN];
   int fd, len;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   sprintf(buf, "%s/._hlfstmp_%lu", path, (long) getpid());
   if ((fd = open(buf, O_RDWR | O_CREAT, 0600)) < 0) {
     plog(XLOG_ERROR, "cannot open %s: %m", buf);
@@ -485,8 +481,6 @@ hlfsd_getpwent(void)
     return getpwent();
   }
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   /* return here to read another entry */
 readent:
 
@@ -595,8 +589,6 @@ plt_reset(void)
 {
   int i;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   hlfsd_setpwent();
   if (hlfsd_getpwent() == (struct passwd *) NULL) {
     hlfsd_endpwent();
@@ -641,8 +633,6 @@ table_add(u_int u, const char *h, const char *n)
 {
   int i;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   if (max_pwtab_num <= 0) {    /* was never initialized */
     max_pwtab_num = 1;
     pwtab = (uid2home_t *) xmalloc(max_pwtab_num *
index d7b4843b78e0c4d56626311eb452987d110d7812..6cc8f7babf159b12b6c8d4a3ddeafd2ffc84cd48 100644 (file)
 /* default: fatal + error + user + warning + info */
 #define XLOG_DEFAULT   (XLOG_MASK & (XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS))
 
- /* default: no logging options */
-
-#define clocktime() (clock_valid ? clock_valid : time(&clock_valid))
+/* default: no logging options */
 
 #define NO_SUBNET      "notknown"   /* default subnet name for no subnet */
 #define        NEXP_AP         (1022)                  /* gdmr: was 254 */
@@ -271,7 +269,6 @@ extern int orig_umask;              /* umask() on startup */
 extern serv_state amd_state;   /* Should we go now */
 extern struct in_addr myipaddr;        /* (An) IP address of this host */
 extern struct opt_tab xlog_opt[];
-extern time_t clock_valid;     /* Clock needs recalculating */
 extern u_short nfs_port;       /* Our NFS service port */
 
 /*
@@ -340,7 +337,7 @@ extern long get_server_pid(void);
 extern int xsnprintf(char *str, size_t size, const char *format, ...);
 extern int xvsnprintf(char *str, size_t size, const char *format, va_list ap);
 extern void setup_sighandler(int signum, void (*handler)(int));
-
+extern time_t clocktime(nfstime *nt);
 
 #ifdef MOUNT_TABLE_ON_FILE
 extern void rewrite_mtab(mntlist *, const char *);
index 866076cb87888f69f451bcc6bf2fc77a6d2d521b..29d68682460a57c24a8ea88874773054dfa1bbe3 100644 (file)
@@ -180,8 +180,6 @@ mount_fs(mntent_t *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type,
        mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
 
 again:
-  clock_valid = 0;
-
   error = MOUNT_TRAP(type, mnt, flags, mnt_data);
 
   if (error < 0) {
index eab3be44792b0fd179d96f06ec562fcbe83dbcaf..17cdf5f3505f31fa4b25dbced71978113d69ccdc 100644 (file)
@@ -67,9 +67,6 @@ int syslogging;
 static u_int xlog_level = XLOG_DEFAULT;
 static u_long amd_program_number = AMQ_PROGRAM;
 
-time_t clock_valid = 0;
-time_t xclock_valid = 0;
-
 #ifdef DEBUG_MEM
 # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
 static int mem_bytes;
@@ -336,7 +333,7 @@ show_time_host_and_name(int lvl)
   }
   else
 #endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */
-    t = clocktime();
+    t = clocktime(NULL);
 
   if (t != last_t) {
     last_ctime = ctime(&t);
@@ -860,7 +857,7 @@ unregister_amq(void)
     /* find which instance of amd to unregister */
     u_long amd_prognum = get_amd_program_number();
 
-    if (pmap_unset(amd_prognum, AMQ_VERSION) == 1)
+    if (pmap_unset(amd_prognum, AMQ_VERSION) != 1)
       dlog("failed to de-register Amd program %lu, version %lu",
           amd_prognum, AMQ_VERSION);
   }
@@ -1044,3 +1041,27 @@ setup_sighandler(int signum, void (*handler)(int))
   (void) signal(signum, handler);
 #endif /* not HAVE_SIGACTION */
 }
+
+
+/*
+ * Return current time in seconds.  If passed a non-null argyument, then
+ * fill it in with the current time in seconds and microseconds (useful
+ * for mtime updates).
+ */
+time_t
+clocktime(nfstime *nt)
+{
+  static struct timeval now;   /* keep last time, as default */
+
+  if (gettimeofday(&now, NULL) < 0) {
+    plog(XLOG_ERROR, "clocktime: gettimeofday: %m");
+    /* hack: force time to have incremented by at least 1 second */
+    now.tv_sec++;
+  }
+  /* copy seconds and microseconds. may demote a long to an int */
+  if (nt) {
+    nt->nt_seconds = (u_int) now.tv_sec;
+    nt->nt_useconds = (u_int) now.tv_usec;
+  }
+  return (time_t) now.tv_sec;
+}