aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/Makefile2
-rw-r--r--fs/nfsd/nfs4recover.c97
-rw-r--r--fs/nfsd/nfs4state.c80
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
10nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o 10nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
11nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o 11nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
12nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ 12nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
13 nfs4acl.o nfs4callback.o 13 nfs4acl.o nfs4callback.o nfs4recover.o
14nfsd-objs := $(nfsd-y) 14nfsd-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
49static void
50md5_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
63int
64nfs4_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;
93out:
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
368static struct nfs4_client * 368static struct nfs4_client *
369create_client(struct xdr_netobj name) { 369create_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
406static int 407static inline int
407cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) { 408same_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
413static int 412static 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
3076static inline struct nfs4_client_reclaim * 3083static inline struct nfs4_client_reclaim *
3077alloc_reclaim(int namelen) 3084alloc_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 */
3095static int 3092static int
3096nfs4_client_to_reclaim(char *name, int namlen) 3093nfs4_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 }