summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2007-04-02 13:25:40 +1000
committerNeil Brown <neilb@suse.de>2007-04-02 13:25:40 +1000
commitdda3455d8b96a7b078bc00c113e1af15ed421d5b (patch)
tree50d1c08a904ff99714f69d1cea1422cd8d196143
parentca5f2d1e16a6451c1df203bccfd8944ee84c728f (diff)
downloadnfs-utils-dda3455d8b96a7b078bc00c113e1af15ed421d5b.tar.gz
nfs-utils-dda3455d8b96a7b078bc00c113e1af15ed421d5b.tar.xz
nfs-utils-dda3455d8b96a7b078bc00c113e1af15ed421d5b.zip
Tell NFS/lockd client what that local state number is.
Both SM_STAT and SM_MON can return the state of an NSM, but it is unclear which NSM they return the state of, so the value cannot be used, and lockd doesn't use it. Document this confusion, and give the current state to the kernel via a sysctl if that sysctl is available (since about 2.6.19). This should make is possible for the NFS server to detect a small class of bad SM_NOTIFY packets and not flush locks in that case. Signed-off-by: Neil Brown <neilb@suse.de>
-rw-r--r--utils/statd/monitor.c18
-rw-r--r--utils/statd/sm-notify.c21
-rw-r--r--utils/statd/stat.c15
-rw-r--r--utils/statd/statd.c23
4 files changed, 68 insertions, 9 deletions
diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c
index b95b0ad..bbc1dec 100644
--- a/utils/statd/monitor.c
+++ b/utils/statd/monitor.c
@@ -166,9 +166,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
mon_name, my_name);
/* But we'll let you pass anyway. */
- result.res_stat = STAT_SUCC;
- result.state = MY_STATE;
- return (&result);
+ goto success;
}
clnt = NL_NEXT(clnt);
}
@@ -222,10 +220,20 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
ha_callout("add-client", mon_name, my_name, -1);
nlist_insert(&rtnl, clnt);
close(fd);
-
+ dprintf(N_DEBUG, "MONITORING %s for %s", mon_name, my_name);
+ success:
result.res_stat = STAT_SUCC;
+ /* SUN's sm_inter.x says this should be "state number of local site".
+ * X/Open says '"state" will be contain the state of the remote NSM.'
+ * href=http://www.opengroup.org/onlinepubs/9629799/SM_MON.htm
+ * Linux lockd currently (2.6.21 and prior) ignores whatever is
+ * returned, and given the above contraction, it probably always will..
+ * So we just return what we always returned. If possible, we
+ * have already told lockd about our state number via a sysctl.
+ * If lockd wants the remote state, it will need to
+ * use SM_STAT (and prayer).
+ */
result.state = MY_STATE;
- dprintf(N_DEBUG, "MONITORING %s for %s", mon_name, my_name);
return (&result);
failure:
diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c
index a94876d..bb6c2ef 100644
--- a/utils/statd/sm-notify.c
+++ b/utils/statd/sm-notify.c
@@ -88,6 +88,7 @@ static struct addrinfo *host_lookup(int, const char *);
void nsm_log(int fac, const char *fmt, ...);
static int record_pid();
static void drop_privs(void);
+static void set_kernel_nsm_state(int state);
static struct nsm_host * hosts = NULL;
@@ -166,6 +167,10 @@ usage: fprintf(stderr,
backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH);
get_hosts(_SM_BAK_PATH);
+ /* Get and update the NSM state. This will call sync() */
+ nsm_state = nsm_get_state(opt_update_state);
+ set_kernel_nsm_state(nsm_state);
+
if (!opt_debug) {
if (!opt_quiet)
printf("Backgrounding to notify hosts...\n");
@@ -184,9 +189,6 @@ usage: fprintf(stderr,
close(2);
}
- /* Get and update the NSM state. This will call sync() */
- nsm_state = nsm_get_state(opt_update_state);
-
notify();
if (hosts) {
@@ -758,3 +760,16 @@ static void drop_privs(void)
exit(1);
}
}
+
+static void set_kernel_nsm_state(int state)
+{
+ int fd;
+
+ fd = open("/proc/sys/fs/nfs/nsm_local_state",O_WRONLY);
+ if (fd >= 0) {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", state);
+ write(fd, buf, strlen(buf));
+ close(fd);
+ }
+}
diff --git a/utils/statd/stat.c b/utils/statd/stat.c
index bcd3550..799239f 100644
--- a/utils/statd/stat.c
+++ b/utils/statd/stat.c
@@ -21,6 +21,21 @@
* status." My implementation is operative; it returns 'STAT_SUCC'
* whenever it can resolve the hostname that it's being asked to
* monitor, and returns 'STAT_FAIL' otherwise.
+ *
+ * sm_inter.x says the 'state' returned should be
+ * "state number of site sm_name". It is not clear how to get this.
+ * X/Open says:
+ * STAT_SUCC
+ * The NSM will monitor the given host. "sm_stat_res.state" contains
+ * the state of the NSM.
+ * Which implies that 'state' is the state number of the *local* NSM.
+ * href=http://www.opengroup.org/onlinepubs/9629799/SM_STAT.htm
+ *
+ * We return the *local* state as
+ * 1/ We have easy access to it.
+ * 2/ It might be useful to a remote client who needs it and has no
+ * other way to get it.
+ * 3/ That's what we always did in the past.
*/
struct sm_stat_res *
sm_stat_1_svc (struct sm_name *argp, struct svc_req *rqstp)
diff --git a/utils/statd/statd.c b/utils/statd/statd.c
index 091ced9..8337b64 100644
--- a/utils/statd/statd.c
+++ b/utils/statd/statd.c
@@ -76,6 +76,7 @@ static struct option longopts[] =
extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
extern int statd_get_socket(void);
+static void load_state_number(void);
#ifdef SIMULATIONS
extern void simulator (int, char **);
@@ -483,7 +484,7 @@ int main (int argc, char **argv)
* pass on any SM_NOTIFY that arrives
*/
load_state();
-
+ load_state_number();
pmap_unset (SM_PROG, SM_VERS);
/* this registers both UDP and TCP services */
@@ -526,3 +527,23 @@ int main (int argc, char **argv)
}
return 0;
}
+
+static void
+load_state_number(void)
+{
+ int fd;
+
+ if ((fd = open(SM_STAT_PATH, O_RDONLY)) == -1)
+ return;
+
+ read(fd, &MY_STATE, sizeof(MY_STATE));
+ close(fd);
+ fd = open("/proc/sys/fs/nfs/nsm_local_state",O_WRONLY);
+ if (fd >= 0) {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", MY_STATE);
+ write(fd, buf, strlen(buf));
+ close(fd);
+ }
+
+}