* libamu/xutil.c (clocktime): newly implemented routine. Uses after-clocktime-fixes-61-br
authorErez Zadok <ezk@cs.sunysb.edu>
Sat, 17 Sep 2005 22:19:44 +0000 (22:19 +0000)
committerErez Zadok <ezk@cs.sunysb.edu>
Sat, 17 Sep 2005 22:19:44 +0000 (22:19 +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().

25 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
vers.m4

index 45c5d7c0df04f27ff4f456069bb86228fcfa51de..19c08db6f6f8da87cf9bb42a6cda033f5e9482ce 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-07  Erez Zadok  <ezk@cs.sunysb.edu>
 
        * minor new port: powerpc-apple-darwin8.2.0.
diff --git a/NEWS b/NEWS
index a6d53ff97df0c45633fffe815f519ff986252f03..d84695ce420d0ef95776da598b5efd5931361c5e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,27 @@
-*** Notes specific to am-utils version 6.1.2-rc1
+*** Notes specific to am-utils version 6.1.2
+
+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
index ead5ac2ef313afbb0c4f2961e8ae15cc737ce23b..cbac56d80c973122c6b106ec8874ad82b6dfbe3a 100644 (file)
--- a/amd/amd.c
+++ b/amd/amd.c
@@ -551,7 +551,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 1330ed4c763825058a1a967ce8f753363b2e1c9a..f60a22c9cb4395c00d63772b4374b0d6611e385b 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
@@ -789,8 +789,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;
       }
     }
@@ -855,7 +856,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
@@ -1082,7 +1083,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 7a4215105b083d33d19b916bea1ce81af18fd66a..755db79415e328df4ec546524c974dbb3f767a6f 100644 (file)
@@ -201,7 +201,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);
@@ -244,7 +243,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();
   }
 }
@@ -378,16 +383,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
@@ -769,7 +774,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 74d2619c42ffc8601e283ec19dbef26cc1b97561..0d874518472979c54de163120cb8101f0189cfde 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)
@@ -413,7 +413,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(mapfd, map, key, pval, tp);
   }
index a961e69ab87baa1c0c17957bd5c8003826dbf2f2..9f242e5277de8ab6b274f3e20a3d7a39a8388257 100644 (file)
@@ -197,7 +197,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 9da26c2d82a8ea5ba6bed16919ecf70cf81ba9ab..6cc80fc8032bad6fc70f361f75a33f1e137b04f8 100644 (file)
@@ -276,7 +276,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 aed668e42d4c316a07117464b0653231a596d20f..d7835009448b5434435f04a84a480f67ef6f3e18 100644 (file)
@@ -123,7 +123,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 47279debab41dea3a766392065f7ce31f21f8022..c977ed9109d329d6bd625d4177870432047e29d1 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 00d9bf52510f7977dbd2b13f1ae47c7b3cf5a506..8395492e13be4365889fd6410ff3cdab15fb6513 100644 (file)
@@ -514,11 +514,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;
 
@@ -536,7 +537,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;
     }
   }
 
@@ -565,6 +566,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 = 0;
 
@@ -572,6 +574,7 @@ mapc_reload_map(mnt_map *m)
   error = mapc_search(m, wildcard, &m->wildcard);
   if (error)
     m->wildcard = 0;
+  return ret;
 }
 
 
@@ -929,25 +932,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);
     }
   }
 }
@@ -984,7 +1004,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 f9acb97e30d5c5ad1e6765a139adceeabe08ad85..92686749d9212dcbdfbf036988788f7b38e0cd98 100644 (file)
@@ -121,10 +121,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
@@ -152,9 +148,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;
 }
@@ -195,7 +191,7 @@ run_rpc(void)
   int smask = sigblock(MASKED_SIGS);
 #endif /* not HAVE_SIGACTION */
 
-  next_softclock = clocktime();
+  next_softclock = clocktime(NULL);
 
   amd_state = Run;
 
@@ -228,7 +224,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 94e2547ae3ed1c4c4f2c68b5a8334d1df855c41a..7d04f8f8e055535a84802803f0e989d74ba4ed2b 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;
-  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 ae7aa0e46abcd206bb81c8d7f038404f00d1c5fc..5363167a5a1d9c34c9a9f8e846d9124e037ed132 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 = 0, *p2;
 
   /*
index a1355b92f9b6062f91d620a2e6a2b9e74e32e7a6..37fc24c0cb5f29d953806e947f74f7f149834d0e 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 16bee0a9dbb2308f45471abe2d4907a2ba505d6f..387c2244956d429ece588809a4fb1574c35f5789 100644 (file)
@@ -180,7 +180,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;
 }
 
 
@@ -808,7 +808,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 4d2201ed3f6e13fd33d0bc4c21bddb34f5788d4c..cddf6b351215c89af3e33ee8400096b078c11524 100644 (file)
@@ -129,7 +129,6 @@ again:
     endmntent(mfp);
     mfp = 0;
   }
-  clock_valid = 0;
   if (stat(mnttabname, &st_before) < 0) {
     plog(XLOG_ERROR, "%s: stat: %m", mnttabname);
     if (errno == ESTALE) {
index 51d9790fb42d076d2b1cf2c127c21a7a18f4e70e..261455aa337a8b031f090fb80a9d4ea637ee3a31 100644 (file)
@@ -127,7 +127,6 @@ again:
     endmntent(mfp);
     mfp = 0;
   }
-  clock_valid = 0;
   if (stat(mnttabname, &st_before) < 0) {
     plog(XLOG_ERROR, "%s: stat: %m", mnttabname);
     if (errno == ESTALE) {
index c81d64f233265bba968ffb4c1ed4ce36a05f9808..f5dca3fa91c4f59e872921467d018de73a335af1 100644 (file)
@@ -336,8 +336,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)
@@ -571,8 +569,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
@@ -639,8 +635,6 @@ hlfsd_init(void)
   struct sigaction sa;
 #endif /* HAVE_SIGACTION */
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   /*
    * Initialize file handles.
    */
@@ -780,8 +774,6 @@ reload(int signum)
   int child;
   int status;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   if (getpid() != masterpid)
     return;
 
@@ -833,8 +825,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 18374a72bfd7dbc8ef44d8205b9afd4b495b9fae..0a6f6c80e138fb57492b980ad4ba0567f33f62d3 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 */
   }
@@ -229,8 +227,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);
@@ -484,8 +480,6 @@ hlfsd_getpwent(void)
     return getpwent();
   }
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   /* return here to read another entry */
 readent:
 
@@ -594,8 +588,6 @@ plt_reset(void)
 {
   int i;
 
-  clock_valid = 0;             /* invalidate logging clock */
-
   hlfsd_setpwent();
   if (hlfsd_getpwent() == (struct passwd *) NULL) {
     hlfsd_endpwent();
@@ -640,8 +632,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 24b193f9ef28d4295124347aeb620ea14bf12312..5d7a16830c63f2c268296950a09f2fd78a6ae194 100644 (file)
 #define XLOG_DEFSTR    "all,nomap,nostats"     /* Default log options */
 #define XLOG_ALL       (XLOG_FATAL|XLOG_ERROR|XLOG_USER|XLOG_WARNING|XLOG_INFO|XLOG_MAP|XLOG_STATS)
 
-#define clocktime() (clock_valid ? clock_valid : time(&clock_valid))
-
 #define NO_SUBNET      "notknown"   /* default subnet name for no subnet */
 #define        NEXP_AP         (1022)                  /* gdmr: was 254 */
 #define NEXP_AP_MARGIN (128)                   /* ???? not used */
@@ -267,7 +265,6 @@ extern int xlog_level_init;
 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 */
 
 /*
@@ -334,7 +331,7 @@ extern u_long get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_ve
 extern long get_server_pid(void);
 extern int xsnprintf(char *str, size_t size, const char *format, ...);
 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 163b17095eae761d284572a66ccdfe0fa698c65e..fe4ed62dac904c51256027d3fd079946bde64b1d 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 51837cbef3dc71672fa7480e6a595409c4cc0aa0..f3c4a67a2a172bf5b47dd616bfd07f8e98fcf439 100644 (file)
@@ -68,9 +68,6 @@ int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS;
 int xlog_level_init = ~0;
 static int 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);
@@ -842,9 +839,14 @@ switch_to_logfile(char *logfile, int old_umask, int truncate_log)
 void
 unregister_amq(void)
 {
-  if (!amuDebug(D_AMQ))
+  if (amuDebug(D_AMQ)) {
     /* find which instance of amd to unregister */
-    pmap_unset(get_amd_program_number(), AMQ_VERSION);
+    u_long amd_prognum = get_amd_program_number();
+
+    if (pmap_unset(amd_prognum, AMQ_VERSION) != 1)
+      dlog("failed to de-register Amd program %lu, version %lu",
+          amd_prognum, AMQ_VERSION);
+  }
 }
 
 
@@ -1000,3 +1002,25 @@ setup_sighandler(int signum, void (*handler)(int))
 }
 
 
+/*
+ * 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;
+}
diff --git a/vers.m4 b/vers.m4
index 656ddeaebf3532551d77f208c25283ee45ed7bbc..931a0756c2654cdc1693be2a325b7c1b99028112 100644 (file)
--- a/vers.m4
+++ b/vers.m4
@@ -1 +1 @@
-[6.1.2-rc1]dnl
+[6.1.2]dnl