Commit de8d4f5d758786a2cbcfa54a6a85ce747e5637e3
Exists in
master
and in
7 other branches
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: SUNRPC: Fix the NFSv4 and RPCSEC_GSS Kconfig dependencies statfs() gives ESTALE error NFS: Fix a typo in nfs_sockaddr_match_ipaddr6 sunrpc: increase MAX_HASHTABLE_BITS to 14 gss:spkm3 miss returning error to caller when import security context gss:krb5 miss returning error to caller when import security context Remove incorrect do_vfs_lock message SUNRPC: cleanup state-machine ordering SUNRPC: Fix a race in rpc_info_open SUNRPC: Fix race corrupting rpc upcall Fix null dereference in call_allocate
Showing 12 changed files Side-by-side Diff
fs/nfs/Kconfig
fs/nfs/client.c
... | ... | @@ -275,7 +275,7 @@ |
275 | 275 | sin1->sin6_scope_id != sin2->sin6_scope_id) |
276 | 276 | return 0; |
277 | 277 | |
278 | - return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr); | |
278 | + return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr); | |
279 | 279 | } |
280 | 280 | #else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ |
281 | 281 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, |
fs/nfs/file.c
fs/nfs/super.c
... | ... | @@ -431,7 +431,15 @@ |
431 | 431 | goto out_err; |
432 | 432 | |
433 | 433 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
434 | + if (unlikely(error == -ESTALE)) { | |
435 | + struct dentry *pd_dentry; | |
434 | 436 | |
437 | + pd_dentry = dget_parent(dentry); | |
438 | + if (pd_dentry != NULL) { | |
439 | + nfs_zap_caches(pd_dentry->d_inode); | |
440 | + dput(pd_dentry); | |
441 | + } | |
442 | + } | |
435 | 443 | nfs_free_fattr(res.fattr); |
436 | 444 | if (error < 0) |
437 | 445 | goto out_err; |
fs/nfsd/Kconfig
include/linux/sunrpc/clnt.h
... | ... | @@ -30,7 +30,7 @@ |
30 | 30 | * The high-level client handle |
31 | 31 | */ |
32 | 32 | struct rpc_clnt { |
33 | - struct kref cl_kref; /* Number of references */ | |
33 | + atomic_t cl_count; /* Number of references */ | |
34 | 34 | struct list_head cl_clients; /* Global list of clients */ |
35 | 35 | struct list_head cl_tasks; /* List of tasks */ |
36 | 36 | spinlock_t cl_lock; /* spinlock */ |
net/sunrpc/auth.c
... | ... | @@ -38,7 +38,7 @@ |
38 | 38 | static LIST_HEAD(cred_unused); |
39 | 39 | static unsigned long number_cred_unused; |
40 | 40 | |
41 | -#define MAX_HASHTABLE_BITS (10) | |
41 | +#define MAX_HASHTABLE_BITS (14) | |
42 | 42 | static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) |
43 | 43 | { |
44 | 44 | unsigned long num; |
net/sunrpc/auth_gss/auth_gss.c
... | ... | @@ -745,17 +745,18 @@ |
745 | 745 | struct rpc_inode *rpci = RPC_I(inode); |
746 | 746 | struct gss_upcall_msg *gss_msg; |
747 | 747 | |
748 | +restart: | |
748 | 749 | spin_lock(&inode->i_lock); |
749 | - while (!list_empty(&rpci->in_downcall)) { | |
750 | + list_for_each_entry(gss_msg, &rpci->in_downcall, list) { | |
750 | 751 | |
751 | - gss_msg = list_entry(rpci->in_downcall.next, | |
752 | - struct gss_upcall_msg, list); | |
752 | + if (!list_empty(&gss_msg->msg.list)) | |
753 | + continue; | |
753 | 754 | gss_msg->msg.errno = -EPIPE; |
754 | 755 | atomic_inc(&gss_msg->count); |
755 | 756 | __gss_unhash_msg(gss_msg); |
756 | 757 | spin_unlock(&inode->i_lock); |
757 | 758 | gss_release_msg(gss_msg); |
758 | - spin_lock(&inode->i_lock); | |
759 | + goto restart; | |
759 | 760 | } |
760 | 761 | spin_unlock(&inode->i_lock); |
761 | 762 |
net/sunrpc/auth_gss/gss_krb5_mech.c
... | ... | @@ -237,6 +237,7 @@ |
237 | 237 | if (!supported_gss_krb5_enctype(alg)) { |
238 | 238 | printk(KERN_WARNING "gss_kerberos_mech: unsupported " |
239 | 239 | "encryption key algorithm %d\n", alg); |
240 | + p = ERR_PTR(-EINVAL); | |
240 | 241 | goto out_err; |
241 | 242 | } |
242 | 243 | p = simple_get_netobj(p, end, &key); |
243 | 244 | |
244 | 245 | |
245 | 246 | |
... | ... | @@ -282,15 +283,19 @@ |
282 | 283 | ctx->enctype = ENCTYPE_DES_CBC_RAW; |
283 | 284 | |
284 | 285 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); |
285 | - if (ctx->gk5e == NULL) | |
286 | + if (ctx->gk5e == NULL) { | |
287 | + p = ERR_PTR(-EINVAL); | |
286 | 288 | goto out_err; |
289 | + } | |
287 | 290 | |
288 | 291 | /* The downcall format was designed before we completely understood |
289 | 292 | * the uses of the context fields; so it includes some stuff we |
290 | 293 | * just give some minimal sanity-checking, and some we ignore |
291 | 294 | * completely (like the next twenty bytes): */ |
292 | - if (unlikely(p + 20 > end || p + 20 < p)) | |
295 | + if (unlikely(p + 20 > end || p + 20 < p)) { | |
296 | + p = ERR_PTR(-EFAULT); | |
293 | 297 | goto out_err; |
298 | + } | |
294 | 299 | p += 20; |
295 | 300 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
296 | 301 | if (IS_ERR(p)) |
... | ... | @@ -619,6 +624,7 @@ |
619 | 624 | if (ctx->seq_send64 != ctx->seq_send) { |
620 | 625 | dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__, |
621 | 626 | (long unsigned)ctx->seq_send64, ctx->seq_send); |
627 | + p = ERR_PTR(-EINVAL); | |
622 | 628 | goto out_err; |
623 | 629 | } |
624 | 630 | p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); |
net/sunrpc/auth_gss/gss_spkm3_mech.c
... | ... | @@ -100,6 +100,7 @@ |
100 | 100 | if (version != 1) { |
101 | 101 | dprintk("RPC: unknown spkm3 token format: " |
102 | 102 | "obsolete nfs-utils?\n"); |
103 | + p = ERR_PTR(-EINVAL); | |
103 | 104 | goto out_err_free_ctx; |
104 | 105 | } |
105 | 106 | |
106 | 107 | |
... | ... | @@ -135,8 +136,10 @@ |
135 | 136 | if (IS_ERR(p)) |
136 | 137 | goto out_err_free_intg_alg; |
137 | 138 | |
138 | - if (p != end) | |
139 | + if (p != end) { | |
140 | + p = ERR_PTR(-EFAULT); | |
139 | 141 | goto out_err_free_intg_key; |
142 | + } | |
140 | 143 | |
141 | 144 | ctx_id->internal_ctx_id = ctx; |
142 | 145 |
net/sunrpc/clnt.c
... | ... | @@ -226,7 +226,7 @@ |
226 | 226 | goto out_no_principal; |
227 | 227 | } |
228 | 228 | |
229 | - kref_init(&clnt->cl_kref); | |
229 | + atomic_set(&clnt->cl_count, 1); | |
230 | 230 | |
231 | 231 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name); |
232 | 232 | if (err < 0) |
233 | 233 | |
... | ... | @@ -390,14 +390,14 @@ |
390 | 390 | if (new->cl_principal == NULL) |
391 | 391 | goto out_no_principal; |
392 | 392 | } |
393 | - kref_init(&new->cl_kref); | |
393 | + atomic_set(&new->cl_count, 1); | |
394 | 394 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); |
395 | 395 | if (err != 0) |
396 | 396 | goto out_no_path; |
397 | 397 | if (new->cl_auth) |
398 | 398 | atomic_inc(&new->cl_auth->au_count); |
399 | 399 | xprt_get(clnt->cl_xprt); |
400 | - kref_get(&clnt->cl_kref); | |
400 | + atomic_inc(&clnt->cl_count); | |
401 | 401 | rpc_register_client(new); |
402 | 402 | rpciod_up(); |
403 | 403 | return new; |
404 | 404 | |
... | ... | @@ -465,10 +465,8 @@ |
465 | 465 | * Free an RPC client |
466 | 466 | */ |
467 | 467 | static void |
468 | -rpc_free_client(struct kref *kref) | |
468 | +rpc_free_client(struct rpc_clnt *clnt) | |
469 | 469 | { |
470 | - struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); | |
471 | - | |
472 | 470 | dprintk("RPC: destroying %s client for %s\n", |
473 | 471 | clnt->cl_protname, clnt->cl_server); |
474 | 472 | if (!IS_ERR(clnt->cl_path.dentry)) { |
475 | 473 | |
476 | 474 | |
... | ... | @@ -495,12 +493,10 @@ |
495 | 493 | * Free an RPC client |
496 | 494 | */ |
497 | 495 | static void |
498 | -rpc_free_auth(struct kref *kref) | |
496 | +rpc_free_auth(struct rpc_clnt *clnt) | |
499 | 497 | { |
500 | - struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); | |
501 | - | |
502 | 498 | if (clnt->cl_auth == NULL) { |
503 | - rpc_free_client(kref); | |
499 | + rpc_free_client(clnt); | |
504 | 500 | return; |
505 | 501 | } |
506 | 502 | |
507 | 503 | |
... | ... | @@ -509,10 +505,11 @@ |
509 | 505 | * release remaining GSS contexts. This mechanism ensures |
510 | 506 | * that it can do so safely. |
511 | 507 | */ |
512 | - kref_init(kref); | |
508 | + atomic_inc(&clnt->cl_count); | |
513 | 509 | rpcauth_release(clnt->cl_auth); |
514 | 510 | clnt->cl_auth = NULL; |
515 | - kref_put(kref, rpc_free_client); | |
511 | + if (atomic_dec_and_test(&clnt->cl_count)) | |
512 | + rpc_free_client(clnt); | |
516 | 513 | } |
517 | 514 | |
518 | 515 | /* |
... | ... | @@ -525,7 +522,8 @@ |
525 | 522 | |
526 | 523 | if (list_empty(&clnt->cl_tasks)) |
527 | 524 | wake_up(&destroy_wait); |
528 | - kref_put(&clnt->cl_kref, rpc_free_auth); | |
525 | + if (atomic_dec_and_test(&clnt->cl_count)) | |
526 | + rpc_free_auth(clnt); | |
529 | 527 | } |
530 | 528 | |
531 | 529 | /** |
... | ... | @@ -588,7 +586,7 @@ |
588 | 586 | if (clnt != NULL) { |
589 | 587 | rpc_task_release_client(task); |
590 | 588 | task->tk_client = clnt; |
591 | - kref_get(&clnt->cl_kref); | |
589 | + atomic_inc(&clnt->cl_count); | |
592 | 590 | if (clnt->cl_softrtry) |
593 | 591 | task->tk_flags |= RPC_TASK_SOFT; |
594 | 592 | /* Add to the client's list of all tasks */ |
... | ... | @@ -931,7 +929,7 @@ |
931 | 929 | task->tk_status = 0; |
932 | 930 | if (status >= 0) { |
933 | 931 | if (task->tk_rqstp) { |
934 | - task->tk_action = call_allocate; | |
932 | + task->tk_action = call_refresh; | |
935 | 933 | return; |
936 | 934 | } |
937 | 935 | |
938 | 936 | |
... | ... | @@ -966,13 +964,54 @@ |
966 | 964 | } |
967 | 965 | |
968 | 966 | /* |
969 | - * 2. Allocate the buffer. For details, see sched.c:rpc_malloc. | |
967 | + * 2. Bind and/or refresh the credentials | |
968 | + */ | |
969 | +static void | |
970 | +call_refresh(struct rpc_task *task) | |
971 | +{ | |
972 | + dprint_status(task); | |
973 | + | |
974 | + task->tk_action = call_refreshresult; | |
975 | + task->tk_status = 0; | |
976 | + task->tk_client->cl_stats->rpcauthrefresh++; | |
977 | + rpcauth_refreshcred(task); | |
978 | +} | |
979 | + | |
980 | +/* | |
981 | + * 2a. Process the results of a credential refresh | |
982 | + */ | |
983 | +static void | |
984 | +call_refreshresult(struct rpc_task *task) | |
985 | +{ | |
986 | + int status = task->tk_status; | |
987 | + | |
988 | + dprint_status(task); | |
989 | + | |
990 | + task->tk_status = 0; | |
991 | + task->tk_action = call_allocate; | |
992 | + if (status >= 0 && rpcauth_uptodatecred(task)) | |
993 | + return; | |
994 | + switch (status) { | |
995 | + case -EACCES: | |
996 | + rpc_exit(task, -EACCES); | |
997 | + return; | |
998 | + case -ENOMEM: | |
999 | + rpc_exit(task, -ENOMEM); | |
1000 | + return; | |
1001 | + case -ETIMEDOUT: | |
1002 | + rpc_delay(task, 3*HZ); | |
1003 | + } | |
1004 | + task->tk_action = call_refresh; | |
1005 | +} | |
1006 | + | |
1007 | +/* | |
1008 | + * 2b. Allocate the buffer. For details, see sched.c:rpc_malloc. | |
970 | 1009 | * (Note: buffer memory is freed in xprt_release). |
971 | 1010 | */ |
972 | 1011 | static void |
973 | 1012 | call_allocate(struct rpc_task *task) |
974 | 1013 | { |
975 | - unsigned int slack = task->tk_client->cl_auth->au_cslack; | |
1014 | + unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack; | |
976 | 1015 | struct rpc_rqst *req = task->tk_rqstp; |
977 | 1016 | struct rpc_xprt *xprt = task->tk_xprt; |
978 | 1017 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; |
... | ... | @@ -980,7 +1019,7 @@ |
980 | 1019 | dprint_status(task); |
981 | 1020 | |
982 | 1021 | task->tk_status = 0; |
983 | - task->tk_action = call_refresh; | |
1022 | + task->tk_action = call_bind; | |
984 | 1023 | |
985 | 1024 | if (req->rq_buffer) |
986 | 1025 | return; |
... | ... | @@ -1015,47 +1054,6 @@ |
1015 | 1054 | } |
1016 | 1055 | |
1017 | 1056 | rpc_exit(task, -ERESTARTSYS); |
1018 | -} | |
1019 | - | |
1020 | -/* | |
1021 | - * 2a. Bind and/or refresh the credentials | |
1022 | - */ | |
1023 | -static void | |
1024 | -call_refresh(struct rpc_task *task) | |
1025 | -{ | |
1026 | - dprint_status(task); | |
1027 | - | |
1028 | - task->tk_action = call_refreshresult; | |
1029 | - task->tk_status = 0; | |
1030 | - task->tk_client->cl_stats->rpcauthrefresh++; | |
1031 | - rpcauth_refreshcred(task); | |
1032 | -} | |
1033 | - | |
1034 | -/* | |
1035 | - * 2b. Process the results of a credential refresh | |
1036 | - */ | |
1037 | -static void | |
1038 | -call_refreshresult(struct rpc_task *task) | |
1039 | -{ | |
1040 | - int status = task->tk_status; | |
1041 | - | |
1042 | - dprint_status(task); | |
1043 | - | |
1044 | - task->tk_status = 0; | |
1045 | - task->tk_action = call_bind; | |
1046 | - if (status >= 0 && rpcauth_uptodatecred(task)) | |
1047 | - return; | |
1048 | - switch (status) { | |
1049 | - case -EACCES: | |
1050 | - rpc_exit(task, -EACCES); | |
1051 | - return; | |
1052 | - case -ENOMEM: | |
1053 | - rpc_exit(task, -ENOMEM); | |
1054 | - return; | |
1055 | - case -ETIMEDOUT: | |
1056 | - rpc_delay(task, 3*HZ); | |
1057 | - } | |
1058 | - task->tk_action = call_refresh; | |
1059 | 1057 | } |
1060 | 1058 | |
1061 | 1059 | static inline int |
net/sunrpc/rpc_pipe.c
... | ... | @@ -48,7 +48,7 @@ |
48 | 48 | return; |
49 | 49 | do { |
50 | 50 | msg = list_entry(head->next, struct rpc_pipe_msg, list); |
51 | - list_del(&msg->list); | |
51 | + list_del_init(&msg->list); | |
52 | 52 | msg->errno = err; |
53 | 53 | destroy_msg(msg); |
54 | 54 | } while (!list_empty(head)); |
... | ... | @@ -208,7 +208,7 @@ |
208 | 208 | if (msg != NULL) { |
209 | 209 | spin_lock(&inode->i_lock); |
210 | 210 | msg->errno = -EAGAIN; |
211 | - list_del(&msg->list); | |
211 | + list_del_init(&msg->list); | |
212 | 212 | spin_unlock(&inode->i_lock); |
213 | 213 | rpci->ops->destroy_msg(msg); |
214 | 214 | } |
... | ... | @@ -268,7 +268,7 @@ |
268 | 268 | if (res < 0 || msg->len == msg->copied) { |
269 | 269 | filp->private_data = NULL; |
270 | 270 | spin_lock(&inode->i_lock); |
271 | - list_del(&msg->list); | |
271 | + list_del_init(&msg->list); | |
272 | 272 | spin_unlock(&inode->i_lock); |
273 | 273 | rpci->ops->destroy_msg(msg); |
274 | 274 | } |
275 | 275 | |
276 | 276 | |
277 | 277 | |
... | ... | @@ -371,21 +371,23 @@ |
371 | 371 | static int |
372 | 372 | rpc_info_open(struct inode *inode, struct file *file) |
373 | 373 | { |
374 | - struct rpc_clnt *clnt; | |
374 | + struct rpc_clnt *clnt = NULL; | |
375 | 375 | int ret = single_open(file, rpc_show_info, NULL); |
376 | 376 | |
377 | 377 | if (!ret) { |
378 | 378 | struct seq_file *m = file->private_data; |
379 | - mutex_lock(&inode->i_mutex); | |
380 | - clnt = RPC_I(inode)->private; | |
381 | - if (clnt) { | |
382 | - kref_get(&clnt->cl_kref); | |
379 | + | |
380 | + spin_lock(&file->f_path.dentry->d_lock); | |
381 | + if (!d_unhashed(file->f_path.dentry)) | |
382 | + clnt = RPC_I(inode)->private; | |
383 | + if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) { | |
384 | + spin_unlock(&file->f_path.dentry->d_lock); | |
383 | 385 | m->private = clnt; |
384 | 386 | } else { |
387 | + spin_unlock(&file->f_path.dentry->d_lock); | |
385 | 388 | single_release(inode, file); |
386 | 389 | ret = -EINVAL; |
387 | 390 | } |
388 | - mutex_unlock(&inode->i_mutex); | |
389 | 391 | } |
390 | 392 | return ret; |
391 | 393 | } |