You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
851 lines
23 KiB
851 lines
23 KiB
7 years ago
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index c9e9f87..6f3f3d6 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -9,34 +9,6 @@ MAINTAINERCLEANFILES = Makefile.in
|
||
|
EXTRA_DIST = \
|
||
|
autogen.sh \
|
||
|
\
|
||
|
- debian/changelog \
|
||
|
- debian/control \
|
||
|
- debian/copyright \
|
||
|
- debian/etc.exports \
|
||
|
- debian/idmapd.conf \
|
||
|
- debian/nfs-common.conffiles \
|
||
|
- debian/nfs-common.default \
|
||
|
- debian/nfs-common.dirs \
|
||
|
- debian/nfs-common.files \
|
||
|
- debian/nfs-common.init \
|
||
|
- debian/nfs-common.install \
|
||
|
- debian/nfs-common.postinst \
|
||
|
- debian/nfs-common.postrm \
|
||
|
- debian/nfs-common.prerm \
|
||
|
- debian/nfs-kernel-server.NEWS \
|
||
|
- debian/nfs-kernel-server.conffiles \
|
||
|
- debian/nfs-kernel-server.default \
|
||
|
- debian/nfs-kernel-server.dirs \
|
||
|
- debian/nfs-kernel-server.init \
|
||
|
- debian/nfs-kernel-server.postinst \
|
||
|
- debian/nfs-kernel-server.postrm \
|
||
|
- debian/nfs-kernel-server.prerm \
|
||
|
- debian/nhfsstone.dirs \
|
||
|
- debian/nhfsstone.files \
|
||
|
- debian/nhfsstone.postinst \
|
||
|
- debian/nhfsstone.prerm \
|
||
|
- debian/rules \
|
||
|
- \
|
||
|
aclocal/bsdsignals.m4 \
|
||
|
aclocal/nfs-utils.m4 \
|
||
|
aclocal/kerberos5.m4 \
|
||
|
diff --git a/support/include/Makefile.am b/support/include/Makefile.am
|
||
|
index 4b33ee9..5c80c8b 100644
|
||
|
--- a/support/include/Makefile.am
|
||
|
+++ b/support/include/Makefile.am
|
||
|
@@ -3,6 +3,7 @@
|
||
|
SUBDIRS = nfs rpcsvc sys
|
||
|
|
||
|
noinst_HEADERS = \
|
||
|
+ cld.h \
|
||
|
exportfs.h \
|
||
|
ha-callout.h \
|
||
|
misc.h \
|
||
|
@@ -10,9 +11,13 @@ noinst_HEADERS = \
|
||
|
nfs_paths.h \
|
||
|
nfslib.h \
|
||
|
nfsrpc.h \
|
||
|
+ nls.h \
|
||
|
nsm.h \
|
||
|
+ pseudoflavors.h \
|
||
|
rpcmisc.h \
|
||
|
+ sockaddr.h \
|
||
|
tcpwrapper.h \
|
||
|
+ v4root.h \
|
||
|
xio.h \
|
||
|
xlog.h \
|
||
|
xmalloc.h \
|
||
|
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
||
|
index faa8197..1f96264 100644
|
||
|
--- a/tests/Makefile.am
|
||
|
+++ b/tests/Makefile.am
|
||
|
@@ -11,3 +11,4 @@ SUBDIRS = nsm_client
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
|
||
|
TESTS = t0001-statd-basic-mon-unmon.sh
|
||
|
+EXTRA_DIST = test-lib.sh $(TESTS)
|
||
|
diff --git a/tests/nsm_client/Makefile.am b/tests/nsm_client/Makefile.am
|
||
|
index 4c15346..a8fc131 100644
|
||
|
--- a/tests/nsm_client/Makefile.am
|
||
|
+++ b/tests/nsm_client/Makefile.am
|
||
|
@@ -7,6 +7,7 @@ GENFILES_H = nlm_sm_inter.h
|
||
|
|
||
|
GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
|
||
|
|
||
|
+EXTRA_DIST = nlm_sm_inter.x
|
||
|
|
||
|
check_PROGRAMS = nsm_client
|
||
|
nsm_client_SOURCES = $(GENFILES) nsm_client.c
|
||
|
diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am
|
||
|
index af59791..a4e9c56 100644
|
||
|
--- a/utils/gssd/Makefile.am
|
||
|
+++ b/utils/gssd/Makefile.am
|
||
|
@@ -8,7 +8,6 @@ sbin_PREFIXED = gssd svcgssd
|
||
|
sbin_PROGRAMS = $(sbin_PREFIXED)
|
||
|
|
||
|
EXTRA_DIST = \
|
||
|
- gss_destroy_creds \
|
||
|
$(man8_MANS)
|
||
|
|
||
|
COMMON_SRCS = \
|
||
|
diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am
|
||
|
index 58b33ec..c2f8ba1 100644
|
||
|
--- a/utils/idmapd/Makefile.am
|
||
|
+++ b/utils/idmapd/Makefile.am
|
||
|
@@ -7,8 +7,7 @@ KPREFIX = @kprefix@
|
||
|
sbin_PROGRAMS = idmapd
|
||
|
|
||
|
EXTRA_DIST = \
|
||
|
- $(man8_MANS) \
|
||
|
- idmapd.conf
|
||
|
+ $(man8_MANS)
|
||
|
|
||
|
idmapd_SOURCES = \
|
||
|
idmapd.c \
|
||
|
diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
|
||
|
index 5810936..e24f3bd 100644
|
||
|
--- a/utils/mount/Makefile.am
|
||
|
+++ b/utils/mount/Makefile.am
|
||
|
@@ -8,19 +8,21 @@ man8_MANS = mount.nfs.man umount.nfs.man
|
||
|
man5_MANS = nfs.man
|
||
|
|
||
|
sbin_PROGRAMS = mount.nfs
|
||
|
-EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS)
|
||
|
+EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS)
|
||
|
mount_common = error.c network.c token.c \
|
||
|
parse_opt.c parse_dev.c \
|
||
|
nfsmount.c nfs4mount.c stropts.c\
|
||
|
mount_constants.h error.h network.h token.h \
|
||
|
parse_opt.h parse_dev.h \
|
||
|
- nfs4_mount.h nfs_mount4.h stropts.h version.h \
|
||
|
- mount_config.h utils.c utils.h
|
||
|
+ nfs4_mount.h stropts.h version.h \
|
||
|
+ mount_config.h utils.c utils.h \
|
||
|
+ nfs_mount.h
|
||
|
|
||
|
if MOUNT_CONFIG
|
||
|
mount_common += configfile.c
|
||
|
man5_MANS += nfsmount.conf.man
|
||
|
-EXTRA_DIST += nfsmount.conf
|
||
|
+else
|
||
|
+EXTRA_DIST += nfsmount.conf.man
|
||
|
endif
|
||
|
|
||
|
mount_nfs_LDADD = ../../support/nfs/libnfs.a \
|
||
|
diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am
|
||
|
index 7db968b..9e1ab5c 100644
|
||
|
--- a/utils/mountd/Makefile.am
|
||
|
+++ b/utils/mountd/Makefile.am
|
||
|
@@ -7,6 +7,7 @@ RPCPREFIX = rpc.
|
||
|
KPREFIX = @kprefix@
|
||
|
sbin_PROGRAMS = mountd
|
||
|
|
||
|
+noinst_HEADERS = fsloc.h
|
||
|
mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
|
||
|
svc_run.c fsloc.c v4root.c mountd.h
|
||
|
mountd_LDADD = ../../support/export/libexport.a \
|
||
|
diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am
|
||
|
index 1536065..39a6e6f 100644
|
||
|
--- a/utils/nfsd/Makefile.am
|
||
|
+++ b/utils/nfsd/Makefile.am
|
||
|
@@ -7,6 +7,7 @@ RPCPREFIX = rpc.
|
||
|
KPREFIX = @kprefix@
|
||
|
sbin_PROGRAMS = nfsd
|
||
|
|
||
|
+noinst_HEADERS = nfssvc.h
|
||
|
nfsd_SOURCES = nfsd.c nfssvc.c
|
||
|
nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC)
|
||
|
|
||
|
diff --git a/utils/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am
|
||
|
index a860ffb..d603f92 100644
|
||
|
--- a/utils/nfsdcltrack/Makefile.am
|
||
|
+++ b/utils/nfsdcltrack/Makefile.am
|
||
|
@@ -6,6 +6,8 @@ EXTRA_DIST = $(man8_MANS)
|
||
|
AM_CFLAGS += -D_LARGEFILE64_SOURCE
|
||
|
sbin_PROGRAMS = nfsdcltrack
|
||
|
|
||
|
+noinst_HEADERS = sqlite.h
|
||
|
+
|
||
|
nfsdcltrack_SOURCES = nfsdcltrack.c sqlite.c
|
||
|
nfsdcltrack_LDADD = ../../support/nfs/libnfs.a $(LIBSQLITE) $(LIBCAP)
|
||
|
|
||
|
diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c
|
||
|
index 4334340..fcdda7f 100644
|
||
|
--- a/utils/nfsdcltrack/nfsdcltrack.c
|
||
|
+++ b/utils/nfsdcltrack/nfsdcltrack.c
|
||
|
@@ -37,6 +37,7 @@
|
||
|
#include <libgen.h>
|
||
|
#include <sys/inotify.h>
|
||
|
#include <dirent.h>
|
||
|
+#include <limits.h>
|
||
|
#ifdef HAVE_SYS_CAPABILITY_H
|
||
|
#include <sys/prctl.h>
|
||
|
#include <sys/capability.h>
|
||
|
@@ -49,6 +50,8 @@
|
||
|
#define CLD_DEFAULT_STORAGEDIR NFS_STATEDIR "/nfsdcltrack"
|
||
|
#endif
|
||
|
|
||
|
+#define NFSD_END_GRACE_FILE "/proc/fs/nfsd/v4_end_grace"
|
||
|
+
|
||
|
/* defined by RFC 3530 */
|
||
|
#define NFS4_OPAQUE_LIMIT 1024
|
||
|
|
||
|
@@ -210,6 +213,64 @@ cltrack_set_caps(void)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+/* Inform the kernel that it's OK to lift nfsd's grace period */
|
||
|
+static void
|
||
|
+cltrack_lift_grace_period(void)
|
||
|
+{
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ fd = open(NFSD_END_GRACE_FILE, O_WRONLY);
|
||
|
+ if (fd < 0) {
|
||
|
+ /* Don't warn if file isn't present */
|
||
|
+ if (errno != ENOENT)
|
||
|
+ xlog(L_WARNING, "Unable to open %s: %m",
|
||
|
+ NFSD_END_GRACE_FILE);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (write(fd, "Y", 1) < 0)
|
||
|
+ xlog(L_WARNING, "Unable to write to %s: %m",
|
||
|
+ NFSD_END_GRACE_FILE);
|
||
|
+
|
||
|
+ close(fd);
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Fetch the contents of the NFSDCLTRACK_GRACE_START env var. If it's not set
|
||
|
+ * or there's an error converting it to time_t, then return LONG_MAX.
|
||
|
+ */
|
||
|
+static time_t
|
||
|
+cltrack_get_grace_start(void)
|
||
|
+{
|
||
|
+ time_t grace_start;
|
||
|
+ char *end;
|
||
|
+ char *grace_start_str = getenv("NFSDCLTRACK_GRACE_START");
|
||
|
+
|
||
|
+ if (!grace_start_str)
|
||
|
+ return LONG_MAX;
|
||
|
+
|
||
|
+ errno = 0;
|
||
|
+ grace_start = strtol(grace_start_str, &end, 0);
|
||
|
+ /* Problem converting or value is too large? */
|
||
|
+ if (errno)
|
||
|
+ return LONG_MAX;
|
||
|
+
|
||
|
+ return grace_start;
|
||
|
+}
|
||
|
+
|
||
|
+static bool
|
||
|
+cltrack_reclaims_complete(void)
|
||
|
+{
|
||
|
+ time_t grace_start = cltrack_get_grace_start();
|
||
|
+
|
||
|
+ /* Don't query DB if we didn't get a valid boot time */
|
||
|
+ if (grace_start == LONG_MAX)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ return !sqlite_query_reclaiming(grace_start);
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
cltrack_init(const char __attribute__((unused)) *unused)
|
||
|
{
|
||
|
@@ -241,7 +302,7 @@ cltrack_init(const char __attribute__((unused)) *unused)
|
||
|
}
|
||
|
|
||
|
/* set up storage db */
|
||
|
- ret = sqlite_maindb_init(storagedir);
|
||
|
+ ret = sqlite_prepare_dbh(storagedir);
|
||
|
if (ret) {
|
||
|
xlog(L_ERROR, "Failed to init database: %d", ret);
|
||
|
/*
|
||
|
@@ -250,15 +311,36 @@ cltrack_init(const char __attribute__((unused)) *unused)
|
||
|
* stop upcalling until the problem is resolved.
|
||
|
*/
|
||
|
ret = -EACCES;
|
||
|
+ } else {
|
||
|
+ if (cltrack_reclaims_complete())
|
||
|
+ cltrack_lift_grace_period();
|
||
|
}
|
||
|
+
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Fetch the contents of the NFSDCLTRACK_CLIENT_HAS_SESSION env var. If
|
||
|
+ * it's set and the first character is 'Y' then return true. Otherwise
|
||
|
+ * return false.
|
||
|
+ */
|
||
|
+static bool
|
||
|
+cltrack_client_has_session(void)
|
||
|
+{
|
||
|
+ char *has_session = getenv("NFSDCLTRACK_CLIENT_HAS_SESSION");
|
||
|
+
|
||
|
+ if (has_session && *has_session == 'Y')
|
||
|
+ return true;
|
||
|
+
|
||
|
+ return false;
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
cltrack_create(const char *id)
|
||
|
{
|
||
|
int ret;
|
||
|
ssize_t len;
|
||
|
+ bool has_session;
|
||
|
|
||
|
xlog(D_GENERAL, "%s: create client record.", __func__);
|
||
|
|
||
|
@@ -270,7 +352,12 @@ cltrack_create(const char *id)
|
||
|
if (len < 0)
|
||
|
return (int)len;
|
||
|
|
||
|
- ret = sqlite_insert_client(blob, len);
|
||
|
+ has_session = cltrack_client_has_session();
|
||
|
+
|
||
|
+ ret = sqlite_insert_client(blob, len, has_session, false);
|
||
|
+
|
||
|
+ if (!ret && has_session && cltrack_reclaims_complete())
|
||
|
+ cltrack_lift_grace_period();
|
||
|
|
||
|
return ret ? -EREMOTEIO : ret;
|
||
|
}
|
||
|
@@ -297,7 +384,8 @@ cltrack_remove(const char *id)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-cltrack_check_legacy(const unsigned char *blob, const ssize_t len)
|
||
|
+cltrack_check_legacy(const unsigned char *blob, const ssize_t len,
|
||
|
+ bool has_session)
|
||
|
{
|
||
|
int ret;
|
||
|
struct stat st;
|
||
|
@@ -323,7 +411,7 @@ cltrack_check_legacy(const unsigned char *blob, const ssize_t len)
|
||
|
}
|
||
|
|
||
|
/* Dir exists, try to insert record into db */
|
||
|
- ret = sqlite_insert_client(blob, len);
|
||
|
+ ret = sqlite_insert_client(blob, len, has_session, has_session);
|
||
|
if (ret) {
|
||
|
xlog(D_GENERAL, "Failed to insert client: %d", ret);
|
||
|
return -EREMOTEIO;
|
||
|
@@ -343,6 +431,7 @@ cltrack_check(const char *id)
|
||
|
{
|
||
|
int ret;
|
||
|
ssize_t len;
|
||
|
+ bool has_session;
|
||
|
|
||
|
xlog(D_GENERAL, "%s: check client record", __func__);
|
||
|
|
||
|
@@ -354,9 +443,11 @@ cltrack_check(const char *id)
|
||
|
if (len < 0)
|
||
|
return (int)len;
|
||
|
|
||
|
- ret = sqlite_check_client(blob, len);
|
||
|
+ has_session = cltrack_client_has_session();
|
||
|
+
|
||
|
+ ret = sqlite_check_client(blob, len, has_session);
|
||
|
if (ret)
|
||
|
- ret = cltrack_check_legacy(blob, len);
|
||
|
+ ret = cltrack_check_legacy(blob, len, has_session);
|
||
|
|
||
|
return ret ? -EPERM : ret;
|
||
|
}
|
||
|
diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c
|
||
|
index bac6789..eb1711a 100644
|
||
|
--- a/utils/nfsdcltrack/sqlite.c
|
||
|
+++ b/utils/nfsdcltrack/sqlite.c
|
||
|
@@ -21,17 +21,15 @@
|
||
|
* Explanation:
|
||
|
*
|
||
|
* This file contains the code to manage the sqlite backend database for the
|
||
|
- * clstated upcall daemon.
|
||
|
+ * nfsdcltrack usermodehelper upcall program.
|
||
|
*
|
||
|
* The main database is called main.sqlite and contains the following tables:
|
||
|
*
|
||
|
* parameters: simple key/value pairs for storing database info
|
||
|
*
|
||
|
- * clients: one column containing a BLOB with the as sent by the client
|
||
|
- * and a timestamp (in epoch seconds) of when the record was
|
||
|
- * established
|
||
|
- *
|
||
|
- * FIXME: should we also record the fsid being accessed?
|
||
|
+ * clients: an "id" column containing a BLOB with the long-form clientid as
|
||
|
+ * sent by the client, a "time" column containing a timestamp (in
|
||
|
+ * epoch seconds) of when the record was last updated.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
@@ -52,10 +50,10 @@
|
||
|
|
||
|
#include "xlog.h"
|
||
|
|
||
|
-#define CLD_SQLITE_SCHEMA_VERSION 1
|
||
|
+#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 1
|
||
|
|
||
|
/* in milliseconds */
|
||
|
-#define CLD_SQLITE_BUSY_TIMEOUT 10000
|
||
|
+#define CLTRACK_SQLITE_BUSY_TIMEOUT 10000
|
||
|
|
||
|
/* private data structures */
|
||
|
|
||
|
@@ -90,135 +88,192 @@ mkdir_if_not_exist(const char *dirname)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-/* Open the database and set up the database handle for it */
|
||
|
-int
|
||
|
-sqlite_prepare_dbh(const char *topdir)
|
||
|
+static int
|
||
|
+sqlite_query_schema_version(void)
|
||
|
{
|
||
|
int ret;
|
||
|
+ sqlite3_stmt *stmt = NULL;
|
||
|
|
||
|
- /* Do nothing if the database handle is already set up */
|
||
|
- if (dbh)
|
||
|
- return 0;
|
||
|
-
|
||
|
- ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", topdir);
|
||
|
- if (ret < 0)
|
||
|
- return ret;
|
||
|
-
|
||
|
- buf[PATH_MAX - 1] = '\0';
|
||
|
-
|
||
|
- ret = sqlite3_open(buf, &dbh);
|
||
|
+ /* prepare select query */
|
||
|
+ ret = sqlite3_prepare_v2(dbh,
|
||
|
+ "SELECT value FROM parameters WHERE key == \"version\";",
|
||
|
+ -1, &stmt, NULL);
|
||
|
if (ret != SQLITE_OK) {
|
||
|
- xlog(L_ERROR, "Unable to open main database: %d", ret);
|
||
|
- dbh = NULL;
|
||
|
- return ret;
|
||
|
+ xlog(L_ERROR, "Unable to prepare select statement: %s",
|
||
|
+ sqlite3_errmsg(dbh));
|
||
|
+ ret = 0;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
- ret = sqlite3_busy_timeout(dbh, CLD_SQLITE_BUSY_TIMEOUT);
|
||
|
- if (ret != SQLITE_OK) {
|
||
|
- xlog(L_ERROR, "Unable to set sqlite busy timeout: %d", ret);
|
||
|
- sqlite3_close(dbh);
|
||
|
- dbh = NULL;
|
||
|
+ /* query schema version */
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret != SQLITE_ROW) {
|
||
|
+ xlog(L_ERROR, "Select statement execution failed: %s",
|
||
|
+ sqlite3_errmsg(dbh));
|
||
|
+ ret = 0;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
+ ret = sqlite3_column_int(stmt, 0);
|
||
|
+out:
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Open the "main" database, and attempt to initialize it by creating the
|
||
|
- * parameters table and inserting the schema version into it. Ignore any errors
|
||
|
- * from that, and then attempt to select the version out of it again. If the
|
||
|
- * version appears wrong, then assume that the DB is corrupt or has been
|
||
|
- * upgraded, and return an error. If all of that works, then attempt to create
|
||
|
- * the "clients" table.
|
||
|
+ * Start an exclusive transaction and recheck the DB schema version. If it's
|
||
|
+ * still zero (indicating a new database) then set it up. If that all works,
|
||
|
+ * then insert schema version into the parameters table and commit the
|
||
|
+ * transaction. On any error, rollback the transaction.
|
||
|
*/
|
||
|
int
|
||
|
-sqlite_maindb_init(const char *topdir)
|
||
|
+sqlite_maindb_init_v1(void)
|
||
|
{
|
||
|
int ret;
|
||
|
char *err = NULL;
|
||
|
- sqlite3_stmt *stmt = NULL;
|
||
|
|
||
|
- ret = mkdir_if_not_exist(topdir);
|
||
|
- if (ret)
|
||
|
+ /* Start a transaction */
|
||
|
+ ret = sqlite3_exec(dbh, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL,
|
||
|
+ &err);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to begin transaction: %s", err);
|
||
|
return ret;
|
||
|
+ }
|
||
|
|
||
|
- ret = sqlite_prepare_dbh(topdir);
|
||
|
- if (ret)
|
||
|
- return ret;
|
||
|
+ /*
|
||
|
+ * Check schema version again. This time, under an exclusive
|
||
|
+ * transaction to guard against racing DB setup attempts
|
||
|
+ */
|
||
|
+ ret = sqlite_query_schema_version();
|
||
|
+ switch (ret) {
|
||
|
+ case 0:
|
||
|
+ /* Query failed again -- set up DB */
|
||
|
+ break;
|
||
|
+ case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION:
|
||
|
+ /* Someone else raced in and set it up */
|
||
|
+ ret = 0;
|
||
|
+ goto rollback;
|
||
|
+ default:
|
||
|
+ /* Something went wrong -- fail! */
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto rollback;
|
||
|
+ }
|
||
|
|
||
|
- /* Try to create table */
|
||
|
- ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS parameters "
|
||
|
+ ret = sqlite3_exec(dbh, "CREATE TABLE parameters "
|
||
|
"(key TEXT PRIMARY KEY, value TEXT);",
|
||
|
NULL, NULL, &err);
|
||
|
if (ret != SQLITE_OK) {
|
||
|
- xlog(L_ERROR, "Unable to create parameter table: %d", ret);
|
||
|
- goto out_err;
|
||
|
+ xlog(L_ERROR, "Unable to create parameter table: %s", err);
|
||
|
+ goto rollback;
|
||
|
}
|
||
|
|
||
|
- /* insert version into table -- ignore error if it fails */
|
||
|
- ret = snprintf(buf, sizeof(buf),
|
||
|
- "INSERT OR IGNORE INTO parameters values (\"version\", "
|
||
|
- "\"%d\");", CLD_SQLITE_SCHEMA_VERSION);
|
||
|
+ /* create the "clients" table */
|
||
|
+ ret = sqlite3_exec(dbh, "CREATE TABLE clients (id BLOB PRIMARY KEY, "
|
||
|
+ "time INTEGER);",
|
||
|
+ NULL, NULL, &err);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to create clients table: %s", err);
|
||
|
+ goto rollback;
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
+ /* insert version into parameters table */
|
||
|
+ ret = snprintf(buf, sizeof(buf), "INSERT OR FAIL INTO parameters "
|
||
|
+ "values (\"version\", \"%d\");",
|
||
|
+ CLTRACK_SQLITE_LATEST_SCHEMA_VERSION);
|
||
|
if (ret < 0) {
|
||
|
- goto out_err;
|
||
|
+ xlog(L_ERROR, "sprintf failed!");
|
||
|
+ goto rollback;
|
||
|
} else if ((size_t)ret >= sizeof(buf)) {
|
||
|
+ xlog(L_ERROR, "sprintf output too long! (%d chars)", ret);
|
||
|
ret = -EINVAL;
|
||
|
- goto out_err;
|
||
|
+ goto rollback;
|
||
|
}
|
||
|
|
||
|
ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err);
|
||
|
if (ret != SQLITE_OK) {
|
||
|
- xlog(L_ERROR, "Unable to insert into parameter table: %d",
|
||
|
- ret);
|
||
|
- goto out_err;
|
||
|
+ xlog(L_ERROR, "Unable to insert into parameter table: %s", err);
|
||
|
+ goto rollback;
|
||
|
}
|
||
|
|
||
|
- ret = sqlite3_prepare_v2(dbh,
|
||
|
- "SELECT value FROM parameters WHERE key == \"version\";",
|
||
|
- -1, &stmt, NULL);
|
||
|
+ ret = sqlite3_exec(dbh, "COMMIT TRANSACTION;", NULL, NULL, &err);
|
||
|
if (ret != SQLITE_OK) {
|
||
|
- xlog(L_ERROR, "Unable to prepare select statement: %d", ret);
|
||
|
- goto out_err;
|
||
|
+ xlog(L_ERROR, "Unable to commit transaction: %s", err);
|
||
|
+ goto rollback;
|
||
|
}
|
||
|
+out:
|
||
|
+ sqlite3_free(err);
|
||
|
+ return ret;
|
||
|
|
||
|
- /* check schema version */
|
||
|
- ret = sqlite3_step(stmt);
|
||
|
- if (ret != SQLITE_ROW) {
|
||
|
- xlog(L_ERROR, "Select statement execution failed: %s",
|
||
|
+rollback:
|
||
|
+ /* Attempt to rollback the transaction */
|
||
|
+ sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err);
|
||
|
+ goto out;
|
||
|
+}
|
||
|
+
|
||
|
+/* Open the database and set up the database handle for it */
|
||
|
+int
|
||
|
+sqlite_prepare_dbh(const char *topdir)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ /* Do nothing if the database handle is already set up */
|
||
|
+ if (dbh)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", topdir);
|
||
|
+ if (ret < 0)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ buf[PATH_MAX - 1] = '\0';
|
||
|
+
|
||
|
+ /* open a new DB handle */
|
||
|
+ ret = sqlite3_open(buf, &dbh);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ /* try to create the dir */
|
||
|
+ ret = mkdir_if_not_exist(topdir);
|
||
|
+ if (ret)
|
||
|
+ goto out_close;
|
||
|
+
|
||
|
+ /* retry open */
|
||
|
+ ret = sqlite3_open(buf, &dbh);
|
||
|
+ if (ret != SQLITE_OK)
|
||
|
+ goto out_close;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* set busy timeout */
|
||
|
+ ret = sqlite3_busy_timeout(dbh, CLTRACK_SQLITE_BUSY_TIMEOUT);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to set sqlite busy timeout: %s",
|
||
|
sqlite3_errmsg(dbh));
|
||
|
- goto out_err;
|
||
|
+ goto out_close;
|
||
|
}
|
||
|
|
||
|
- /* process SELECT result */
|
||
|
- ret = sqlite3_column_int(stmt, 0);
|
||
|
- if (ret != CLD_SQLITE_SCHEMA_VERSION) {
|
||
|
+ ret = sqlite_query_schema_version();
|
||
|
+ switch (ret) {
|
||
|
+ case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION:
|
||
|
+ /* DB is already set up. Do nothing */
|
||
|
+ ret = 0;
|
||
|
+ break;
|
||
|
+ case 0:
|
||
|
+ /* Query failed -- try to set up new DB */
|
||
|
+ ret = sqlite_maindb_init_v1();
|
||
|
+ if (ret)
|
||
|
+ goto out_close;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ /* Unknown DB version -- downgrade? Fail */
|
||
|
xlog(L_ERROR, "Unsupported database schema version! "
|
||
|
"Expected %d, got %d.",
|
||
|
- CLD_SQLITE_SCHEMA_VERSION, ret);
|
||
|
+ CLTRACK_SQLITE_LATEST_SCHEMA_VERSION, ret);
|
||
|
ret = -EINVAL;
|
||
|
- goto out_err;
|
||
|
- }
|
||
|
-
|
||
|
- /* now create the "clients" table */
|
||
|
- ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS clients "
|
||
|
- "(id BLOB PRIMARY KEY, time INTEGER);",
|
||
|
- NULL, NULL, &err);
|
||
|
- if (ret != SQLITE_OK) {
|
||
|
- xlog(L_ERROR, "Unable to create clients table: %s", err);
|
||
|
- goto out_err;
|
||
|
+ goto out_close;
|
||
|
}
|
||
|
|
||
|
- sqlite3_free(err);
|
||
|
- sqlite3_finalize(stmt);
|
||
|
- return 0;
|
||
|
-
|
||
|
-out_err:
|
||
|
- if (err) {
|
||
|
- xlog(L_ERROR, "sqlite error: %s", err);
|
||
|
- sqlite3_free(err);
|
||
|
- }
|
||
|
- sqlite3_finalize(stmt);
|
||
|
+ return ret;
|
||
|
+out_close:
|
||
|
sqlite3_close(dbh);
|
||
|
+ dbh = NULL;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -228,14 +283,20 @@ out_err:
|
||
|
* Returns a non-zero sqlite error code, or SQLITE_OK (aka 0)
|
||
|
*/
|
||
|
int
|
||
|
-sqlite_insert_client(const unsigned char *clname, const size_t namelen)
|
||
|
+sqlite_insert_client(const unsigned char *clname, const size_t namelen,
|
||
|
+ const bool has_session, const bool zerotime)
|
||
|
{
|
||
|
int ret;
|
||
|
sqlite3_stmt *stmt = NULL;
|
||
|
|
||
|
- ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients VALUES "
|
||
|
- "(?, strftime('%s', 'now'));", -1,
|
||
|
- &stmt, NULL);
|
||
|
+ if (zerotime)
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients "
|
||
|
+ "VALUES (?, 0, ?);", -1, &stmt, NULL);
|
||
|
+ else
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients "
|
||
|
+ "VALUES (?, strftime('%s', 'now'), ?);", -1,
|
||
|
+ &stmt, NULL);
|
||
|
+
|
||
|
if (ret != SQLITE_OK) {
|
||
|
xlog(L_ERROR, "%s: insert statement prepare failed: %s",
|
||
|
__func__, sqlite3_errmsg(dbh));
|
||
|
@@ -250,6 +311,13 @@ sqlite_insert_client(const unsigned char *clname, const size_t namelen)
|
||
|
goto out_err;
|
||
|
}
|
||
|
|
||
|
+ ret = sqlite3_bind_int(stmt, 2, (int)has_session);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: bind int failed: %s", __func__,
|
||
|
+ sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
ret = sqlite3_step(stmt);
|
||
|
if (ret == SQLITE_DONE)
|
||
|
ret = SQLITE_OK;
|
||
|
@@ -305,7 +373,8 @@ out_err:
|
||
|
* return an error.
|
||
|
*/
|
||
|
int
|
||
|
-sqlite_check_client(const unsigned char *clname, const size_t namelen)
|
||
|
+sqlite_check_client(const unsigned char *clname, const size_t namelen,
|
||
|
+ const bool has_session)
|
||
|
{
|
||
|
int ret;
|
||
|
sqlite3_stmt *stmt = NULL;
|
||
|
@@ -340,6 +409,12 @@ sqlite_check_client(const unsigned char *clname, const size_t namelen)
|
||
|
goto out_err;
|
||
|
}
|
||
|
|
||
|
+ /* Only update timestamp for v4.0 clients */
|
||
|
+ if (has_session) {
|
||
|
+ ret = SQLITE_OK;
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
sqlite3_finalize(stmt);
|
||
|
stmt = NULL;
|
||
|
ret = sqlite3_prepare_v2(dbh, "UPDATE OR FAIL clients SET "
|
||
|
@@ -398,3 +473,43 @@ sqlite_remove_unreclaimed(time_t grace_start)
|
||
|
sqlite3_free(err);
|
||
|
return ret;
|
||
|
}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Are there any clients that are possibly still reclaiming? Return a positive
|
||
|
+ * integer (usually number of clients) if so. If not, then return 0. On any
|
||
|
+ * error, return non-zero.
|
||
|
+ */
|
||
|
+int
|
||
|
+sqlite_query_reclaiming(const time_t grace_start)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ sqlite3_stmt *stmt = NULL;
|
||
|
+
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "SELECT count(*) FROM clients WHERE "
|
||
|
+ "time < ? OR has_session != 1", -1, &stmt, NULL);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: unable to prepare select statement: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_bind_int64(stmt, 1, (sqlite3_int64)grace_start);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: bind int64 failed: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret != SQLITE_ROW) {
|
||
|
+ xlog(L_ERROR, "%s: unexpected return code from select: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_column_int(stmt, 0);
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ xlog(D_GENERAL, "%s: there are %d clients that have not completed "
|
||
|
+ "reclaim", __func__, ret);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/utils/nfsdcltrack/sqlite.h b/utils/nfsdcltrack/sqlite.h
|
||
|
index ebf04c3..06e7c04 100644
|
||
|
--- a/utils/nfsdcltrack/sqlite.h
|
||
|
+++ b/utils/nfsdcltrack/sqlite.h
|
||
|
@@ -21,10 +21,12 @@
|
||
|
#define _SQLITE_H_
|
||
|
|
||
|
int sqlite_prepare_dbh(const char *topdir);
|
||
|
-int sqlite_maindb_init(const char *topdir);
|
||
|
-int sqlite_insert_client(const unsigned char *clname, const size_t namelen);
|
||
|
+int sqlite_insert_client(const unsigned char *clname, const size_t namelen,
|
||
|
+ const bool has_session, const bool zerotime);
|
||
|
int sqlite_remove_client(const unsigned char *clname, const size_t namelen);
|
||
|
-int sqlite_check_client(const unsigned char *clname, const size_t namelen);
|
||
|
+int sqlite_check_client(const unsigned char *clname, const size_t namelen,
|
||
|
+ const bool has_session);
|
||
|
int sqlite_remove_unreclaimed(const time_t grace_start);
|
||
|
+int sqlite_query_reclaiming(const time_t grace_start);
|
||
|
|
||
|
#endif /* _SQLITE_H */
|
||
|
diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am
|
||
|
index 737a219..91cedfd 100644
|
||
|
--- a/utils/nfsidmap/Makefile.am
|
||
|
+++ b/utils/nfsidmap/Makefile.am
|
||
|
@@ -7,4 +7,4 @@ nfsidmap_SOURCES = nfsidmap.c
|
||
|
nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
-EXTRA_DIST = id_resolver.conf
|
||
|
+EXTRA_DIST = id_resolver.conf $(man8_MANS)
|
||
|
diff --git a/utils/osd_login/Makefile.am b/utils/osd_login/Makefile.am
|
||
|
index 20c2d8c..ded1fd3 100644
|
||
|
--- a/utils/osd_login/Makefile.am
|
||
|
+++ b/utils/osd_login/Makefile.am
|
||
|
@@ -4,6 +4,6 @@
|
||
|
# overridden at config time.
|
||
|
sbindir = /sbin
|
||
|
|
||
|
-sbin_SCRIPTS = osd_login
|
||
|
+dist_sbin_SCRIPTS = osd_login
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am
|
||
|
index dc2bfc4..152b680 100644
|
||
|
--- a/utils/statd/Makefile.am
|
||
|
+++ b/utils/statd/Makefile.am
|
||
|
@@ -8,7 +8,7 @@ sbin_PROGRAMS = statd sm-notify
|
||
|
dist_sbin_SCRIPTS = start-statd
|
||
|
statd_SOURCES = callback.c notlist.c misc.c monitor.c hostname.c \
|
||
|
simu.c stat.c statd.c svc_run.c rmtcall.c \
|
||
|
- notlist.h statd.h system.h version.h
|
||
|
+ notlist.h statd.h system.h
|
||
|
sm_notify_SOURCES = sm-notify.c
|
||
|
|
||
|
BUILT_SOURCES = $(GENFILES)
|
||
|
@@ -20,7 +20,7 @@ sm_notify_LDADD = ../../support/nsm/libnsm.a \
|
||
|
../../support/nfs/libnfs.a \
|
||
|
$(LIBNSL) $(LIBCAP) $(LIBTIRPC)
|
||
|
|
||
|
-EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
|
||
|
+EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c
|
||
|
|
||
|
if CONFIG_RPCGEN
|
||
|
RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
|