diff options
-rw-r--r-- | fs/nfsd/nfs4recover.c | 93 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 18 | ||||
-rw-r--r-- | fs/nfsd/state.h | 2 |
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 | 106 | static int |
107 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | 107 | nfs4_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; |
133 | out: | 139 | out: |
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 | */ | ||
151 | static void | ||
152 | legacy_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 | |||
140 | static void | 171 | static void |
141 | nfsd4_create_clid_dir(struct nfs4_client *clp) | 172 | nfsd4_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: | |||
328 | out: | 369 | out: |
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 | ||
334 | static int | 375 | static int |
@@ -500,14 +541,22 @@ nfs4_recoverydir(void) | |||
500 | static int | 541 | static int |
501 | nfsd4_check_legacy_client(struct nfs4_client *clp) | 542 | nfsd4_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 | ||
995 | static char * | 1044 | static char * |
996 | nfsd4_cltrack_legacy_recdir(const char *recdir) | 1045 | nfsd4_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 | ||
1302 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | 1302 | static 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) */ |
1703 | out_new: | 1696 | out_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); | |||
482 | extern void nfsd4_destroy_callback_queue(void); | 481 | extern void nfsd4_destroy_callback_queue(void); |
483 | extern void nfsd4_shutdown_callback(struct nfs4_client *); | 482 | extern void nfsd4_shutdown_callback(struct nfs4_client *); |
484 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); | 483 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); |
485 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); | ||
486 | extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); | 484 | extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); |
487 | extern bool nfs4_has_reclaimed_state(const char *name); | 485 | extern bool nfs4_has_reclaimed_state(const char *name); |
488 | extern void release_session_client(struct nfsd4_session *); | 486 | extern void release_session_client(struct nfsd4_session *); |