Commit 6b189105 authored by Scott Mayhew's avatar Scott Mayhew Committed by J. Bruce Fields

nfsd: make nfs4_client_reclaim use an xdr_netobj instead of a fixed char array

This will allow the reclaim_str_hashtbl to store either the recovery
directory names used by the legacy client tracking code or the full
client strings used by the nfsdcld client tracking code.
Signed-off-by: default avatarScott Mayhew <smayhew@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 9d69338c
...@@ -169,13 +169,34 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error) ...@@ -169,13 +169,34 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error)
} }
} }
static void
__nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
const char *dname, int len, struct nfsd_net *nn)
{
struct xdr_netobj name;
struct nfs4_client_reclaim *crp;
name.data = kmemdup(dname, len, GFP_KERNEL);
if (!name.data) {
dprintk("%s: failed to allocate memory for name.data!\n",
__func__);
return;
}
name.len = len;
crp = nfs4_client_to_reclaim(name, nn);
if (!crp) {
kfree(name.data);
return;
}
crp->cr_clp = clp;
}
static void static void
nfsd4_create_clid_dir(struct nfs4_client *clp) nfsd4_create_clid_dir(struct nfs4_client *clp)
{ {
const struct cred *original_cred; const struct cred *original_cred;
char dname[HEXDIR_LEN]; char dname[HEXDIR_LEN];
struct dentry *dir, *dentry; struct dentry *dir, *dentry;
struct nfs4_client_reclaim *crp;
int status; int status;
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
...@@ -221,11 +242,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) ...@@ -221,11 +242,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
out_unlock: out_unlock:
inode_unlock(d_inode(dir)); inode_unlock(d_inode(dir));
if (status == 0) { if (status == 0) {
if (nn->in_grace) { if (nn->in_grace)
crp = nfs4_client_to_reclaim(dname, nn); __nfsd4_create_reclaim_record_grace(clp, dname,
if (crp) HEXDIR_LEN, nn);
crp->cr_clp = clp;
}
vfs_fsync(nn->rec_file, 0); vfs_fsync(nn->rec_file, 0);
} else { } else {
printk(KERN_ERR "NFSD: failed to write recovery record" printk(KERN_ERR "NFSD: failed to write recovery record"
...@@ -345,11 +364,30 @@ nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn) ...@@ -345,11 +364,30 @@ nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
return status; return status;
} }
static void
__nfsd4_remove_reclaim_record_grace(const char *dname, int len,
struct nfsd_net *nn)
{
struct xdr_netobj name;
struct nfs4_client_reclaim *crp;
name.data = kmemdup(dname, len, GFP_KERNEL);
if (!name.data) {
dprintk("%s: failed to allocate memory for name.data!\n",
__func__);
return;
}
name.len = len;
crp = nfsd4_find_reclaim_client(name, nn);
kfree(name.data);
if (crp)
nfs4_remove_reclaim_record(crp, nn);
}
static void static void
nfsd4_remove_clid_dir(struct nfs4_client *clp) nfsd4_remove_clid_dir(struct nfs4_client *clp)
{ {
const struct cred *original_cred; const struct cred *original_cred;
struct nfs4_client_reclaim *crp;
char dname[HEXDIR_LEN]; char dname[HEXDIR_LEN];
int status; int status;
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
...@@ -374,12 +412,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) ...@@ -374,12 +412,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
nfs4_reset_creds(original_cred); nfs4_reset_creds(original_cred);
if (status == 0) { if (status == 0) {
vfs_fsync(nn->rec_file, 0); vfs_fsync(nn->rec_file, 0);
if (nn->in_grace) { if (nn->in_grace)
/* remove reclaim record */ __nfsd4_remove_reclaim_record_grace(dname,
crp = nfsd4_find_reclaim_client(dname, nn); HEXDIR_LEN, nn);
if (crp)
nfs4_remove_reclaim_record(crp, nn);
}
} }
out_drop_write: out_drop_write:
mnt_drop_write_file(nn->rec_file); mnt_drop_write_file(nn->rec_file);
...@@ -393,14 +428,31 @@ static int ...@@ -393,14 +428,31 @@ static int
purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
{ {
int status; int status;
struct xdr_netobj name;
if (nfs4_has_reclaimed_state(child->d_name.name, nn)) if (child->d_name.len != HEXDIR_LEN - 1) {
printk("%s: illegal name %pd in recovery directory\n",
__func__, child);
/* Keep trying; maybe the others are OK: */
return 0; return 0;
}
name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
if (!name.data) {
dprintk("%s: failed to allocate memory for name.data!\n",
__func__);
goto out;
}
name.len = HEXDIR_LEN;
if (nfs4_has_reclaimed_state(name, nn))
goto out_free;
status = vfs_rmdir(d_inode(parent), child); status = vfs_rmdir(d_inode(parent), child);
if (status) if (status)
printk("failed to remove client recovery directory %pd\n", printk("failed to remove client recovery directory %pd\n",
child); child);
out_free:
kfree(name.data);
out:
/* Keep trying, success or failure: */ /* Keep trying, success or failure: */
return 0; return 0;
} }
...@@ -430,13 +482,24 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn) ...@@ -430,13 +482,24 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn)
static int static int
load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
{ {
struct xdr_netobj name;
if (child->d_name.len != HEXDIR_LEN - 1) { if (child->d_name.len != HEXDIR_LEN - 1) {
printk("nfsd4: illegal name %pd in recovery directory\n", printk("%s: illegal name %pd in recovery directory\n",
child); __func__, child);
/* Keep trying; maybe the others are OK: */ /* Keep trying; maybe the others are OK: */
return 0; return 0;
} }
nfs4_client_to_reclaim(child->d_name.name, nn); name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
if (!name.data) {
dprintk("%s: failed to allocate memory for name.data!\n",
__func__);
goto out;
}
name.len = HEXDIR_LEN;
if (!nfs4_client_to_reclaim(name, nn))
kfree(name.data);
out:
return 0; return 0;
} }
...@@ -616,6 +679,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) ...@@ -616,6 +679,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
char dname[HEXDIR_LEN]; char dname[HEXDIR_LEN];
struct nfs4_client_reclaim *crp; struct nfs4_client_reclaim *crp;
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
struct xdr_netobj name;
/* did we already find that this client is stable? */ /* did we already find that this client is stable? */
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
...@@ -628,13 +692,22 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) ...@@ -628,13 +692,22 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
} }
/* look for it in the reclaim hashtable otherwise */ /* look for it in the reclaim hashtable otherwise */
crp = nfsd4_find_reclaim_client(dname, nn); name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
if (!name.data) {
dprintk("%s: failed to allocate memory for name.data!\n",
__func__);
goto out_enoent;
}
name.len = HEXDIR_LEN;
crp = nfsd4_find_reclaim_client(name, nn);
kfree(name.data);
if (crp) { if (crp) {
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
crp->cr_clp = clp; crp->cr_clp = clp;
return 0; return 0;
} }
out_enoent:
return -ENOENT; return -ENOENT;
} }
......
...@@ -1067,9 +1067,9 @@ static unsigned int clientid_hashval(u32 id) ...@@ -1067,9 +1067,9 @@ static unsigned int clientid_hashval(u32 id)
return id & CLIENT_HASH_MASK; return id & CLIENT_HASH_MASK;
} }
static unsigned int clientstr_hashval(const char *name) static unsigned int clientstr_hashval(struct xdr_netobj name)
{ {
return opaque_hashval(name, 8) & CLIENT_HASH_MASK; return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK;
} }
/* /*
...@@ -2048,11 +2048,6 @@ compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) ...@@ -2048,11 +2048,6 @@ compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
return memcmp(o1->data, o2->data, o1->len); return memcmp(o1->data, o2->data, o1->len);
} }
static int same_name(const char *n1, const char *n2)
{
return 0 == memcmp(n1, n2, HEXDIR_LEN);
}
static int static int
same_verf(nfs4_verifier *v1, nfs4_verifier *v2) same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
{ {
...@@ -6457,7 +6452,7 @@ alloc_reclaim(void) ...@@ -6457,7 +6452,7 @@ alloc_reclaim(void)
} }
bool bool
nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn)
{ {
struct nfs4_client_reclaim *crp; struct nfs4_client_reclaim *crp;
...@@ -6467,20 +6462,24 @@ nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) ...@@ -6467,20 +6462,24 @@ nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
/* /*
* failure => all reset bets are off, nfserr_no_grace... * failure => all reset bets are off, nfserr_no_grace...
*
* The caller is responsible for freeing name.data if NULL is returned (it
* will be freed in nfs4_remove_reclaim_record in the normal case).
*/ */
struct nfs4_client_reclaim * struct nfs4_client_reclaim *
nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn)
{ {
unsigned int strhashval; unsigned int strhashval;
struct nfs4_client_reclaim *crp; struct nfs4_client_reclaim *crp;
dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data);
crp = alloc_reclaim(); crp = alloc_reclaim();
if (crp) { if (crp) {
strhashval = clientstr_hashval(name); strhashval = clientstr_hashval(name);
INIT_LIST_HEAD(&crp->cr_strhash); INIT_LIST_HEAD(&crp->cr_strhash);
list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
memcpy(crp->cr_recdir, name, HEXDIR_LEN); crp->cr_name.data = name.data;
crp->cr_name.len = name.len;
crp->cr_clp = NULL; crp->cr_clp = NULL;
nn->reclaim_str_hashtbl_size++; nn->reclaim_str_hashtbl_size++;
} }
...@@ -6491,6 +6490,7 @@ void ...@@ -6491,6 +6490,7 @@ void
nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
{ {
list_del(&crp->cr_strhash); list_del(&crp->cr_strhash);
kfree(crp->cr_name.data);
kfree(crp); kfree(crp);
nn->reclaim_str_hashtbl_size--; nn->reclaim_str_hashtbl_size--;
} }
...@@ -6514,16 +6514,16 @@ nfs4_release_reclaim(struct nfsd_net *nn) ...@@ -6514,16 +6514,16 @@ nfs4_release_reclaim(struct nfsd_net *nn)
/* /*
* called from OPEN, CLAIM_PREVIOUS with a new clientid. */ * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
struct nfs4_client_reclaim * struct nfs4_client_reclaim *
nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn)
{ {
unsigned int strhashval; unsigned int strhashval;
struct nfs4_client_reclaim *crp = NULL; struct nfs4_client_reclaim *crp = NULL;
dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); dprintk("NFSD: nfs4_find_reclaim_client for name %.*s\n", name.len, name.data);
strhashval = clientstr_hashval(recdir); strhashval = clientstr_hashval(name);
list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
if (same_name(crp->cr_recdir, recdir)) { if (compare_blob(&crp->cr_name, &name) == 0) {
return crp; return crp;
} }
} }
......
...@@ -368,7 +368,7 @@ struct nfs4_client { ...@@ -368,7 +368,7 @@ struct nfs4_client {
struct nfs4_client_reclaim { struct nfs4_client_reclaim {
struct list_head cr_strhash; /* hash by cr_name */ struct list_head cr_strhash; /* hash by cr_name */
struct nfs4_client *cr_clp; /* pointer to associated clp */ struct nfs4_client *cr_clp; /* pointer to associated clp */
char cr_recdir[HEXDIR_LEN]; /* recover dir */ struct xdr_netobj cr_name; /* recovery dir name */
}; };
/* A reasonable value for REPLAY_ISIZE was estimated as follows: /* A reasonable value for REPLAY_ISIZE was estimated as follows:
...@@ -620,7 +620,7 @@ void nfs4_put_stid(struct nfs4_stid *s); ...@@ -620,7 +620,7 @@ void nfs4_put_stid(struct nfs4_stid *s);
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
extern void nfs4_release_reclaim(struct nfsd_net *); extern void nfs4_release_reclaim(struct nfsd_net *);
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct xdr_netobj name,
struct nfsd_net *nn); struct nfsd_net *nn);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid, extern __be32 nfs4_check_open_reclaim(clientid_t *clid,
struct nfsd4_compound_state *cstate, struct nfsd_net *nn); struct nfsd4_compound_state *cstate, struct nfsd_net *nn);
...@@ -635,9 +635,9 @@ extern void nfsd4_destroy_callback_queue(void); ...@@ -635,9 +635,9 @@ extern void nfsd4_destroy_callback_queue(void);
extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfsd4_shutdown_copy(struct nfs4_client *clp); extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
struct nfsd_net *nn); struct nfsd_net *nn);
extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
struct nfs4_file *find_file(struct knfsd_fh *fh); struct nfs4_file *find_file(struct knfsd_fh *fh);
void put_nfs4_file(struct nfs4_file *fi); void put_nfs4_file(struct nfs4_file *fi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment