diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-06-24 01:03:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:06:33 -0400 |
commit | a55370a3c0106106a975c5a09cee800611d0cf50 (patch) | |
tree | 408d5dc0ecf970c103ef091388e66da267adb2e2 /fs/nfsd/nfs4state.c | |
parent | 7dea9d280c96f90382ec5d5709433e66a0993ec9 (diff) |
[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.c | 80 |
1 files changed, 38 insertions, 42 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2a59d176e69a..0be0b37c84e9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -231,8 +231,8 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
231 | 231 | ||
232 | #define clientid_hashval(id) \ | 232 | #define clientid_hashval(id) \ |
233 | ((id) & CLIENT_HASH_MASK) | 233 | ((id) & CLIENT_HASH_MASK) |
234 | #define clientstr_hashval(name, namelen) \ | 234 | #define clientstr_hashval(name) \ |
235 | (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK) | 235 | (opaque_hashval((name), 8) & CLIENT_HASH_MASK) |
236 | /* | 236 | /* |
237 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | 237 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot |
238 | * used in reboot/reset lease grace period processing | 238 | * used in reboot/reset lease grace period processing |
@@ -366,11 +366,12 @@ expire_client(struct nfs4_client *clp) | |||
366 | } | 366 | } |
367 | 367 | ||
368 | static struct nfs4_client * | 368 | static struct nfs4_client * |
369 | create_client(struct xdr_netobj name) { | 369 | create_client(struct xdr_netobj name, char *recdir) { |
370 | struct nfs4_client *clp; | 370 | struct nfs4_client *clp; |
371 | 371 | ||
372 | if (!(clp = alloc_client(name))) | 372 | if (!(clp = alloc_client(name))) |
373 | goto out; | 373 | goto out; |
374 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
374 | atomic_set(&clp->cl_count, 1); | 375 | atomic_set(&clp->cl_count, 1); |
375 | atomic_set(&clp->cl_callback.cb_set, 0); | 376 | atomic_set(&clp->cl_callback.cb_set, 0); |
376 | clp->cl_callback.cb_parsed = 0; | 377 | clp->cl_callback.cb_parsed = 0; |
@@ -403,11 +404,9 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) { | |||
403 | get_group_info(target->cr_group_info); | 404 | get_group_info(target->cr_group_info); |
404 | } | 405 | } |
405 | 406 | ||
406 | static int | 407 | static inline int |
407 | cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) { | 408 | same_name(const char *n1, const char *n2) { |
408 | if (!n1 || !n2) | 409 | return 0 == memcmp(n1, n2, HEXDIR_LEN); |
409 | return 0; | ||
410 | return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len)); | ||
411 | } | 410 | } |
412 | 411 | ||
413 | static int | 412 | static int |
@@ -479,8 +478,7 @@ move_to_confirmed(struct nfs4_client *clp) | |||
479 | list_del_init(&clp->cl_strhash); | 478 | list_del_init(&clp->cl_strhash); |
480 | list_del_init(&clp->cl_idhash); | 479 | list_del_init(&clp->cl_idhash); |
481 | list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); | 480 | list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); |
482 | strhashval = clientstr_hashval(clp->cl_name.data, | 481 | strhashval = clientstr_hashval(clp->cl_recdir); |
483 | clp->cl_name.len); | ||
484 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 482 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); |
485 | renew_client(clp); | 483 | renew_client(clp); |
486 | } | 484 | } |
@@ -651,22 +649,27 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
651 | unsigned int strhashval; | 649 | unsigned int strhashval; |
652 | struct nfs4_client * conf, * unconf, * new, * clp; | 650 | struct nfs4_client * conf, * unconf, * new, * clp; |
653 | int status; | 651 | int status; |
652 | char dname[HEXDIR_LEN]; | ||
654 | 653 | ||
655 | status = nfserr_inval; | 654 | status = nfserr_inval; |
656 | if (!check_name(clname)) | 655 | if (!check_name(clname)) |
657 | goto out; | 656 | goto out; |
658 | 657 | ||
658 | status = nfs4_make_rec_clidname(dname, &clname); | ||
659 | if (status) | ||
660 | goto out; | ||
661 | |||
659 | /* | 662 | /* |
660 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | 663 | * XXX The Duplicate Request Cache (DRC) has been checked (??) |
661 | * We get here on a DRC miss. | 664 | * We get here on a DRC miss. |
662 | */ | 665 | */ |
663 | 666 | ||
664 | strhashval = clientstr_hashval(clname.data, clname.len); | 667 | strhashval = clientstr_hashval(dname); |
665 | 668 | ||
666 | conf = NULL; | 669 | conf = NULL; |
667 | nfs4_lock_state(); | 670 | nfs4_lock_state(); |
668 | list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) { | 671 | list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) { |
669 | if (!cmp_name(&clp->cl_name, &clname)) | 672 | if (!same_name(clp->cl_recdir, dname)) |
670 | continue; | 673 | continue; |
671 | /* | 674 | /* |
672 | * CASE 0: | 675 | * CASE 0: |
@@ -686,7 +689,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
686 | } | 689 | } |
687 | unconf = NULL; | 690 | unconf = NULL; |
688 | list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) { | 691 | list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) { |
689 | if (!cmp_name(&clp->cl_name, &clname)) | 692 | if (!same_name(clp->cl_recdir, dname)) |
690 | continue; | 693 | continue; |
691 | /* cl_name match from a previous SETCLIENTID operation */ | 694 | /* cl_name match from a previous SETCLIENTID operation */ |
692 | unconf = clp; | 695 | unconf = clp; |
@@ -700,7 +703,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
700 | */ | 703 | */ |
701 | if (unconf) | 704 | if (unconf) |
702 | expire_client(unconf); | 705 | expire_client(unconf); |
703 | if (!(new = create_client(clname))) | 706 | new = create_client(clname, dname); |
707 | if (new == NULL) | ||
704 | goto out; | 708 | goto out; |
705 | copy_verf(new, &clverifier); | 709 | copy_verf(new, &clverifier); |
706 | new->cl_addr = ip_addr; | 710 | new->cl_addr = ip_addr; |
@@ -728,7 +732,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
728 | cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) { | 732 | cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) { |
729 | expire_client(unconf); | 733 | expire_client(unconf); |
730 | } | 734 | } |
731 | if (!(new = create_client(clname))) | 735 | new = create_client(clname, dname); |
736 | if (new == NULL) | ||
732 | goto out; | 737 | goto out; |
733 | copy_verf(new,&conf->cl_verifier); | 738 | copy_verf(new,&conf->cl_verifier); |
734 | new->cl_addr = ip_addr; | 739 | new->cl_addr = ip_addr; |
@@ -746,7 +751,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
746 | * using input clverifier, clname, and callback info | 751 | * using input clverifier, clname, and callback info |
747 | * and generate a new cl_clientid and cl_confirm. | 752 | * and generate a new cl_clientid and cl_confirm. |
748 | */ | 753 | */ |
749 | if (!(new = create_client(clname))) | 754 | new = create_client(clname, dname); |
755 | if (new == NULL) | ||
750 | goto out; | 756 | goto out; |
751 | copy_verf(new,&clverifier); | 757 | copy_verf(new,&clverifier); |
752 | new->cl_addr = ip_addr; | 758 | new->cl_addr = ip_addr; |
@@ -772,7 +778,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
772 | * new cl_verifier and a new cl_confirm | 778 | * new cl_verifier and a new cl_confirm |
773 | */ | 779 | */ |
774 | expire_client(unconf); | 780 | expire_client(unconf); |
775 | if (!(new = create_client(clname))) | 781 | new = create_client(clname, dname); |
782 | if (new == NULL) | ||
776 | goto out; | 783 | goto out; |
777 | copy_verf(new,&clverifier); | 784 | copy_verf(new,&clverifier); |
778 | new->cl_addr = ip_addr; | 785 | new->cl_addr = ip_addr; |
@@ -856,7 +863,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi | |||
856 | if ((conf && unconf) && | 863 | if ((conf && unconf) && |
857 | (cmp_verf(&unconf->cl_confirm, &confirm)) && | 864 | (cmp_verf(&unconf->cl_confirm, &confirm)) && |
858 | (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && | 865 | (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && |
859 | (cmp_name(&conf->cl_name,&unconf->cl_name)) && | 866 | (same_name(conf->cl_recdir,unconf->cl_recdir)) && |
860 | (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { | 867 | (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { |
861 | if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) | 868 | if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) |
862 | status = nfserr_clid_inuse; | 869 | status = nfserr_clid_inuse; |
@@ -876,7 +883,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi | |||
876 | if ((conf && !unconf) || | 883 | if ((conf && !unconf) || |
877 | ((conf && unconf) && | 884 | ((conf && unconf) && |
878 | (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || | 885 | (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || |
879 | !cmp_name(&conf->cl_name, &unconf->cl_name)))) { | 886 | !same_name(conf->cl_recdir, unconf->cl_recdir)))) { |
880 | if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) { | 887 | if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) { |
881 | status = nfserr_clid_inuse; | 888 | status = nfserr_clid_inuse; |
882 | } else { | 889 | } else { |
@@ -3074,39 +3081,28 @@ out: | |||
3074 | } | 3081 | } |
3075 | 3082 | ||
3076 | static inline struct nfs4_client_reclaim * | 3083 | static inline struct nfs4_client_reclaim * |
3077 | alloc_reclaim(int namelen) | 3084 | alloc_reclaim(void) |
3078 | { | 3085 | { |
3079 | struct nfs4_client_reclaim *crp = NULL; | 3086 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); |
3080 | |||
3081 | crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); | ||
3082 | if (!crp) | ||
3083 | return NULL; | ||
3084 | crp->cr_name.data = kmalloc(namelen, GFP_KERNEL); | ||
3085 | if (!crp->cr_name.data) { | ||
3086 | kfree(crp); | ||
3087 | return NULL; | ||
3088 | } | ||
3089 | return crp; | ||
3090 | } | 3087 | } |
3091 | 3088 | ||
3092 | /* | 3089 | /* |
3093 | * failure => all reset bets are off, nfserr_no_grace... | 3090 | * failure => all reset bets are off, nfserr_no_grace... |
3094 | */ | 3091 | */ |
3095 | static int | 3092 | static int |
3096 | nfs4_client_to_reclaim(char *name, int namlen) | 3093 | nfs4_client_to_reclaim(char *name) |
3097 | { | 3094 | { |
3098 | unsigned int strhashval; | 3095 | unsigned int strhashval; |
3099 | struct nfs4_client_reclaim *crp = NULL; | 3096 | struct nfs4_client_reclaim *crp = NULL; |
3100 | 3097 | ||
3101 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name); | 3098 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); |
3102 | crp = alloc_reclaim(namlen); | 3099 | crp = alloc_reclaim(); |
3103 | if (!crp) | 3100 | if (!crp) |
3104 | return 0; | 3101 | return 0; |
3105 | strhashval = clientstr_hashval(name, namlen); | 3102 | strhashval = clientstr_hashval(name); |
3106 | INIT_LIST_HEAD(&crp->cr_strhash); | 3103 | INIT_LIST_HEAD(&crp->cr_strhash); |
3107 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); | 3104 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); |
3108 | memcpy(crp->cr_name.data, name, namlen); | 3105 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); |
3109 | crp->cr_name.len = namlen; | ||
3110 | reclaim_str_hashtbl_size++; | 3106 | reclaim_str_hashtbl_size++; |
3111 | return 1; | 3107 | return 1; |
3112 | } | 3108 | } |
@@ -3122,7 +3118,6 @@ nfs4_release_reclaim(void) | |||
3122 | crp = list_entry(reclaim_str_hashtbl[i].next, | 3118 | crp = list_entry(reclaim_str_hashtbl[i].next, |
3123 | struct nfs4_client_reclaim, cr_strhash); | 3119 | struct nfs4_client_reclaim, cr_strhash); |
3124 | list_del(&crp->cr_strhash); | 3120 | list_del(&crp->cr_strhash); |
3125 | kfree(crp->cr_name.data); | ||
3126 | kfree(crp); | 3121 | kfree(crp); |
3127 | reclaim_str_hashtbl_size--; | 3122 | reclaim_str_hashtbl_size--; |
3128 | } | 3123 | } |
@@ -3145,13 +3140,14 @@ nfs4_find_reclaim_client(clientid_t *clid) | |||
3145 | if (clp == NULL) | 3140 | if (clp == NULL) |
3146 | return NULL; | 3141 | return NULL; |
3147 | 3142 | ||
3148 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n", | 3143 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", |
3149 | clp->cl_name.len, clp->cl_name.data); | 3144 | clp->cl_name.len, clp->cl_name.data, |
3145 | clp->cl_recdir); | ||
3150 | 3146 | ||
3151 | /* find clp->cl_name in reclaim_str_hashtbl */ | 3147 | /* find clp->cl_name in reclaim_str_hashtbl */ |
3152 | strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len); | 3148 | strhashval = clientstr_hashval(clp->cl_recdir); |
3153 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { | 3149 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { |
3154 | if (cmp_name(&crp->cr_name, &clp->cl_name)) { | 3150 | if (same_name(crp->cr_recdir, clp->cl_recdir)) { |
3155 | return crp; | 3151 | return crp; |
3156 | } | 3152 | } |
3157 | } | 3153 | } |