summaryrefslogtreecommitdiff
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@cse.unsw.edu.au>2005-06-24 05:03:52 (GMT)
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 07:06:33 (GMT)
commita55370a3c0106106a975c5a09cee800611d0cf50 (patch)
tree408d5dc0ecf970c103ef091388e66da267adb2e2 /fs/nfsd/nfs4state.c
parent7dea9d280c96f90382ec5d5709433e66a0993ec9 (diff)
downloadlinux-a55370a3c0106106a975c5a09cee800611d0cf50.tar.xz
[PATCH] knfsd: nfsd4: reboot hash
For the purposes of reboot recovery we keep a directory with subdirectories each having a name that is the ascii hex representation of the md5 sum of a client identifier for an active client. This adds the code to calculate that name. We also use it for the purposes of comparing clients, so if someone ever manages to find two client names that are md5 collisions, then we'll return clid_inuse to the second. Signed-off-by: Andy Adamson <andros@citi.umich.edu> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c80
1 files changed, 38 insertions, 42 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2a59d17..0be0b37c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -231,8 +231,8 @@ unhash_delegation(struct nfs4_delegation *dp)
#define clientid_hashval(id) \
((id) & CLIENT_HASH_MASK)
-#define clientstr_hashval(name, namelen) \
- (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK)
+#define clientstr_hashval(name) \
+ (opaque_hashval((name), 8) & CLIENT_HASH_MASK)
/*
* reclaim_str_hashtbl[] holds known client info from previous reset/reboot
* used in reboot/reset lease grace period processing
@@ -366,11 +366,12 @@ expire_client(struct nfs4_client *clp)
}
static struct nfs4_client *
-create_client(struct xdr_netobj name) {
+create_client(struct xdr_netobj name, char *recdir) {
struct nfs4_client *clp;
if (!(clp = alloc_client(name)))
goto out;
+ memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_count, 1);
atomic_set(&clp->cl_callback.cb_set, 0);
clp->cl_callback.cb_parsed = 0;
@@ -403,11 +404,9 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) {
get_group_info(target->cr_group_info);
}
-static int
-cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) {
- if (!n1 || !n2)
- return 0;
- return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len));
+static inline int
+same_name(const char *n1, const char *n2) {
+ return 0 == memcmp(n1, n2, HEXDIR_LEN);
}
static int
@@ -479,8 +478,7 @@ move_to_confirmed(struct nfs4_client *clp)
list_del_init(&clp->cl_strhash);
list_del_init(&clp->cl_idhash);
list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
- strhashval = clientstr_hashval(clp->cl_name.data,
- clp->cl_name.len);
+ strhashval = clientstr_hashval(clp->cl_recdir);
list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
renew_client(clp);
}
@@ -651,22 +649,27 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
unsigned int strhashval;
struct nfs4_client * conf, * unconf, * new, * clp;
int status;
+ char dname[HEXDIR_LEN];
status = nfserr_inval;
if (!check_name(clname))
goto out;
+ status = nfs4_make_rec_clidname(dname, &clname);
+ if (status)
+ goto out;
+
/*
* XXX The Duplicate Request Cache (DRC) has been checked (??)
* We get here on a DRC miss.
*/
- strhashval = clientstr_hashval(clname.data, clname.len);
+ strhashval = clientstr_hashval(dname);
conf = NULL;
nfs4_lock_state();
list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) {
- if (!cmp_name(&clp->cl_name, &clname))
+ if (!same_name(clp->cl_recdir, dname))
continue;
/*
* CASE 0:
@@ -686,7 +689,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
}
unconf = NULL;
list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) {
- if (!cmp_name(&clp->cl_name, &clname))
+ if (!same_name(clp->cl_recdir, dname))
continue;
/* cl_name match from a previous SETCLIENTID operation */
unconf = clp;
@@ -700,7 +703,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
*/
if (unconf)
expire_client(unconf);
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new, &clverifier);
new->cl_addr = ip_addr;
@@ -728,7 +732,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {
expire_client(unconf);
}
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new,&conf->cl_verifier);
new->cl_addr = ip_addr;
@@ -746,7 +751,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
* using input clverifier, clname, and callback info
* and generate a new cl_clientid and cl_confirm.
*/
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new,&clverifier);
new->cl_addr = ip_addr;
@@ -772,7 +778,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
* new cl_verifier and a new cl_confirm
*/
expire_client(unconf);
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new,&clverifier);
new->cl_addr = ip_addr;
@@ -856,7 +863,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
if ((conf && unconf) &&
(cmp_verf(&unconf->cl_confirm, &confirm)) &&
(cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
- (cmp_name(&conf->cl_name,&unconf->cl_name)) &&
+ (same_name(conf->cl_recdir,unconf->cl_recdir)) &&
(!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
@@ -876,7 +883,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
if ((conf && !unconf) ||
((conf && unconf) &&
(!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
- !cmp_name(&conf->cl_name, &unconf->cl_name)))) {
+ !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
status = nfserr_clid_inuse;
} else {
@@ -3074,39 +3081,28 @@ out:
}
static inline struct nfs4_client_reclaim *
-alloc_reclaim(int namelen)
+alloc_reclaim(void)
{
- struct nfs4_client_reclaim *crp = NULL;
-
- crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
- if (!crp)
- return NULL;
- crp->cr_name.data = kmalloc(namelen, GFP_KERNEL);
- if (!crp->cr_name.data) {
- kfree(crp);
- return NULL;
- }
- return crp;
+ return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
}
/*
* failure => all reset bets are off, nfserr_no_grace...
*/
static int
-nfs4_client_to_reclaim(char *name, int namlen)
+nfs4_client_to_reclaim(char *name)
{
unsigned int strhashval;
struct nfs4_client_reclaim *crp = NULL;
- dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name);
- crp = alloc_reclaim(namlen);
+ dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
+ crp = alloc_reclaim();
if (!crp)
return 0;
- strhashval = clientstr_hashval(name, namlen);
+ strhashval = clientstr_hashval(name);
INIT_LIST_HEAD(&crp->cr_strhash);
list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
- memcpy(crp->cr_name.data, name, namlen);
- crp->cr_name.len = namlen;
+ memcpy(crp->cr_recdir, name, HEXDIR_LEN);
reclaim_str_hashtbl_size++;
return 1;
}
@@ -3122,7 +3118,6 @@ nfs4_release_reclaim(void)
crp = list_entry(reclaim_str_hashtbl[i].next,
struct nfs4_client_reclaim, cr_strhash);
list_del(&crp->cr_strhash);
- kfree(crp->cr_name.data);
kfree(crp);
reclaim_str_hashtbl_size--;
}
@@ -3145,13 +3140,14 @@ nfs4_find_reclaim_client(clientid_t *clid)
if (clp == NULL)
return NULL;
- dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n",
- clp->cl_name.len, clp->cl_name.data);
+ dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
+ clp->cl_name.len, clp->cl_name.data,
+ clp->cl_recdir);
/* find clp->cl_name in reclaim_str_hashtbl */
- strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len);
+ strhashval = clientstr_hashval(clp->cl_recdir);
list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
- if (cmp_name(&crp->cr_name, &clp->cl_name)) {
+ if (same_name(crp->cr_recdir, clp->cl_recdir)) {
return crp;
}
}