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.
850 lines
23 KiB
850 lines
23 KiB
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
|
|
|