diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/Makefile | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 97 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 80 |
3 files changed, 136 insertions, 43 deletions
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 9f043f44c92f..ce341dc76d5e 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile | |||
@@ -10,5 +10,5 @@ nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o | |||
10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o | 10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o |
11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o | 11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o |
12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ | 12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ |
13 | nfs4acl.o nfs4callback.o | 13 | nfs4acl.o nfs4callback.o nfs4recover.o |
14 | nfsd-objs := $(nfsd-y) | 14 | nfsd-objs := $(nfsd-y) |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c new file mode 100644 index 000000000000..841a305d7948 --- /dev/null +++ b/fs/nfsd/nfs4recover.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfs4recover.c | ||
3 | * | ||
4 | * Copyright (c) 2004 The Regents of the University of Michigan. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Andy Adamson <andros@citi.umich.edu> | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * 3. Neither the name of the University nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
25 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | |||
37 | #include <linux/sunrpc/svc.h> | ||
38 | #include <linux/nfsd/nfsd.h> | ||
39 | #include <linux/nfs4.h> | ||
40 | #include <linux/nfsd/state.h> | ||
41 | #include <linux/nfsd/xdr4.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/scatterlist.h> | ||
44 | #include <linux/crypto.h> | ||
45 | |||
46 | |||
47 | #define NFSDDBG_FACILITY NFSDDBG_PROC | ||
48 | |||
49 | static void | ||
50 | md5_to_hex(char *out, char *md5) | ||
51 | { | ||
52 | int i; | ||
53 | |||
54 | for (i=0; i<16; i++) { | ||
55 | unsigned char c = md5[i]; | ||
56 | |||
57 | *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); | ||
58 | *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); | ||
59 | } | ||
60 | *out = '\0'; | ||
61 | } | ||
62 | |||
63 | int | ||
64 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | ||
65 | { | ||
66 | struct xdr_netobj cksum; | ||
67 | struct crypto_tfm *tfm; | ||
68 | struct scatterlist sg[1]; | ||
69 | int status = nfserr_resource; | ||
70 | |||
71 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", | ||
72 | clname->len, clname->data); | ||
73 | tfm = crypto_alloc_tfm("md5", 0); | ||
74 | if (tfm == NULL) | ||
75 | goto out; | ||
76 | cksum.len = crypto_tfm_alg_digestsize(tfm); | ||
77 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); | ||
78 | if (cksum.data == NULL) | ||
79 | goto out; | ||
80 | crypto_digest_init(tfm); | ||
81 | |||
82 | sg[0].page = virt_to_page(clname->data); | ||
83 | sg[0].offset = offset_in_page(clname->data); | ||
84 | sg[0].length = clname->len; | ||
85 | |||
86 | crypto_digest_update(tfm, sg, 1); | ||
87 | crypto_digest_final(tfm, cksum.data); | ||
88 | |||
89 | md5_to_hex(dname, cksum.data); | ||
90 | |||
91 | kfree(cksum.data); | ||
92 | status = nfs_ok; | ||
93 | out: | ||
94 | if (tfm) | ||
95 | crypto_free_tfm(tfm); | ||
96 | return status; | ||
97 | } | ||
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 | } |