aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4recover.c93
-rw-r--r--fs/nfsd/nfs4state.c18
-rw-r--r--fs/nfsd/state.h2
3 files changed, 77 insertions, 36 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 3048c012d4bc..80e77cc14250 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -103,33 +103,39 @@ md5_to_hex(char *out, char *md5)
103 *out = '\0'; 103 *out = '\0';
104} 104}
105 105
106__be32 106static int
107nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) 107nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname)
108{ 108{
109 struct xdr_netobj cksum; 109 struct xdr_netobj cksum;
110 struct hash_desc desc; 110 struct hash_desc desc;
111 struct scatterlist sg; 111 struct scatterlist sg;
112 __be32 status = nfserr_jukebox; 112 int status;
113 113
114 dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", 114 dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
115 clname->len, clname->data); 115 clname->len, clname->data);
116 desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; 116 desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
117 desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); 117 desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
118 if (IS_ERR(desc.tfm)) 118 if (IS_ERR(desc.tfm)) {
119 status = PTR_ERR(desc.tfm);
119 goto out_no_tfm; 120 goto out_no_tfm;
121 }
122
120 cksum.len = crypto_hash_digestsize(desc.tfm); 123 cksum.len = crypto_hash_digestsize(desc.tfm);
121 cksum.data = kmalloc(cksum.len, GFP_KERNEL); 124 cksum.data = kmalloc(cksum.len, GFP_KERNEL);
122 if (cksum.data == NULL) 125 if (cksum.data == NULL) {
126 status = -ENOMEM;
123 goto out; 127 goto out;
128 }
124 129
125 sg_init_one(&sg, clname->data, clname->len); 130 sg_init_one(&sg, clname->data, clname->len);
126 131
127 if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) 132 status = crypto_hash_digest(&desc, &sg, sg.length, cksum.data);
133 if (status)
128 goto out; 134 goto out;
129 135
130 md5_to_hex(dname, cksum.data); 136 md5_to_hex(dname, cksum.data);
131 137
132 status = nfs_ok; 138 status = 0;
133out: 139out:
134 kfree(cksum.data); 140 kfree(cksum.data);
135 crypto_free_hash(desc.tfm); 141 crypto_free_hash(desc.tfm);
@@ -137,11 +143,36 @@ out_no_tfm:
137 return status; 143 return status;
138} 144}
139 145
146/*
147 * If we had an error generating the recdir name for the legacy tracker
148 * then warn the admin. If the error doesn't appear to be transient,
149 * then disable recovery tracking.
150 */
151static void
152legacy_recdir_name_error(int error)
153{
154 printk(KERN_ERR "NFSD: unable to generate recoverydir "
155 "name (%d).\n", error);
156
157 /*
158 * if the algorithm just doesn't exist, then disable the recovery
159 * tracker altogether. The crypto libs will generally return this if
160 * FIPS is enabled as well.
161 */
162 if (error == -ENOENT) {
163 printk(KERN_ERR "NFSD: disabling legacy clientid tracking. "
164 "Reboot recovery will not function correctly!\n");
165
166 /* the argument is ignored by the legacy exit function */
167 nfsd4_client_tracking_exit(NULL);
168 }
169}
170
140static void 171static void
141nfsd4_create_clid_dir(struct nfs4_client *clp) 172nfsd4_create_clid_dir(struct nfs4_client *clp)
142{ 173{
143 const struct cred *original_cred; 174 const struct cred *original_cred;
144 char *dname = clp->cl_recdir; 175 char dname[HEXDIR_LEN];
145 struct dentry *dir, *dentry; 176 struct dentry *dir, *dentry;
146 struct nfs4_client_reclaim *crp; 177 struct nfs4_client_reclaim *crp;
147 int status; 178 int status;
@@ -152,6 +183,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
152 return; 183 return;
153 if (!rec_file) 184 if (!rec_file)
154 return; 185 return;
186
187 status = nfs4_make_rec_clidname(dname, &clp->cl_name);
188 if (status)
189 return legacy_recdir_name_error(status);
190
155 status = nfs4_save_creds(&original_cred); 191 status = nfs4_save_creds(&original_cred);
156 if (status < 0) 192 if (status < 0)
157 return; 193 return;
@@ -186,7 +222,7 @@ out_unlock:
186 mutex_unlock(&dir->d_inode->i_mutex); 222 mutex_unlock(&dir->d_inode->i_mutex);
187 if (status == 0) { 223 if (status == 0) {
188 if (in_grace) { 224 if (in_grace) {
189 crp = nfs4_client_to_reclaim(clp->cl_recdir); 225 crp = nfs4_client_to_reclaim(dname);
190 if (crp) 226 if (crp)
191 crp->cr_clp = clp; 227 crp->cr_clp = clp;
192 } 228 }
@@ -298,11 +334,16 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
298{ 334{
299 const struct cred *original_cred; 335 const struct cred *original_cred;
300 struct nfs4_client_reclaim *crp; 336 struct nfs4_client_reclaim *crp;
337 char dname[HEXDIR_LEN];
301 int status; 338 int status;
302 339
303 if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 340 if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
304 return; 341 return;
305 342
343 status = nfs4_make_rec_clidname(dname, &clp->cl_name);
344 if (status)
345 return legacy_recdir_name_error(status);
346
306 status = mnt_want_write_file(rec_file); 347 status = mnt_want_write_file(rec_file);
307 if (status) 348 if (status)
308 goto out; 349 goto out;
@@ -312,13 +353,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
312 if (status < 0) 353 if (status < 0)
313 goto out_drop_write; 354 goto out_drop_write;
314 355
315 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 356 status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1);
316 nfs4_reset_creds(original_cred); 357 nfs4_reset_creds(original_cred);
317 if (status == 0) { 358 if (status == 0) {
318 vfs_fsync(rec_file, 0); 359 vfs_fsync(rec_file, 0);
319 if (in_grace) { 360 if (in_grace) {
320 /* remove reclaim record */ 361 /* remove reclaim record */
321 crp = nfsd4_find_reclaim_client(clp->cl_recdir); 362 crp = nfsd4_find_reclaim_client(dname);
322 if (crp) 363 if (crp)
323 nfs4_remove_reclaim_record(crp); 364 nfs4_remove_reclaim_record(crp);
324 } 365 }
@@ -328,7 +369,7 @@ out_drop_write:
328out: 369out:
329 if (status) 370 if (status)
330 printk("NFSD: Failed to remove expired client state directory" 371 printk("NFSD: Failed to remove expired client state directory"
331 " %.*s\n", HEXDIR_LEN, clp->cl_recdir); 372 " %.*s\n", HEXDIR_LEN, dname);
332} 373}
333 374
334static int 375static int
@@ -500,14 +541,22 @@ nfs4_recoverydir(void)
500static int 541static int
501nfsd4_check_legacy_client(struct nfs4_client *clp) 542nfsd4_check_legacy_client(struct nfs4_client *clp)
502{ 543{
544 int status;
545 char dname[HEXDIR_LEN];
503 struct nfs4_client_reclaim *crp; 546 struct nfs4_client_reclaim *crp;
504 547
505 /* did we already find that this client is stable? */ 548 /* did we already find that this client is stable? */
506 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 549 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
507 return 0; 550 return 0;
508 551
552 status = nfs4_make_rec_clidname(dname, &clp->cl_name);
553 if (status) {
554 legacy_recdir_name_error(status);
555 return status;
556 }
557
509 /* look for it in the reclaim hashtable otherwise */ 558 /* look for it in the reclaim hashtable otherwise */
510 crp = nfsd4_find_reclaim_client(clp->cl_recdir); 559 crp = nfsd4_find_reclaim_client(dname);
511 if (crp) { 560 if (crp) {
512 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 561 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
513 crp->cr_clp = clp; 562 crp->cr_clp = clp;
@@ -993,7 +1042,7 @@ nfsd4_cltrack_legacy_topdir(void)
993} 1042}
994 1043
995static char * 1044static char *
996nfsd4_cltrack_legacy_recdir(const char *recdir) 1045nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name)
997{ 1046{
998 int copied; 1047 int copied;
999 size_t len; 1048 size_t len;
@@ -1010,10 +1059,16 @@ nfsd4_cltrack_legacy_recdir(const char *recdir)
1010 if (!result) 1059 if (!result)
1011 return result; 1060 return result;
1012 1061
1013 copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/%s", 1062 copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/",
1014 nfs4_recoverydir(), recdir); 1063 nfs4_recoverydir());
1015 if (copied >= len) { 1064 if (copied > (len - HEXDIR_LEN)) {
1016 /* just return nothing if output was truncated */ 1065 /* just return nothing if output will be truncated */
1066 kfree(result);
1067 return NULL;
1068 }
1069
1070 copied = nfs4_make_rec_clidname(result + copied, name);
1071 if (copied) {
1017 kfree(result); 1072 kfree(result);
1018 return NULL; 1073 return NULL;
1019 } 1074 }
@@ -1126,7 +1181,7 @@ nfsd4_umh_cltrack_check(struct nfs4_client *clp)
1126 dprintk("%s: can't allocate memory for upcall!\n", __func__); 1181 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1127 return -ENOMEM; 1182 return -ENOMEM;
1128 } 1183 }
1129 legacy = nfsd4_cltrack_legacy_recdir(clp->cl_recdir); 1184 legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name);
1130 ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy); 1185 ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy);
1131 kfree(legacy); 1186 kfree(legacy);
1132 kfree(hexid); 1187 kfree(hexid);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 99998a1eb426..37b19f7948ed 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1299,7 +1299,7 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t
1299 return NULL; 1299 return NULL;
1300} 1300}
1301 1301
1302static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, 1302static struct nfs4_client *create_client(struct xdr_netobj name,
1303 struct svc_rqst *rqstp, nfs4_verifier *verf) 1303 struct svc_rqst *rqstp, nfs4_verifier *verf)
1304{ 1304{
1305 struct nfs4_client *clp; 1305 struct nfs4_client *clp;
@@ -1319,7 +1319,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
1319 return NULL; 1319 return NULL;
1320 } 1320 }
1321 idr_init(&clp->cl_stateids); 1321 idr_init(&clp->cl_stateids);
1322 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
1323 atomic_set(&clp->cl_refcount, 0); 1322 atomic_set(&clp->cl_refcount, 0);
1324 clp->cl_cb_state = NFSD4_CB_UNKNOWN; 1323 clp->cl_cb_state = NFSD4_CB_UNKNOWN;
1325 INIT_LIST_HEAD(&clp->cl_idhash); 1324 INIT_LIST_HEAD(&clp->cl_idhash);
@@ -1616,7 +1615,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
1616{ 1615{
1617 struct nfs4_client *unconf, *conf, *new; 1616 struct nfs4_client *unconf, *conf, *new;
1618 __be32 status; 1617 __be32 status;
1619 char dname[HEXDIR_LEN];
1620 char addr_str[INET6_ADDRSTRLEN]; 1618 char addr_str[INET6_ADDRSTRLEN];
1621 nfs4_verifier verf = exid->verifier; 1619 nfs4_verifier verf = exid->verifier;
1622 struct sockaddr *sa = svc_addr(rqstp); 1620 struct sockaddr *sa = svc_addr(rqstp);
@@ -1643,11 +1641,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
1643 return nfserr_serverfault; /* no excuse :-/ */ 1641 return nfserr_serverfault; /* no excuse :-/ */
1644 } 1642 }
1645 1643
1646 status = nfs4_make_rec_clidname(dname, &exid->clname);
1647
1648 if (status)
1649 return status;
1650
1651 /* Cases below refer to rfc 5661 section 18.35.4: */ 1644 /* Cases below refer to rfc 5661 section 18.35.4: */
1652 nfs4_lock_state(); 1645 nfs4_lock_state();
1653 conf = find_confirmed_client_by_name(&exid->clname); 1646 conf = find_confirmed_client_by_name(&exid->clname);
@@ -1701,7 +1694,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
1701 1694
1702 /* case 1 (normal case) */ 1695 /* case 1 (normal case) */
1703out_new: 1696out_new:
1704 new = create_client(exid->clname, dname, rqstp, &verf); 1697 new = create_client(exid->clname, rqstp, &verf);
1705 if (new == NULL) { 1698 if (new == NULL) {
1706 status = nfserr_jukebox; 1699 status = nfserr_jukebox;
1707 goto out; 1700 goto out;
@@ -2236,12 +2229,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2236 nfs4_verifier clverifier = setclid->se_verf; 2229 nfs4_verifier clverifier = setclid->se_verf;
2237 struct nfs4_client *conf, *unconf, *new; 2230 struct nfs4_client *conf, *unconf, *new;
2238 __be32 status; 2231 __be32 status;
2239 char dname[HEXDIR_LEN];
2240 2232
2241 status = nfs4_make_rec_clidname(dname, &clname);
2242 if (status)
2243 return status;
2244
2245 /* Cases below refer to rfc 3530 section 14.2.33: */ 2233 /* Cases below refer to rfc 3530 section 14.2.33: */
2246 nfs4_lock_state(); 2234 nfs4_lock_state();
2247 conf = find_confirmed_client_by_name(&clname); 2235 conf = find_confirmed_client_by_name(&clname);
@@ -2263,7 +2251,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2263 if (unconf) 2251 if (unconf)
2264 expire_client(unconf); 2252 expire_client(unconf);
2265 status = nfserr_jukebox; 2253 status = nfserr_jukebox;
2266 new = create_client(clname, dname, rqstp, &clverifier); 2254 new = create_client(clname, rqstp, &clverifier);
2267 if (new == NULL) 2255 if (new == NULL)
2268 goto out; 2256 goto out;
2269 if (conf && same_verf(&conf->cl_verifier, &clverifier)) 2257 if (conf && same_verf(&conf->cl_verifier, &clverifier))
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 6c342bd806e5..029217ad2cb0 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -238,7 +238,6 @@ struct nfs4_client {
238 struct list_head cl_delegations; 238 struct list_head cl_delegations;
239 struct list_head cl_lru; /* tail queue */ 239 struct list_head cl_lru; /* tail queue */
240 struct xdr_netobj cl_name; /* id generated by client */ 240 struct xdr_netobj cl_name; /* id generated by client */
241 char cl_recdir[HEXDIR_LEN]; /* recovery dir */
242 nfs4_verifier cl_verifier; /* generated by client */ 241 nfs4_verifier cl_verifier; /* generated by client */
243 time_t cl_time; /* time of last lease renewal */ 242 time_t cl_time; /* time of last lease renewal */
244 struct sockaddr_storage cl_addr; /* client ipaddress */ 243 struct sockaddr_storage cl_addr; /* client ipaddress */
@@ -482,7 +481,6 @@ extern int nfsd4_create_callback_queue(void);
482extern void nfsd4_destroy_callback_queue(void); 481extern void nfsd4_destroy_callback_queue(void);
483extern void nfsd4_shutdown_callback(struct nfs4_client *); 482extern void nfsd4_shutdown_callback(struct nfs4_client *);
484extern void nfs4_put_delegation(struct nfs4_delegation *dp); 483extern void nfs4_put_delegation(struct nfs4_delegation *dp);
485extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
486extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); 484extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name);
487extern bool nfs4_has_reclaimed_state(const char *name); 485extern bool nfs4_has_reclaimed_state(const char *name);
488extern void release_session_client(struct nfsd4_session *); 486extern void release_session_client(struct nfsd4_session *);