From 79ff473c2a07078bde8900e66a6db1a17039a956 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 8 Nov 2012 15:02:20 -0500 Subject: [PATCH] nfsdcltrack: add a legacy transition mechanism If the kernel passes the legacy recdir path in the environment, then we can use that to transition from the old legacy tracker to the new one. On a "check" operation, if there is no record of the client in the database, check to see if there is a matching recoverydir. If there isn't then just refuse the reclaim. If there is, then insert a new record for this client into the db, and remove the legacy recoverydir. If either of those operations fail, then refuse the reclaim. On a "gracedone" operation, clean out the entire legacy recoverydir after purging any unreclaimed records from the db. There's not much we can do if this fails, so just log a warning if it does. Note that this is a one-way conversion. If the user later boots back into an older kernel, it will have no knowledge of the new database. In principle, we could create a tool that would walk the clients table, md5 hash the clientids and create directories in the v4recovery dir. Doing that automatically would be pretty difficult however. Signed-off-by: Jeff Layton Signed-off-by: Steve Dickson --- utils/nfsdcltrack/nfsdcltrack.c | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c index 1d262a2..9801b9c 100644 --- a/utils/nfsdcltrack/nfsdcltrack.c +++ b/utils/nfsdcltrack/nfsdcltrack.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef HAVE_SYS_CAPABILITY_H #include #include @@ -295,6 +296,48 @@ cltrack_remove(const char *id) return ret ? -EREMOTEIO : ret; } +static int +cltrack_check_legacy(const unsigned char *blob, const ssize_t len) +{ + int ret; + struct stat st; + char *recdir = getenv("NFSDCLTRACK_LEGACY_RECDIR"); + + if (!recdir) { + xlog(D_GENERAL, "No NFSDCLTRACK_LEGACY_RECDIR env var"); + return -EOPNOTSUPP; + } + + /* fail recovery on any stat failure */ + ret = stat(recdir, &st); + if (ret) { + xlog(D_GENERAL, "Unable to stat %s: %d", recdir, errno); + return -errno; + } + + /* fail if it isn't a directory */ + if (!S_ISDIR(st.st_mode)) { + xlog(D_GENERAL, "%s is not a directory: mode=0%o", recdir + , st.st_mode); + return -ENOTDIR; + } + + /* Dir exists, try to insert record into db */ + ret = sqlite_insert_client(blob, len); + if (ret) { + xlog(D_GENERAL, "Failed to insert client: %d", ret); + return -EREMOTEIO; + } + + /* remove the legacy recoverydir */ + ret = rmdir(recdir); + if (ret) { + xlog(D_GENERAL, "Failed to rmdir %s: %d", recdir, errno); + return -errno; + } + return 0; +} + static int cltrack_check(const char *id) { @@ -312,10 +355,50 @@ cltrack_check(const char *id) return (int)len; ret = sqlite_check_client(blob, len); + if (ret) + ret = cltrack_check_legacy(blob, len); return ret ? -EPERM : ret; } +/* Clean out the v4recoverydir -- best effort here */ +static void +cltrack_legacy_gracedone(void) +{ + DIR *v4recovery; + struct dirent *entry; + char *dirname = getenv("NFSDCLTRACK_LEGACY_TOPDIR"); + + if (!dirname) + return; + + v4recovery = opendir(dirname); + if (!v4recovery) + return; + + while ((entry = readdir(v4recovery))) { + int len; + + /* borrow the clientid blob for this */ + len = snprintf((char *)blob, sizeof(blob), "%s/%s", dirname, + entry->d_name); + + /* if there's a problem, then skip this entry */ + if (len < 0 || (size_t)len >= sizeof(blob)) { + xlog(L_WARNING, "%s: unable to build filename for %s!", + __func__, entry->d_name); + continue; + } + + len = rmdir((char *)blob); + if (len) + xlog(L_WARNING, "%s: unable to rmdir %s: %d", __func__, + (char *)blob, len); + } + + closedir(v4recovery); +} + static int cltrack_gracedone(const char *timestr) { @@ -343,6 +426,8 @@ cltrack_gracedone(const char *timestr) ret = sqlite_remove_unreclaimed(gracetime); + cltrack_legacy_gracedone(); + return ret ? -EREMOTEIO : ret; } -- 2.39.5