+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.
-*** 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
do_memory_locking();
}
- do_mapc_reload = clocktime() + gopt.map_reload_interval;
+ do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
/*
* Register automounter with system.
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
* 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;
}
}
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
cp->callout = 0;
cp->mp = new_mp;
cp->retry = TRUE;
- cp->start = clocktime();
+ cp->start = clocktime(NULL);
cp->mf = new_mp->am_mfarray;
/*
*/
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);
} 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();
}
}
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
* 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);
/*
* 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
if (task_notify_todo)
do_task_notify();
- now = clocktime();
+ now = clocktime(NULL);
/*
* While there are more callouts waiting...
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' */
}
timeo.tv_usec = 0;
- now = clocktime() - start;
+ now = clocktime(NULL) - start;
if (secs <= 0)
timeo.tv_sec = 0;
else if (now < secs)
if (mapfd >= 0) {
if (tp)
- *tp = clocktime();
+ *tp = clocktime(NULL);
return exec_parse_qanswer(mapfd, map, key, pval, tp);
}
if (mapf && tp) {
struct stat stb;
if (fstat(fileno(mapf), &stb) < 0)
- *tp = clocktime();
+ *tp = clocktime(NULL);
else
*tp = stb.st_mtime;
}
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");
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);
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 */
}
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);
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;
}
}
* 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)) {
{
int i;
time_t t = NEVER;
- time_t now = clocktime();
+ time_t now = clocktime(NULL);
int backoff = NumChildren / 4;
dlog("Timing out automount points...");
* 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;
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;
}
}
mapc_clear(m);
memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash));
m->modify = t;
+ ret = 1;
}
m->wildcard = 0;
error = mapc_search(m, wildcard, &m->wildcard);
if (error)
m->wildcard = 0;
+ return ret;
}
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);
}
}
}
static int
root_init(mnt_map *m, char *map, time_t *tp)
{
- *tp = clocktime();
+ *tp = clocktime(NULL);
return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
}
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
/*
* 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;
}
int smask = sigblock(MASKED_SIGS);
#endif /* not HAVE_SIGACTION */
- next_softclock = clocktime();
+ next_softclock = clocktime(NULL);
amd_state = Run;
* 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)
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:");
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)
* 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
static rpc_forward *
fwd_alloc(void)
{
- time_t now = clocktime();
+ time_t now = clocktime(NULL);
rpc_forward *p = 0, *p2;
/*
/*
* 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;
/*
/*
* 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) {
* 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;
* 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;
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;
}
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;
endmntent(mfp);
mfp = 0;
}
- clock_valid = 0;
if (stat(mnttabname, &st_before) < 0) {
plog(XLOG_ERROR, "%s: stat: %m", mnttabname);
if (errno == ESTALE) {
endmntent(mfp);
mfp = 0;
}
- clock_valid = 0;
if (stat(mnttabname, &st_before) < 0) {
plog(XLOG_ERROR, "%s: stat: %m", mnttabname);
if (errno == ESTALE) {
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)
*************************************************************************/
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
struct sigaction sa;
#endif /* HAVE_SIGACTION */
- clock_valid = 0; /* invalidate logging clock */
-
/*
* Initialize file handles.
*/
int child;
int status;
- clock_valid = 0; /* invalidate logging clock */
-
if (getpid() != masterpid)
return;
struct stat stbuf;
int umount_result;
- clock_valid = 0; /* invalidate logging clock */
-
if (!amuDebug(D_DAEMON)) {
if (getpid() != masterpid)
return;
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 */
}
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);
return getpwent();
}
- clock_valid = 0; /* invalidate logging clock */
-
/* return here to read another entry */
readent:
{
int i;
- clock_valid = 0; /* invalidate logging clock */
-
hlfsd_setpwent();
if (hlfsd_getpwent() == (struct passwd *) NULL) {
hlfsd_endpwent();
{
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 *
#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 */
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 */
/*
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 *);
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) {
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;
}
else
#endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */
- t = clocktime();
+ t = clocktime(NULL);
if (t != last_t) {
last_ctime = ctime(&t);
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);
+ }
}
}
+/*
+ * 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;
+}
-[6.1.2-rc1]dnl
+[6.1.2]dnl