summaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4recover.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-11-12 21:00:55 +0100
committerJ. Bruce Fields <bfields@redhat.com>2012-11-13 00:55:11 +0100
commit0ce0c2b5d23080eec39ccc52354be1eea326ed5f (patch)
tree560db260bfd579a0b78f75eca46fbf67a90ed6ed /fs/nfsd/nfs4recover.c
parentnfsd: make nfs4_client_to_reclaim return a pointer to the reclaim record (diff)
downloadlinux-0ce0c2b5d23080eec39ccc52354be1eea326ed5f.tar.xz
linux-0ce0c2b5d23080eec39ccc52354be1eea326ed5f.zip
nfsd: don't search for client by hash on legacy reboot recovery gracedone
When nfsd starts, the legacy reboot recovery code creates a tracking struct for each directory in the v4recoverydir. When the grace period ends, it basically does a "readdir" on the directory again, and matches each dentry in there to an existing client id to see if it should be removed or not. If the matching client doesn't exist, or hasn't reclaimed its state then it will remove that dentry. This is pretty inefficient since it involves doing a lot of hash-bucket searching. It also means that we have to keep relying on being able to search for a nfs4_client by md5 hashed cl_recdir name. Instead, add a pointer to the nfs4_client that indicates the association between the nfs4_client_reclaim and nfs4_client. When a reclaim operation comes in, we set the pointer to make that association. On gracedone, the legacy client tracker will keep the recdir around iff: 1/ there is a reclaim record for the directory ...and... 2/ there's an association between the reclaim record and a client record -- that is, a create or check operation was performed on the client that matches that directory. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4recover.c')
-rw-r--r--fs/nfsd/nfs4recover.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 4e92fb38cfb2..3048c012d4bc 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -65,6 +65,7 @@ struct nfsd4_client_tracking_ops {
static struct file *rec_file;
static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
static struct nfsd4_client_tracking_ops *client_tracking_ops;
+static bool in_grace;
static int
nfs4_save_creds(const struct cred **original_creds)
@@ -142,6 +143,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
const struct cred *original_cred;
char *dname = clp->cl_recdir;
struct dentry *dir, *dentry;
+ struct nfs4_client_reclaim *crp;
int status;
dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -182,13 +184,19 @@ out_put:
dput(dentry);
out_unlock:
mutex_unlock(&dir->d_inode->i_mutex);
- if (status == 0)
+ if (status == 0) {
+ if (in_grace) {
+ crp = nfs4_client_to_reclaim(clp->cl_recdir);
+ if (crp)
+ crp->cr_clp = clp;
+ }
vfs_fsync(rec_file, 0);
- else
+ } else {
printk(KERN_ERR "NFSD: failed to write recovery record"
" (err %d); please check that %s exists"
" and is writeable", status,
user_recovery_dirname);
+ }
mnt_drop_write_file(rec_file);
nfs4_reset_creds(original_cred);
}
@@ -289,6 +297,7 @@ static void
nfsd4_remove_clid_dir(struct nfs4_client *clp)
{
const struct cred *original_cred;
+ struct nfs4_client_reclaim *crp;
int status;
if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
@@ -305,8 +314,15 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
nfs4_reset_creds(original_cred);
- if (status == 0)
+ if (status == 0) {
vfs_fsync(rec_file, 0);
+ if (in_grace) {
+ /* remove reclaim record */
+ crp = nfsd4_find_reclaim_client(clp->cl_recdir);
+ if (crp)
+ nfs4_remove_reclaim_record(crp);
+ }
+ }
out_drop_write:
mnt_drop_write_file(rec_file);
out:
@@ -336,6 +352,7 @@ nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
{
int status;
+ in_grace = false;
if (!rec_file)
return;
status = mnt_want_write_file(rec_file);
@@ -410,6 +427,8 @@ nfsd4_init_recdir(void)
}
nfs4_reset_creds(original_cred);
+ if (!status)
+ in_grace = true;
return status;
}
@@ -481,13 +500,17 @@ nfs4_recoverydir(void)
static int
nfsd4_check_legacy_client(struct nfs4_client *clp)
{
+ struct nfs4_client_reclaim *crp;
+
/* did we already find that this client is stable? */
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
return 0;
/* look for it in the reclaim hashtable otherwise */
- if (nfsd4_find_reclaim_client(clp->cl_recdir)) {
+ crp = nfsd4_find_reclaim_client(clp->cl_recdir);
+ if (crp) {
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+ crp->cr_clp = clp;
return 0;
}