Skip to content

Commit

Permalink
nfsd: don't search for client by hash on legacy reboot recovery grace…
Browse files Browse the repository at this point in the history
…done

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>
  • Loading branch information
jtlayton authored and J. Bruce Fields committed Nov 12, 2012
1 parent 772a9bb commit 0ce0c2b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
31 changes: 27 additions & 4 deletions fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -182,13 +184,19 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
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);
}
Expand Down Expand Up @@ -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))
Expand All @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -410,6 +427,8 @@ nfsd4_init_recdir(void)
}

nfs4_reset_creds(original_cred);
if (!status)
in_grace = true;
return status;
}

Expand Down Expand Up @@ -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;
}

Expand Down
12 changes: 5 additions & 7 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -4483,16 +4483,13 @@ alloc_reclaim(void)
return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
}

int
bool
nfs4_has_reclaimed_state(const char *name)
{
unsigned int strhashval = clientstr_hashval(name);
struct nfs4_client *clp;
struct nfs4_client_reclaim *crp;

clp = find_confirmed_client_by_str(name, strhashval);
if (!clp)
return 0;
return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
crp = nfsd4_find_reclaim_client(name);
return (crp && crp->cr_clp);
}

/*
Expand All @@ -4511,6 +4508,7 @@ nfs4_client_to_reclaim(const char *name)
INIT_LIST_HEAD(&crp->cr_strhash);
list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
memcpy(crp->cr_recdir, name, HEXDIR_LEN);
crp->cr_clp = NULL;
reclaim_str_hashtbl_size++;
}
return crp;
Expand Down
4 changes: 2 additions & 2 deletions fs/nfsd/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ is_client_expired(struct nfs4_client *clp)
*/
struct nfs4_client_reclaim {
struct list_head cr_strhash; /* hash by cr_name */
struct nfs4_client *cr_clp; /* pointer to associated clp */
char cr_recdir[HEXDIR_LEN]; /* recover dir */
};

Expand Down Expand Up @@ -464,7 +465,6 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net,
stateid_t *stateid, int flags, struct file **filp);
extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void);
void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *);
extern void nfs4_release_reclaim(void);
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir);
Expand All @@ -483,7 +483,7 @@ extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name);
extern int nfs4_has_reclaimed_state(const char *name);
extern bool nfs4_has_reclaimed_state(const char *name);
extern void release_session_client(struct nfsd4_session *);
extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);

Expand Down

0 comments on commit 0ce0c2b

Please sign in to comment.