From: Neil Brown <neilb@suse.de>
To: Jeff Layton <jlayton@redhat.com>
Cc: nfs@lists.sourceforge.net
Subject: Re: [PATCH] nfs-utils: make auth_reload respect sub-second timestamps on etab
Date: Thu, 26 Apr 2007 14:50:34 +1000 [thread overview]
Message-ID: <17968.12186.298789.226396@notabene.brown> (raw)
In-Reply-To: message from Jeff Layton on Wednesday April 25
On Wednesday April 25, jlayton@redhat.com wrote:
Hi Jeff,
> Currently, when auth_reload is called, it only looks at the tv_sec field
> of the mtime when deciding whether to invalidate the exports cache. It's
> fairly simple to fool this by doing something like:
>
> # exportfs -rv && rpc.mountd && exportfs -uva && exportfs -iv -o no_root_squash,rw 127.0.0.1:/foo
Yes... real problem. Not sure I like your solution.
It obviously helps but it isn't complete (e.g. if filesystem only has
1-second resolution) and I think we can do better.
You can trade performance for accuracy by checking the current time as
well.
Something like:
now = time(0);
stat(_PATH_ETAB, &stb);
if (stb.st_mtime < last_loaded)
return;
last_loaded = now;
// read file.
That way if the file gets changed, we then read the file every time we
want information until the second changes. Then we read it once
more and hold on to that copy.
This might mean we read it several times in one second when only one
update was made, but at least it means we never miss an update.
Of course if the filesystem does provide better resolution, we should
use that, but we can only use it if we know that the resolution is -
and I don't think it is easy to extract that information.
But! We can get some hints from 'atime'. I think it safe to assume
that the resolution of atime is the same as that of ctime. so maybe
something like:
stat(_PATH_ETAB, &stb);
if (tspec_cmp(last_loaded, stb.st_mtim) < 0)
return;
last_loaded = stb.st_atim;
(excuse the pseudo-code. Assume tspec_cmp compares struct timespec
with return value similar to strcmp).
Here, 'last_loaded' represents a time period of a size which matches
the time-resolution of the filesystem. We know that time period ends
after the last time the file was modified, and it begins before the
last time we read the file.
If it is after the time-period when the file was change, we don't need
to read the file again, otherwise we do.
Now if the filesystem as mounted with noatime, this will leave us
always re-reading the file, so we need to assume a minimum resolution
of 1 second, and if atime < now, update atime to equal now.
And if the system clock was pushed back substantially, we would not
read the file until after it had caught up again, so we better leave the
"== last_modified" test in there.
Or maybe we could just note that 'exportfs' always replaced the file
when it updates it, and just check to see if the inode number is
different... though inode number re-use will defeat that (ext3
alternated between two) and we don't have access to a generation
number... better stick with time stamps.
So I would like the propose the following enhancement of your patch.
Do you agree?
Thanks,
NeilBrown
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
index 183c9ea..7c99ee3 100644
--- a/utils/mountd/auth.c
+++ b/utils/mountd/auth.c
@@ -46,24 +46,44 @@ auth_init(char *exports)
xtab_mount_write();
}
-time_t
+struct timespec
auth_reload()
{
+ /* "load_loaded" is an estimate of the last time we
+ * read the file, and importantly has the same resolution as
+ * the filesystem stores timestamps in. We only avoid reading
+ * if last_loaded is certain to be after the last time the file
+ * was modified.
+ * "last_modified" is used to guard against the system clock being
+ * set back, which would confuse the last_loaded calculations.
+ */
struct stat stb;
- static time_t last_modified = 0;
+ static struct timespec last_modified;
+ static struct timespec last_loaded;
+ time_t now = time(0);
if (stat(_PATH_ETAB, &stb) < 0)
xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
- if (stb.st_mtime == last_modified)
- return last_modified;
- last_modified = stb.st_mtime;
+
+ if (timespec_cmp(&stb.st_mtim, &last_loaded) < 0 &&
+ timespec_cmp(&stb.st_mtim, &last_modified) == 0)
+ return last_loaded;
+
+ last_loaded = stb.st_atim;
+ last_modified = stb.st_mtim;
+
+ /* careful of -o noatime */
+ if (last_loaded.tv_sec < now) {
+ last_loaded.tv_sec = now;
+ last_loaded.tv_nsec = 0;
+ }
export_freeall();
memset(&my_client, 0, sizeof(my_client));
// export_read(export_file);
xtab_export_read();
- return last_modified;
+ return last_loaded;
}
static nfs_export *
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
index 04141d1..c16f344 100644
--- a/utils/mountd/mountd.c
+++ b/utils/mountd/mountd.c
@@ -465,15 +465,15 @@ static exports
get_exportlist(void)
{
static exports elist = NULL;
- static time_t etime = 0;
- time_t atime;
+ static struct timespec etime;
+ struct timespec atime;
struct exportnode *e, *ne;
struct groupnode *g, *ng, *c, **cp;
nfs_export *exp;
int i;
atime = auth_reload();
- if (elist && atime == etime)
+ if (elist && timespec_cmp(&atime, &etime) == 0)
return elist;
etime = atime;
diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h
index b539278..3a780fa 100644
--- a/utils/mountd/mountd.h
+++ b/utils/mountd/mountd.h
@@ -40,7 +40,16 @@ bool_t mount_mnt_3_svc(struct svc_req *, dirpath *, mountres3 *);
void mount_dispatch(struct svc_req *, SVCXPRT *);
void auth_init(char *export_file);
-time_t auth_reload(void);
+
+static inline long int timespec_cmp(struct timespec *t1, struct timespec *t2)
+{
+ if (t1->tv_sec == t2->tv_sec)
+ return t1->tv_nsec - t2->tv_nsec;
+ else
+ return t1->tv_sec - t2->tv_sec;
+}
+
+struct timespec auth_reload(void);
nfs_export * auth_authenticate(char *what, struct sockaddr_in *sin,
char *path);
void auth_export(nfs_export *exp);
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
NFS maillist - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
next prev parent reply other threads:[~2007-04-26 4:50 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-25 17:39 [PATCH] nfs-utils: make auth_reload respect sub-second timestamps on etab Jeff Layton
2007-04-25 18:09 ` Jeff Layton
2007-04-25 20:13 ` Jeff Layton
2007-04-25 21:29 ` Chuck Lever
2007-04-26 4:56 ` Neil Brown
2007-04-26 12:05 ` Jeff Layton
2007-04-26 16:23 ` Jeff Layton
2007-04-26 16:58 ` J. Bruce Fields
2007-04-26 17:00 ` Jeff Layton
2007-04-26 17:24 ` J. Bruce Fields
2007-04-26 18:29 ` Jeff Layton
2007-05-03 0:55 ` Neil Brown
2007-05-03 11:58 ` Jeff Layton
2007-05-03 12:11 ` Jeff Layton
2007-04-26 17:33 ` Jeff Layton
2007-04-26 12:35 ` J. Bruce Fields
2007-04-26 4:50 ` Neil Brown [this message]
2007-04-26 11:50 ` Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=17968.12186.298789.226396@notabene.brown \
--to=neilb@suse.de \
--cc=jlayton@redhat.com \
--cc=nfs@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox