Allow the fetching of NFSDCLTRACK_GRACE_START out of environment variables. If it's present in the "create" or "init" upcalls, then we can use that to query the database to see whether there are any clients that have not issued a RECLAIM_COMPLETE since that time. If there aren't any, then we know that all reclaim activity is now done and we can then cue the kernel to lift the grace period. Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxxxxxxx> --- utils/nfsdcltrack/nfsdcltrack.c | 72 ++++++++++++++++++++++++++++++++++++++++- utils/nfsdcltrack/sqlite.c | 40 +++++++++++++++++++++++ utils/nfsdcltrack/sqlite.h | 1 + 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c index 873b1fae056d..7d20f7d27d1a 100644 --- a/utils/nfsdcltrack/nfsdcltrack.c +++ b/utils/nfsdcltrack/nfsdcltrack.c @@ -50,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 @@ -211,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) { @@ -251,7 +311,11 @@ 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; } @@ -276,6 +340,7 @@ cltrack_create(const char *id) { int ret; ssize_t len; + bool reclaim_complete; xlog(D_GENERAL, "%s: create client record.", __func__); @@ -287,7 +352,12 @@ cltrack_create(const char *id) if (len < 0) return (int)len; - ret = sqlite_insert_client(blob, len, cltrack_get_reclaim_complete()); + reclaim_complete = cltrack_get_reclaim_complete(); + + ret = sqlite_insert_client(blob, len, reclaim_complete); + + if (!ret && reclaim_complete && cltrack_reclaims_complete()) + cltrack_lift_grace_period(); return ret ? -EREMOTEIO : ret; } diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c index e2a860f4b924..616a5e59d528 100644 --- a/utils/nfsdcltrack/sqlite.c +++ b/utils/nfsdcltrack/sqlite.c @@ -547,3 +547,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 " + "reclaim_complete < ?", -1, &stmt, NULL); + if (ret != SQLITE_OK) { + xlog(L_ERROR, "%s: unable to prepare select statement: %s", + __func__, sqlite3_errstr(ret)); + 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_errstr(ret)); + return ret; + } + + ret = sqlite3_step(stmt); + if (ret != SQLITE_ROW) { + xlog(L_ERROR, "%s: unexpected return code from select: %s", + __func__, sqlite3_errstr(ret)); + 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 9d7357bcf832..32b92d799b4a 100644 --- a/utils/nfsdcltrack/sqlite.h +++ b/utils/nfsdcltrack/sqlite.h @@ -26,5 +26,6 @@ int sqlite_insert_client(const unsigned char *clname, const size_t namelen, 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_remove_unreclaimed(const time_t grace_start); +int sqlite_query_reclaiming(const time_t grace_start); #endif /* _SQLITE_H */ -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html