aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-11-12 15:00:57 -0500
committerJ. Bruce Fields <bfields@redhat.com>2012-11-12 18:55:11 -0500
commit2216d449a97927cc105912e337d169cd4d4db548 (patch)
tree66e350123f674f0fbcdd558421d4bd29eea4e69c /fs/nfsd
parentac55fdc408039b425a2fa3cbcaed7444e5339f9a (diff)
nfsd: get rid of cl_recdir field
Remove the cl_recdir field from the nfs4_client struct. Instead, just compute it on the fly when and if it's needed, which is now only when the legacy client tracking code is in effect. The error handling in the legacy client tracker is also changed to handle the case where md5 is unavailable. In that case, we'll warn the admin with a KERN_ERR message and disable the client tracking. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-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 *);