diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 18:22:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 18:22:57 -0500 |
commit | 47853e7fa588bef826c9799a87b33904b32bd905 (patch) | |
tree | bd7681d1aedf28125b86fb0218e64297f4d71ac9 /fs | |
parent | 221fc10ec89834329e5613e3cab4569ba22da410 (diff) | |
parent | 9e56904e41e242169007e69d9916059dab995d90 (diff) |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
Diffstat (limited to 'fs')
35 files changed, 1678 insertions, 1016 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index c5a33648e9fd..145524039577 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -26,11 +26,12 @@ | |||
26 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); | 26 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); |
27 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); | 27 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); |
28 | static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); | 28 | static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); |
29 | static void nlmclnt_unlock_callback(struct rpc_task *); | ||
30 | static void nlmclnt_cancel_callback(struct rpc_task *); | ||
31 | static int nlm_stat_to_errno(u32 stat); | 29 | static int nlm_stat_to_errno(u32 stat); |
32 | static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); | 30 | static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); |
33 | 31 | ||
32 | static const struct rpc_call_ops nlmclnt_unlock_ops; | ||
33 | static const struct rpc_call_ops nlmclnt_cancel_ops; | ||
34 | |||
34 | /* | 35 | /* |
35 | * Cookie counter for NLM requests | 36 | * Cookie counter for NLM requests |
36 | */ | 37 | */ |
@@ -221,8 +222,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
221 | goto done; | 222 | goto done; |
222 | } | 223 | } |
223 | clnt->cl_softrtry = nfssrv->client->cl_softrtry; | 224 | clnt->cl_softrtry = nfssrv->client->cl_softrtry; |
224 | clnt->cl_intr = nfssrv->client->cl_intr; | 225 | clnt->cl_intr = nfssrv->client->cl_intr; |
225 | clnt->cl_chatty = nfssrv->client->cl_chatty; | ||
226 | } | 226 | } |
227 | 227 | ||
228 | /* Keep the old signal mask */ | 228 | /* Keep the old signal mask */ |
@@ -399,8 +399,7 @@ in_grace_period: | |||
399 | /* | 399 | /* |
400 | * Generic NLM call, async version. | 400 | * Generic NLM call, async version. |
401 | */ | 401 | */ |
402 | int | 402 | int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
403 | nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) | ||
404 | { | 403 | { |
405 | struct nlm_host *host = req->a_host; | 404 | struct nlm_host *host = req->a_host; |
406 | struct rpc_clnt *clnt; | 405 | struct rpc_clnt *clnt; |
@@ -419,13 +418,12 @@ nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) | |||
419 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | 418 | msg.rpc_proc = &clnt->cl_procinfo[proc]; |
420 | 419 | ||
421 | /* bootstrap and kick off the async RPC call */ | 420 | /* bootstrap and kick off the async RPC call */ |
422 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req); | 421 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); |
423 | 422 | ||
424 | return status; | 423 | return status; |
425 | } | 424 | } |
426 | 425 | ||
427 | static int | 426 | static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
428 | nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) | ||
429 | { | 427 | { |
430 | struct nlm_host *host = req->a_host; | 428 | struct nlm_host *host = req->a_host; |
431 | struct rpc_clnt *clnt; | 429 | struct rpc_clnt *clnt; |
@@ -448,7 +446,7 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) | |||
448 | /* Increment host refcount */ | 446 | /* Increment host refcount */ |
449 | nlm_get_host(host); | 447 | nlm_get_host(host); |
450 | /* bootstrap and kick off the async RPC call */ | 448 | /* bootstrap and kick off the async RPC call */ |
451 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req); | 449 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); |
452 | if (status < 0) | 450 | if (status < 0) |
453 | nlm_release_host(host); | 451 | nlm_release_host(host); |
454 | return status; | 452 | return status; |
@@ -664,7 +662,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
664 | 662 | ||
665 | if (req->a_flags & RPC_TASK_ASYNC) { | 663 | if (req->a_flags & RPC_TASK_ASYNC) { |
666 | status = nlmclnt_async_call(req, NLMPROC_UNLOCK, | 664 | status = nlmclnt_async_call(req, NLMPROC_UNLOCK, |
667 | nlmclnt_unlock_callback); | 665 | &nlmclnt_unlock_ops); |
668 | /* Hrmf... Do the unlock early since locks_remove_posix() | 666 | /* Hrmf... Do the unlock early since locks_remove_posix() |
669 | * really expects us to free the lock synchronously */ | 667 | * really expects us to free the lock synchronously */ |
670 | do_vfs_lock(fl); | 668 | do_vfs_lock(fl); |
@@ -692,10 +690,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
692 | return -ENOLCK; | 690 | return -ENOLCK; |
693 | } | 691 | } |
694 | 692 | ||
695 | static void | 693 | static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) |
696 | nlmclnt_unlock_callback(struct rpc_task *task) | ||
697 | { | 694 | { |
698 | struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; | 695 | struct nlm_rqst *req = data; |
699 | int status = req->a_res.status; | 696 | int status = req->a_res.status; |
700 | 697 | ||
701 | if (RPC_ASSASSINATED(task)) | 698 | if (RPC_ASSASSINATED(task)) |
@@ -722,6 +719,10 @@ die: | |||
722 | rpc_restart_call(task); | 719 | rpc_restart_call(task); |
723 | } | 720 | } |
724 | 721 | ||
722 | static const struct rpc_call_ops nlmclnt_unlock_ops = { | ||
723 | .rpc_call_done = nlmclnt_unlock_callback, | ||
724 | }; | ||
725 | |||
725 | /* | 726 | /* |
726 | * Cancel a blocked lock request. | 727 | * Cancel a blocked lock request. |
727 | * We always use an async RPC call for this in order not to hang a | 728 | * We always use an async RPC call for this in order not to hang a |
@@ -750,8 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) | |||
750 | 751 | ||
751 | nlmclnt_setlockargs(req, fl); | 752 | nlmclnt_setlockargs(req, fl); |
752 | 753 | ||
753 | status = nlmclnt_async_call(req, NLMPROC_CANCEL, | 754 | status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
754 | nlmclnt_cancel_callback); | ||
755 | if (status < 0) { | 755 | if (status < 0) { |
756 | nlmclnt_release_lockargs(req); | 756 | nlmclnt_release_lockargs(req); |
757 | kfree(req); | 757 | kfree(req); |
@@ -765,10 +765,9 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) | |||
765 | return status; | 765 | return status; |
766 | } | 766 | } |
767 | 767 | ||
768 | static void | 768 | static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) |
769 | nlmclnt_cancel_callback(struct rpc_task *task) | ||
770 | { | 769 | { |
771 | struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; | 770 | struct nlm_rqst *req = data; |
772 | 771 | ||
773 | if (RPC_ASSASSINATED(task)) | 772 | if (RPC_ASSASSINATED(task)) |
774 | goto die; | 773 | goto die; |
@@ -807,6 +806,10 @@ retry_cancel: | |||
807 | rpc_delay(task, 30 * HZ); | 806 | rpc_delay(task, 30 * HZ); |
808 | } | 807 | } |
809 | 808 | ||
809 | static const struct rpc_call_ops nlmclnt_cancel_ops = { | ||
810 | .rpc_call_done = nlmclnt_cancel_callback, | ||
811 | }; | ||
812 | |||
810 | /* | 813 | /* |
811 | * Convert an NLM status code to a generic kernel errno | 814 | * Convert an NLM status code to a generic kernel errno |
812 | */ | 815 | */ |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index c4c8601096e0..82f7a0b1d8ae 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -177,7 +177,7 @@ nlm_bind_host(struct nlm_host *host) | |||
177 | if ((clnt = host->h_rpcclnt) != NULL) { | 177 | if ((clnt = host->h_rpcclnt) != NULL) { |
178 | xprt = clnt->cl_xprt; | 178 | xprt = clnt->cl_xprt; |
179 | if (time_after_eq(jiffies, host->h_nextrebind)) { | 179 | if (time_after_eq(jiffies, host->h_nextrebind)) { |
180 | clnt->cl_port = 0; | 180 | rpc_force_rebind(clnt); |
181 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; | 181 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; |
182 | dprintk("lockd: next rebind in %ld jiffies\n", | 182 | dprintk("lockd: next rebind in %ld jiffies\n", |
183 | host->h_nextrebind - jiffies); | 183 | host->h_nextrebind - jiffies); |
@@ -217,7 +217,7 @@ nlm_rebind_host(struct nlm_host *host) | |||
217 | { | 217 | { |
218 | dprintk("lockd: rebind host %s\n", host->h_name); | 218 | dprintk("lockd: rebind host %s\n", host->h_name); |
219 | if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) { | 219 | if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) { |
220 | host->h_rpcclnt->cl_port = 0; | 220 | rpc_force_rebind(host->h_rpcclnt); |
221 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; | 221 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; |
222 | } | 222 | } |
223 | } | 223 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 2d144abe84ad..0edc03e67966 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -123,7 +123,6 @@ nsm_create(void) | |||
123 | if (IS_ERR(clnt)) | 123 | if (IS_ERR(clnt)) |
124 | goto out_err; | 124 | goto out_err; |
125 | clnt->cl_softrtry = 1; | 125 | clnt->cl_softrtry = 1; |
126 | clnt->cl_chatty = 1; | ||
127 | clnt->cl_oneshot = 1; | 126 | clnt->cl_oneshot = 1; |
128 | return clnt; | 127 | return clnt; |
129 | 128 | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 12a857c29e25..71a30b416d1a 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -178,6 +178,8 @@ lockd(struct svc_rqst *rqstp) | |||
178 | 178 | ||
179 | } | 179 | } |
180 | 180 | ||
181 | flush_signals(current); | ||
182 | |||
181 | /* | 183 | /* |
182 | * Check whether there's a new lockd process before | 184 | * Check whether there's a new lockd process before |
183 | * shutting down the hosts and clearing the slot. | 185 | * shutting down the hosts and clearing the slot. |
@@ -192,8 +194,6 @@ lockd(struct svc_rqst *rqstp) | |||
192 | "lockd: new process, skipping host shutdown\n"); | 194 | "lockd: new process, skipping host shutdown\n"); |
193 | wake_up(&lockd_exit); | 195 | wake_up(&lockd_exit); |
194 | 196 | ||
195 | flush_signals(current); | ||
196 | |||
197 | /* Exit the RPC thread */ | 197 | /* Exit the RPC thread */ |
198 | svc_exit_thread(rqstp); | 198 | svc_exit_thread(rqstp); |
199 | 199 | ||
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 489670e21769..4063095d849e 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -22,7 +22,8 @@ | |||
22 | #define NLMDBG_FACILITY NLMDBG_CLIENT | 22 | #define NLMDBG_FACILITY NLMDBG_CLIENT |
23 | 23 | ||
24 | static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *); | 24 | static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *); |
25 | static void nlm4svc_callback_exit(struct rpc_task *); | 25 | |
26 | static const struct rpc_call_ops nlm4svc_callback_ops; | ||
26 | 27 | ||
27 | /* | 28 | /* |
28 | * Obtain client and file from arguments | 29 | * Obtain client and file from arguments |
@@ -470,7 +471,6 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, | |||
470 | } | 471 | } |
471 | 472 | ||
472 | 473 | ||
473 | |||
474 | /* | 474 | /* |
475 | * This is the generic lockd callback for async RPC calls | 475 | * This is the generic lockd callback for async RPC calls |
476 | */ | 476 | */ |
@@ -494,7 +494,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) | |||
494 | call->a_host = host; | 494 | call->a_host = host; |
495 | memcpy(&call->a_args, resp, sizeof(*resp)); | 495 | memcpy(&call->a_args, resp, sizeof(*resp)); |
496 | 496 | ||
497 | if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0) | 497 | if (nlmsvc_async_call(call, proc, &nlm4svc_callback_ops) < 0) |
498 | goto error; | 498 | goto error; |
499 | 499 | ||
500 | return rpc_success; | 500 | return rpc_success; |
@@ -504,10 +504,9 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) | |||
504 | return rpc_system_err; | 504 | return rpc_system_err; |
505 | } | 505 | } |
506 | 506 | ||
507 | static void | 507 | static void nlm4svc_callback_exit(struct rpc_task *task, void *data) |
508 | nlm4svc_callback_exit(struct rpc_task *task) | ||
509 | { | 508 | { |
510 | struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; | 509 | struct nlm_rqst *call = data; |
511 | 510 | ||
512 | if (task->tk_status < 0) { | 511 | if (task->tk_status < 0) { |
513 | dprintk("lockd: %4d callback failed (errno = %d)\n", | 512 | dprintk("lockd: %4d callback failed (errno = %d)\n", |
@@ -517,6 +516,10 @@ nlm4svc_callback_exit(struct rpc_task *task) | |||
517 | kfree(call); | 516 | kfree(call); |
518 | } | 517 | } |
519 | 518 | ||
519 | static const struct rpc_call_ops nlm4svc_callback_ops = { | ||
520 | .rpc_call_done = nlm4svc_callback_exit, | ||
521 | }; | ||
522 | |||
520 | /* | 523 | /* |
521 | * NLM Server procedures. | 524 | * NLM Server procedures. |
522 | */ | 525 | */ |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 49f959796b66..9cfced65d4a2 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -41,7 +41,8 @@ | |||
41 | 41 | ||
42 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); | 42 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); |
43 | static int nlmsvc_remove_block(struct nlm_block *block); | 43 | static int nlmsvc_remove_block(struct nlm_block *block); |
44 | static void nlmsvc_grant_callback(struct rpc_task *task); | 44 | |
45 | static const struct rpc_call_ops nlmsvc_grant_ops; | ||
45 | 46 | ||
46 | /* | 47 | /* |
47 | * The list of blocked locks to retry | 48 | * The list of blocked locks to retry |
@@ -226,31 +227,27 @@ failed: | |||
226 | * It is the caller's responsibility to check whether the file | 227 | * It is the caller's responsibility to check whether the file |
227 | * can be closed hereafter. | 228 | * can be closed hereafter. |
228 | */ | 229 | */ |
229 | static void | 230 | static int |
230 | nlmsvc_delete_block(struct nlm_block *block, int unlock) | 231 | nlmsvc_delete_block(struct nlm_block *block, int unlock) |
231 | { | 232 | { |
232 | struct file_lock *fl = &block->b_call.a_args.lock.fl; | 233 | struct file_lock *fl = &block->b_call.a_args.lock.fl; |
233 | struct nlm_file *file = block->b_file; | 234 | struct nlm_file *file = block->b_file; |
234 | struct nlm_block **bp; | 235 | struct nlm_block **bp; |
236 | int status = 0; | ||
235 | 237 | ||
236 | dprintk("lockd: deleting block %p...\n", block); | 238 | dprintk("lockd: deleting block %p...\n", block); |
237 | 239 | ||
238 | /* Remove block from list */ | 240 | /* Remove block from list */ |
239 | nlmsvc_remove_block(block); | 241 | nlmsvc_remove_block(block); |
240 | if (fl->fl_next) | 242 | if (unlock) |
241 | posix_unblock_lock(file->f_file, fl); | 243 | status = posix_unblock_lock(file->f_file, fl); |
242 | if (unlock) { | ||
243 | fl->fl_type = F_UNLCK; | ||
244 | posix_lock_file(file->f_file, fl); | ||
245 | block->b_granted = 0; | ||
246 | } | ||
247 | 244 | ||
248 | /* If the block is in the middle of a GRANT callback, | 245 | /* If the block is in the middle of a GRANT callback, |
249 | * don't kill it yet. */ | 246 | * don't kill it yet. */ |
250 | if (block->b_incall) { | 247 | if (block->b_incall) { |
251 | nlmsvc_insert_block(block, NLM_NEVER); | 248 | nlmsvc_insert_block(block, NLM_NEVER); |
252 | block->b_done = 1; | 249 | block->b_done = 1; |
253 | return; | 250 | return status; |
254 | } | 251 | } |
255 | 252 | ||
256 | /* Remove block from file's list of blocks */ | 253 | /* Remove block from file's list of blocks */ |
@@ -265,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) | |||
265 | nlm_release_host(block->b_host); | 262 | nlm_release_host(block->b_host); |
266 | nlmclnt_freegrantargs(&block->b_call); | 263 | nlmclnt_freegrantargs(&block->b_call); |
267 | kfree(block); | 264 | kfree(block); |
265 | return status; | ||
268 | } | 266 | } |
269 | 267 | ||
270 | /* | 268 | /* |
@@ -275,6 +273,7 @@ int | |||
275 | nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) | 273 | nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) |
276 | { | 274 | { |
277 | struct nlm_block *block, *next; | 275 | struct nlm_block *block, *next; |
276 | /* XXX: Will everything get cleaned up if we don't unlock here? */ | ||
278 | 277 | ||
279 | down(&file->f_sema); | 278 | down(&file->f_sema); |
280 | for (block = file->f_blocks; block; block = next) { | 279 | for (block = file->f_blocks; block; block = next) { |
@@ -444,6 +443,7 @@ u32 | |||
444 | nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | 443 | nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) |
445 | { | 444 | { |
446 | struct nlm_block *block; | 445 | struct nlm_block *block; |
446 | int status = 0; | ||
447 | 447 | ||
448 | dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", | 448 | dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", |
449 | file->f_file->f_dentry->d_inode->i_sb->s_id, | 449 | file->f_file->f_dentry->d_inode->i_sb->s_id, |
@@ -454,9 +454,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
454 | 454 | ||
455 | down(&file->f_sema); | 455 | down(&file->f_sema); |
456 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) | 456 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) |
457 | nlmsvc_delete_block(block, 1); | 457 | status = nlmsvc_delete_block(block, 1); |
458 | up(&file->f_sema); | 458 | up(&file->f_sema); |
459 | return nlm_granted; | 459 | return status ? nlm_lck_denied : nlm_granted; |
460 | } | 460 | } |
461 | 461 | ||
462 | /* | 462 | /* |
@@ -562,7 +562,7 @@ callback: | |||
562 | /* Call the client */ | 562 | /* Call the client */ |
563 | nlm_get_host(block->b_call.a_host); | 563 | nlm_get_host(block->b_call.a_host); |
564 | if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, | 564 | if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, |
565 | nlmsvc_grant_callback) < 0) | 565 | &nlmsvc_grant_ops) < 0) |
566 | nlm_release_host(block->b_call.a_host); | 566 | nlm_release_host(block->b_call.a_host); |
567 | up(&file->f_sema); | 567 | up(&file->f_sema); |
568 | } | 568 | } |
@@ -575,10 +575,9 @@ callback: | |||
575 | * chain once more in order to have it removed by lockd itself (which can | 575 | * chain once more in order to have it removed by lockd itself (which can |
576 | * then sleep on the file semaphore without disrupting e.g. the nfs client). | 576 | * then sleep on the file semaphore without disrupting e.g. the nfs client). |
577 | */ | 577 | */ |
578 | static void | 578 | static void nlmsvc_grant_callback(struct rpc_task *task, void *data) |
579 | nlmsvc_grant_callback(struct rpc_task *task) | ||
580 | { | 579 | { |
581 | struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; | 580 | struct nlm_rqst *call = data; |
582 | struct nlm_block *block; | 581 | struct nlm_block *block; |
583 | unsigned long timeout; | 582 | unsigned long timeout; |
584 | struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); | 583 | struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); |
@@ -614,6 +613,10 @@ nlmsvc_grant_callback(struct rpc_task *task) | |||
614 | nlm_release_host(call->a_host); | 613 | nlm_release_host(call->a_host); |
615 | } | 614 | } |
616 | 615 | ||
616 | static const struct rpc_call_ops nlmsvc_grant_ops = { | ||
617 | .rpc_call_done = nlmsvc_grant_callback, | ||
618 | }; | ||
619 | |||
617 | /* | 620 | /* |
618 | * We received a GRANT_RES callback. Try to find the corresponding | 621 | * We received a GRANT_RES callback. Try to find the corresponding |
619 | * block. | 622 | * block. |
@@ -633,11 +636,12 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status | |||
633 | 636 | ||
634 | file->f_count++; | 637 | file->f_count++; |
635 | down(&file->f_sema); | 638 | down(&file->f_sema); |
636 | if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { | 639 | block = nlmsvc_find_block(cookie, &rqstp->rq_addr); |
640 | if (block) { | ||
637 | if (status == NLM_LCK_DENIED_GRACE_PERIOD) { | 641 | if (status == NLM_LCK_DENIED_GRACE_PERIOD) { |
638 | /* Try again in a couple of seconds */ | 642 | /* Try again in a couple of seconds */ |
639 | nlmsvc_insert_block(block, 10 * HZ); | 643 | nlmsvc_insert_block(block, 10 * HZ); |
640 | block = NULL; | 644 | up(&file->f_sema); |
641 | } else { | 645 | } else { |
642 | /* Lock is now held by client, or has been rejected. | 646 | /* Lock is now held by client, or has been rejected. |
643 | * In both cases, the block should be removed. */ | 647 | * In both cases, the block should be removed. */ |
@@ -648,8 +652,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status | |||
648 | nlmsvc_delete_block(block, 1); | 652 | nlmsvc_delete_block(block, 1); |
649 | } | 653 | } |
650 | } | 654 | } |
651 | if (!block) | ||
652 | up(&file->f_sema); | ||
653 | nlm_release_file(file); | 655 | nlm_release_file(file); |
654 | } | 656 | } |
655 | 657 | ||
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 757e344cf200..3bc437e0cf5b 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -23,7 +23,8 @@ | |||
23 | #define NLMDBG_FACILITY NLMDBG_CLIENT | 23 | #define NLMDBG_FACILITY NLMDBG_CLIENT |
24 | 24 | ||
25 | static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *); | 25 | static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *); |
26 | static void nlmsvc_callback_exit(struct rpc_task *); | 26 | |
27 | static const struct rpc_call_ops nlmsvc_callback_ops; | ||
27 | 28 | ||
28 | #ifdef CONFIG_LOCKD_V4 | 29 | #ifdef CONFIG_LOCKD_V4 |
29 | static u32 | 30 | static u32 |
@@ -518,7 +519,7 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) | |||
518 | call->a_host = host; | 519 | call->a_host = host; |
519 | memcpy(&call->a_args, resp, sizeof(*resp)); | 520 | memcpy(&call->a_args, resp, sizeof(*resp)); |
520 | 521 | ||
521 | if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0) | 522 | if (nlmsvc_async_call(call, proc, &nlmsvc_callback_ops) < 0) |
522 | goto error; | 523 | goto error; |
523 | 524 | ||
524 | return rpc_success; | 525 | return rpc_success; |
@@ -528,10 +529,9 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) | |||
528 | return rpc_system_err; | 529 | return rpc_system_err; |
529 | } | 530 | } |
530 | 531 | ||
531 | static void | 532 | static void nlmsvc_callback_exit(struct rpc_task *task, void *data) |
532 | nlmsvc_callback_exit(struct rpc_task *task) | ||
533 | { | 533 | { |
534 | struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; | 534 | struct nlm_rqst *call = data; |
535 | 535 | ||
536 | if (task->tk_status < 0) { | 536 | if (task->tk_status < 0) { |
537 | dprintk("lockd: %4d callback failed (errno = %d)\n", | 537 | dprintk("lockd: %4d callback failed (errno = %d)\n", |
@@ -541,6 +541,10 @@ nlmsvc_callback_exit(struct rpc_task *task) | |||
541 | kfree(call); | 541 | kfree(call); |
542 | } | 542 | } |
543 | 543 | ||
544 | static const struct rpc_call_ops nlmsvc_callback_ops = { | ||
545 | .rpc_call_done = nlmsvc_callback_exit, | ||
546 | }; | ||
547 | |||
544 | /* | 548 | /* |
545 | * NLM Server procedures. | 549 | * NLM Server procedures. |
546 | */ | 550 | */ |
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index ae4d6b426c62..fdcf105a5303 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c | |||
@@ -354,7 +354,9 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) | |||
354 | return 0; | 354 | return 0; |
355 | argp->state = ntohl(*p++); | 355 | argp->state = ntohl(*p++); |
356 | /* Preserve the address in network byte order */ | 356 | /* Preserve the address in network byte order */ |
357 | argp->addr = *p++; | 357 | argp->addr = *p++; |
358 | argp->vers = *p++; | ||
359 | argp->proto = *p++; | ||
358 | return xdr_argsize_check(rqstp, p); | 360 | return xdr_argsize_check(rqstp, p); |
359 | } | 361 | } |
360 | 362 | ||
diff --git a/fs/locks.c b/fs/locks.c index 250ef53d25ef..fb32d6218e21 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1958,22 +1958,18 @@ EXPORT_SYMBOL(posix_block_lock); | |||
1958 | * | 1958 | * |
1959 | * lockd needs to block waiting for locks. | 1959 | * lockd needs to block waiting for locks. |
1960 | */ | 1960 | */ |
1961 | void | 1961 | int |
1962 | posix_unblock_lock(struct file *filp, struct file_lock *waiter) | 1962 | posix_unblock_lock(struct file *filp, struct file_lock *waiter) |
1963 | { | 1963 | { |
1964 | /* | 1964 | int status = 0; |
1965 | * A remote machine may cancel the lock request after it's been | 1965 | |
1966 | * granted locally. If that happens, we need to delete the lock. | ||
1967 | */ | ||
1968 | lock_kernel(); | 1966 | lock_kernel(); |
1969 | if (waiter->fl_next) { | 1967 | if (waiter->fl_next) |
1970 | __locks_delete_block(waiter); | 1968 | __locks_delete_block(waiter); |
1971 | unlock_kernel(); | 1969 | else |
1972 | } else { | 1970 | status = -ENOENT; |
1973 | unlock_kernel(); | 1971 | unlock_kernel(); |
1974 | waiter->fl_type = F_UNLCK; | 1972 | return status; |
1975 | posix_lock_file(filp, waiter); | ||
1976 | } | ||
1977 | } | 1973 | } |
1978 | 1974 | ||
1979 | EXPORT_SYMBOL(posix_unblock_lock); | 1975 | EXPORT_SYMBOL(posix_unblock_lock); |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 8b3bb715d177..ec61fd56a1a9 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -13,4 +13,5 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |||
13 | delegation.o idmap.o \ | 13 | delegation.o idmap.o \ |
14 | callback.o callback_xdr.o callback_proc.o | 14 | callback.o callback_xdr.o callback_proc.o |
15 | nfs-$(CONFIG_NFS_DIRECTIO) += direct.o | 15 | nfs-$(CONFIG_NFS_DIRECTIO) += direct.o |
16 | nfs-$(CONFIG_SYSCTL) += sysctl.o | ||
16 | nfs-objs := $(nfs-y) | 17 | nfs-objs := $(nfs-y) |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 30cae3602867..fcd97406a778 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -34,6 +34,7 @@ static struct nfs_callback_data nfs_callback_info; | |||
34 | static DECLARE_MUTEX(nfs_callback_sema); | 34 | static DECLARE_MUTEX(nfs_callback_sema); |
35 | static struct svc_program nfs4_callback_program; | 35 | static struct svc_program nfs4_callback_program; |
36 | 36 | ||
37 | unsigned int nfs_callback_set_tcpport; | ||
37 | unsigned short nfs_callback_tcpport; | 38 | unsigned short nfs_callback_tcpport; |
38 | 39 | ||
39 | /* | 40 | /* |
@@ -98,7 +99,7 @@ int nfs_callback_up(void) | |||
98 | if (!serv) | 99 | if (!serv) |
99 | goto out_err; | 100 | goto out_err; |
100 | /* FIXME: We don't want to register this socket with the portmapper */ | 101 | /* FIXME: We don't want to register this socket with the portmapper */ |
101 | ret = svc_makesock(serv, IPPROTO_TCP, 0); | 102 | ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport); |
102 | if (ret < 0) | 103 | if (ret < 0) |
103 | goto out_destroy; | 104 | goto out_destroy; |
104 | if (!list_empty(&serv->sv_permsocks)) { | 105 | if (!list_empty(&serv->sv_permsocks)) { |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index a0db2d4f9415..b252e7fe53a5 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -65,6 +65,7 @@ extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | |||
65 | extern int nfs_callback_up(void); | 65 | extern int nfs_callback_up(void); |
66 | extern int nfs_callback_down(void); | 66 | extern int nfs_callback_down(void); |
67 | 67 | ||
68 | extern unsigned int nfs_callback_set_tcpport; | ||
68 | extern unsigned short nfs_callback_tcpport; | 69 | extern unsigned short nfs_callback_tcpport; |
69 | 70 | ||
70 | #endif /* __LINUX_FS_NFS_CALLBACK_H */ | 71 | #endif /* __LINUX_FS_NFS_CALLBACK_H */ |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 65f1e19e4d19..462cfceb50c5 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -35,7 +35,9 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres | |||
35 | if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) | 35 | if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) |
36 | goto out_iput; | 36 | goto out_iput; |
37 | res->size = i_size_read(inode); | 37 | res->size = i_size_read(inode); |
38 | res->change_attr = NFS_CHANGE_ATTR(inode); | 38 | res->change_attr = delegation->change_attr; |
39 | if (nfsi->npages != 0) | ||
40 | res->change_attr++; | ||
39 | res->ctime = inode->i_ctime; | 41 | res->ctime = inode->i_ctime; |
40 | res->mtime = inode->i_mtime; | 42 | res->mtime = inode->i_mtime; |
41 | res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) & | 43 | res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) & |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 618a327027b3..c6f07c1c71e6 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
10 | #include <linux/completion.h> | 10 | #include <linux/completion.h> |
11 | #include <linux/kthread.h> | ||
11 | #include <linux/module.h> | 12 | #include <linux/module.h> |
12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
13 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
@@ -130,6 +131,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
130 | sizeof(delegation->stateid.data)); | 131 | sizeof(delegation->stateid.data)); |
131 | delegation->type = res->delegation_type; | 132 | delegation->type = res->delegation_type; |
132 | delegation->maxsize = res->maxsize; | 133 | delegation->maxsize = res->maxsize; |
134 | delegation->change_attr = nfsi->change_attr; | ||
133 | delegation->cred = get_rpccred(cred); | 135 | delegation->cred = get_rpccred(cred); |
134 | delegation->inode = inode; | 136 | delegation->inode = inode; |
135 | 137 | ||
@@ -157,8 +159,6 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |||
157 | { | 159 | { |
158 | int res = 0; | 160 | int res = 0; |
159 | 161 | ||
160 | __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
161 | |||
162 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); | 162 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); |
163 | nfs_free_delegation(delegation); | 163 | nfs_free_delegation(delegation); |
164 | return res; | 164 | return res; |
@@ -231,6 +231,49 @@ restart: | |||
231 | spin_unlock(&clp->cl_lock); | 231 | spin_unlock(&clp->cl_lock); |
232 | } | 232 | } |
233 | 233 | ||
234 | int nfs_do_expire_all_delegations(void *ptr) | ||
235 | { | ||
236 | struct nfs4_client *clp = ptr; | ||
237 | struct nfs_delegation *delegation; | ||
238 | struct inode *inode; | ||
239 | |||
240 | allow_signal(SIGKILL); | ||
241 | restart: | ||
242 | spin_lock(&clp->cl_lock); | ||
243 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) | ||
244 | goto out; | ||
245 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) | ||
246 | goto out; | ||
247 | list_for_each_entry(delegation, &clp->cl_delegations, super_list) { | ||
248 | inode = igrab(delegation->inode); | ||
249 | if (inode == NULL) | ||
250 | continue; | ||
251 | spin_unlock(&clp->cl_lock); | ||
252 | nfs_inode_return_delegation(inode); | ||
253 | iput(inode); | ||
254 | goto restart; | ||
255 | } | ||
256 | out: | ||
257 | spin_unlock(&clp->cl_lock); | ||
258 | nfs4_put_client(clp); | ||
259 | module_put_and_exit(0); | ||
260 | } | ||
261 | |||
262 | void nfs_expire_all_delegations(struct nfs4_client *clp) | ||
263 | { | ||
264 | struct task_struct *task; | ||
265 | |||
266 | __module_get(THIS_MODULE); | ||
267 | atomic_inc(&clp->cl_count); | ||
268 | task = kthread_run(nfs_do_expire_all_delegations, clp, | ||
269 | "%u.%u.%u.%u-delegreturn", | ||
270 | NIPQUAD(clp->cl_addr)); | ||
271 | if (!IS_ERR(task)) | ||
272 | return; | ||
273 | nfs4_put_client(clp); | ||
274 | module_put(THIS_MODULE); | ||
275 | } | ||
276 | |||
234 | /* | 277 | /* |
235 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. | 278 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. |
236 | */ | 279 | */ |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 2fcc30de924b..7a0b2bfce771 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -21,6 +21,7 @@ struct nfs_delegation { | |||
21 | #define NFS_DELEGATION_NEED_RECLAIM 1 | 21 | #define NFS_DELEGATION_NEED_RECLAIM 1 |
22 | long flags; | 22 | long flags; |
23 | loff_t maxsize; | 23 | loff_t maxsize; |
24 | __u64 change_attr; | ||
24 | }; | 25 | }; |
25 | 26 | ||
26 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 27 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
@@ -30,6 +31,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s | |||
30 | 31 | ||
31 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); | 32 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); |
32 | void nfs_return_all_delegations(struct super_block *sb); | 33 | void nfs_return_all_delegations(struct super_block *sb); |
34 | void nfs_expire_all_delegations(struct nfs4_client *clp); | ||
33 | void nfs_handle_cb_pathdown(struct nfs4_client *clp); | 35 | void nfs_handle_cb_pathdown(struct nfs4_client *clp); |
34 | 36 | ||
35 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp); | 37 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c0d1a214572c..e9255198f767 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1550,8 +1550,10 @@ go_ahead: | |||
1550 | } | 1550 | } |
1551 | nfs_inode_return_delegation(old_inode); | 1551 | nfs_inode_return_delegation(old_inode); |
1552 | 1552 | ||
1553 | if (new_inode) | 1553 | if (new_inode != NULL) { |
1554 | nfs_inode_return_delegation(new_inode); | ||
1554 | d_delete(new_dentry); | 1555 | d_delete(new_dentry); |
1556 | } | ||
1555 | 1557 | ||
1556 | nfs_begin_data_update(old_dir); | 1558 | nfs_begin_data_update(old_dir); |
1557 | nfs_begin_data_update(new_dir); | 1559 | nfs_begin_data_update(new_dir); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 079228817603..10ae377e68ff 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -122,9 +122,10 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty) | |||
122 | { | 122 | { |
123 | int i; | 123 | int i; |
124 | for (i = 0; i < npages; i++) { | 124 | for (i = 0; i < npages; i++) { |
125 | if (do_dirty) | 125 | struct page *page = pages[i]; |
126 | set_page_dirty_lock(pages[i]); | 126 | if (do_dirty && !PageCompound(page)) |
127 | page_cache_release(pages[i]); | 127 | set_page_dirty_lock(page); |
128 | page_cache_release(page); | ||
128 | } | 129 | } |
129 | kfree(pages); | 130 | kfree(pages); |
130 | } | 131 | } |
@@ -154,6 +155,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int | |||
154 | struct list_head *list; | 155 | struct list_head *list; |
155 | struct nfs_direct_req *dreq; | 156 | struct nfs_direct_req *dreq; |
156 | unsigned int reads = 0; | 157 | unsigned int reads = 0; |
158 | unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
157 | 159 | ||
158 | dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); | 160 | dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); |
159 | if (!dreq) | 161 | if (!dreq) |
@@ -167,7 +169,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int | |||
167 | 169 | ||
168 | list = &dreq->list; | 170 | list = &dreq->list; |
169 | for(;;) { | 171 | for(;;) { |
170 | struct nfs_read_data *data = nfs_readdata_alloc(); | 172 | struct nfs_read_data *data = nfs_readdata_alloc(rpages); |
171 | 173 | ||
172 | if (unlikely(!data)) { | 174 | if (unlikely(!data)) { |
173 | while (!list_empty(list)) { | 175 | while (!list_empty(list)) { |
@@ -268,8 +270,6 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, | |||
268 | NFS_PROTO(inode)->read_setup(data); | 270 | NFS_PROTO(inode)->read_setup(data); |
269 | 271 | ||
270 | data->task.tk_cookie = (unsigned long) inode; | 272 | data->task.tk_cookie = (unsigned long) inode; |
271 | data->task.tk_calldata = data; | ||
272 | data->task.tk_release = nfs_readdata_release; | ||
273 | data->complete = nfs_direct_read_result; | 273 | data->complete = nfs_direct_read_result; |
274 | 274 | ||
275 | lock_kernel(); | 275 | lock_kernel(); |
@@ -433,7 +433,7 @@ static ssize_t nfs_direct_write_seg(struct inode *inode, | |||
433 | struct nfs_writeverf first_verf; | 433 | struct nfs_writeverf first_verf; |
434 | struct nfs_write_data *wdata; | 434 | struct nfs_write_data *wdata; |
435 | 435 | ||
436 | wdata = nfs_writedata_alloc(); | 436 | wdata = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); |
437 | if (!wdata) | 437 | if (!wdata) |
438 | return -ENOMEM; | 438 | return -ENOMEM; |
439 | 439 | ||
@@ -662,10 +662,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t | |||
662 | .iov_len = count, | 662 | .iov_len = count, |
663 | }; | 663 | }; |
664 | 664 | ||
665 | dprintk("nfs: direct read(%s/%s, %lu@%lu)\n", | 665 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", |
666 | file->f_dentry->d_parent->d_name.name, | 666 | file->f_dentry->d_parent->d_name.name, |
667 | file->f_dentry->d_name.name, | 667 | file->f_dentry->d_name.name, |
668 | (unsigned long) count, (unsigned long) pos); | 668 | (unsigned long) count, (long long) pos); |
669 | 669 | ||
670 | if (!is_sync_kiocb(iocb)) | 670 | if (!is_sync_kiocb(iocb)) |
671 | goto out; | 671 | goto out; |
@@ -718,9 +718,7 @@ out: | |||
718 | ssize_t | 718 | ssize_t |
719 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) | 719 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) |
720 | { | 720 | { |
721 | ssize_t retval = -EINVAL; | 721 | ssize_t retval; |
722 | loff_t *ppos = &iocb->ki_pos; | ||
723 | unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
724 | struct file *file = iocb->ki_filp; | 722 | struct file *file = iocb->ki_filp; |
725 | struct nfs_open_context *ctx = | 723 | struct nfs_open_context *ctx = |
726 | (struct nfs_open_context *) file->private_data; | 724 | (struct nfs_open_context *) file->private_data; |
@@ -728,35 +726,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
728 | struct inode *inode = mapping->host; | 726 | struct inode *inode = mapping->host; |
729 | struct iovec iov = { | 727 | struct iovec iov = { |
730 | .iov_base = (char __user *)buf, | 728 | .iov_base = (char __user *)buf, |
731 | .iov_len = count, | ||
732 | }; | 729 | }; |
733 | 730 | ||
734 | dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", | 731 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", |
735 | file->f_dentry->d_parent->d_name.name, | 732 | file->f_dentry->d_parent->d_name.name, |
736 | file->f_dentry->d_name.name, inode->i_ino, | 733 | file->f_dentry->d_name.name, |
737 | (unsigned long) count, (unsigned long) pos); | 734 | (unsigned long) count, (long long) pos); |
738 | 735 | ||
736 | retval = -EINVAL; | ||
739 | if (!is_sync_kiocb(iocb)) | 737 | if (!is_sync_kiocb(iocb)) |
740 | goto out; | 738 | goto out; |
741 | if (count < 0) | 739 | |
742 | goto out; | 740 | retval = generic_write_checks(file, &pos, &count, 0); |
743 | if (pos < 0) | 741 | if (retval) |
744 | goto out; | 742 | goto out; |
745 | retval = -EFAULT; | 743 | |
746 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 744 | retval = -EINVAL; |
745 | if ((ssize_t) count < 0) | ||
747 | goto out; | 746 | goto out; |
748 | retval = -EFBIG; | ||
749 | if (limit != RLIM_INFINITY) { | ||
750 | if (pos >= limit) { | ||
751 | send_sig(SIGXFSZ, current, 0); | ||
752 | goto out; | ||
753 | } | ||
754 | if (count > limit - (unsigned long) pos) | ||
755 | count = limit - (unsigned long) pos; | ||
756 | } | ||
757 | retval = 0; | 747 | retval = 0; |
758 | if (!count) | 748 | if (!count) |
759 | goto out; | 749 | goto out; |
750 | iov.iov_len = count, | ||
751 | |||
752 | retval = -EFAULT; | ||
753 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | ||
754 | goto out; | ||
760 | 755 | ||
761 | retval = nfs_sync_mapping(mapping); | 756 | retval = nfs_sync_mapping(mapping); |
762 | if (retval) | 757 | if (retval) |
@@ -766,7 +761,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
766 | if (mapping->nrpages) | 761 | if (mapping->nrpages) |
767 | invalidate_inode_pages2(mapping); | 762 | invalidate_inode_pages2(mapping); |
768 | if (retval > 0) | 763 | if (retval > 0) |
769 | *ppos = pos + retval; | 764 | iocb->ki_pos = pos + retval; |
770 | 765 | ||
771 | out: | 766 | out: |
772 | return retval; | 767 | return retval; |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index ffb8df91dc34..821edd30333b 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -54,7 +54,11 @@ | |||
54 | 54 | ||
55 | #define IDMAP_HASH_SZ 128 | 55 | #define IDMAP_HASH_SZ 128 |
56 | 56 | ||
57 | /* Default cache timeout is 10 minutes */ | ||
58 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | ||
59 | |||
57 | struct idmap_hashent { | 60 | struct idmap_hashent { |
61 | unsigned long ih_expires; | ||
58 | __u32 ih_id; | 62 | __u32 ih_id; |
59 | int ih_namelen; | 63 | int ih_namelen; |
60 | char ih_name[IDMAP_NAMESZ]; | 64 | char ih_name[IDMAP_NAMESZ]; |
@@ -149,6 +153,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) | |||
149 | 153 | ||
150 | if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) | 154 | if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) |
151 | return NULL; | 155 | return NULL; |
156 | if (time_after(jiffies, he->ih_expires)) | ||
157 | return NULL; | ||
152 | return he; | 158 | return he; |
153 | } | 159 | } |
154 | 160 | ||
@@ -164,6 +170,8 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id) | |||
164 | struct idmap_hashent *he = idmap_id_hash(h, id); | 170 | struct idmap_hashent *he = idmap_id_hash(h, id); |
165 | if (he->ih_id != id || he->ih_namelen == 0) | 171 | if (he->ih_id != id || he->ih_namelen == 0) |
166 | return NULL; | 172 | return NULL; |
173 | if (time_after(jiffies, he->ih_expires)) | ||
174 | return NULL; | ||
167 | return he; | 175 | return he; |
168 | } | 176 | } |
169 | 177 | ||
@@ -192,6 +200,7 @@ idmap_update_entry(struct idmap_hashent *he, const char *name, | |||
192 | memcpy(he->ih_name, name, namelen); | 200 | memcpy(he->ih_name, name, namelen); |
193 | he->ih_name[namelen] = '\0'; | 201 | he->ih_name[namelen] = '\0'; |
194 | he->ih_namelen = namelen; | 202 | he->ih_namelen = namelen; |
203 | he->ih_expires = jiffies + nfs_idmap_cache_timeout; | ||
195 | } | 204 | } |
196 | 205 | ||
197 | /* | 206 | /* |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 432f41cd75e6..e7bd0d92600f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | 41 | ||
42 | #include "nfs4_fs.h" | 42 | #include "nfs4_fs.h" |
43 | #include "callback.h" | ||
43 | #include "delegation.h" | 44 | #include "delegation.h" |
44 | 45 | ||
45 | #define NFSDBG_FACILITY NFSDBG_VFS | 46 | #define NFSDBG_FACILITY NFSDBG_VFS |
@@ -221,10 +222,10 @@ nfs_calc_block_size(u64 tsize) | |||
221 | static inline unsigned long | 222 | static inline unsigned long |
222 | nfs_block_size(unsigned long bsize, unsigned char *nrbitsp) | 223 | nfs_block_size(unsigned long bsize, unsigned char *nrbitsp) |
223 | { | 224 | { |
224 | if (bsize < 1024) | 225 | if (bsize < NFS_MIN_FILE_IO_SIZE) |
225 | bsize = NFS_DEF_FILE_IO_BUFFER_SIZE; | 226 | bsize = NFS_DEF_FILE_IO_SIZE; |
226 | else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) | 227 | else if (bsize >= NFS_MAX_FILE_IO_SIZE) |
227 | bsize = NFS_MAX_FILE_IO_BUFFER_SIZE; | 228 | bsize = NFS_MAX_FILE_IO_SIZE; |
228 | 229 | ||
229 | return nfs_block_bits(bsize, nrbitsp); | 230 | return nfs_block_bits(bsize, nrbitsp); |
230 | } | 231 | } |
@@ -307,20 +308,15 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | |||
307 | max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); | 308 | max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); |
308 | if (server->rsize > max_rpc_payload) | 309 | if (server->rsize > max_rpc_payload) |
309 | server->rsize = max_rpc_payload; | 310 | server->rsize = max_rpc_payload; |
310 | if (server->wsize > max_rpc_payload) | 311 | if (server->rsize > NFS_MAX_FILE_IO_SIZE) |
311 | server->wsize = max_rpc_payload; | 312 | server->rsize = NFS_MAX_FILE_IO_SIZE; |
312 | |||
313 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 313 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
314 | if (server->rpages > NFS_READ_MAXIOV) { | ||
315 | server->rpages = NFS_READ_MAXIOV; | ||
316 | server->rsize = server->rpages << PAGE_CACHE_SHIFT; | ||
317 | } | ||
318 | 314 | ||
315 | if (server->wsize > max_rpc_payload) | ||
316 | server->wsize = max_rpc_payload; | ||
317 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) | ||
318 | server->wsize = NFS_MAX_FILE_IO_SIZE; | ||
319 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 319 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
320 | if (server->wpages > NFS_WRITE_MAXIOV) { | ||
321 | server->wpages = NFS_WRITE_MAXIOV; | ||
322 | server->wsize = server->wpages << PAGE_CACHE_SHIFT; | ||
323 | } | ||
324 | 320 | ||
325 | if (sb->s_blocksize == 0) | 321 | if (sb->s_blocksize == 0) |
326 | sb->s_blocksize = nfs_block_bits(server->wsize, | 322 | sb->s_blocksize = nfs_block_bits(server->wsize, |
@@ -417,7 +413,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
417 | 413 | ||
418 | clnt->cl_intr = 1; | 414 | clnt->cl_intr = 1; |
419 | clnt->cl_softrtry = 1; | 415 | clnt->cl_softrtry = 1; |
420 | clnt->cl_chatty = 1; | ||
421 | 416 | ||
422 | return clnt; | 417 | return clnt; |
423 | 418 | ||
@@ -575,11 +570,10 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf) | |||
575 | buf->f_namelen = server->namelen; | 570 | buf->f_namelen = server->namelen; |
576 | out: | 571 | out: |
577 | unlock_kernel(); | 572 | unlock_kernel(); |
578 | |||
579 | return 0; | 573 | return 0; |
580 | 574 | ||
581 | out_err: | 575 | out_err: |
582 | printk(KERN_WARNING "nfs_statfs: statfs error = %d\n", -error); | 576 | dprintk("%s: statfs error = %d\n", __FUNCTION__, -error); |
583 | buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; | 577 | buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; |
584 | goto out; | 578 | goto out; |
585 | 579 | ||
@@ -958,6 +952,8 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
958 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 952 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
959 | int err; | 953 | int err; |
960 | 954 | ||
955 | /* Flush out writes to the server in order to update c/mtime */ | ||
956 | nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT); | ||
961 | if (__IS_FLG(inode, MS_NOATIME)) | 957 | if (__IS_FLG(inode, MS_NOATIME)) |
962 | need_atime = 0; | 958 | need_atime = 0; |
963 | else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode)) | 959 | else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode)) |
@@ -1252,6 +1248,33 @@ void nfs_end_data_update(struct inode *inode) | |||
1252 | atomic_dec(&nfsi->data_updates); | 1248 | atomic_dec(&nfsi->data_updates); |
1253 | } | 1249 | } |
1254 | 1250 | ||
1251 | static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | ||
1252 | { | ||
1253 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1254 | |||
1255 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 | ||
1256 | && nfsi->change_attr == fattr->pre_change_attr) { | ||
1257 | nfsi->change_attr = fattr->change_attr; | ||
1258 | nfsi->cache_change_attribute = jiffies; | ||
1259 | } | ||
1260 | |||
1261 | /* If we have atomic WCC data, we may update some attributes */ | ||
1262 | if ((fattr->valid & NFS_ATTR_WCC) != 0) { | ||
1263 | if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) { | ||
1264 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | ||
1265 | nfsi->cache_change_attribute = jiffies; | ||
1266 | } | ||
1267 | if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { | ||
1268 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | ||
1269 | nfsi->cache_change_attribute = jiffies; | ||
1270 | } | ||
1271 | if (inode->i_size == fattr->pre_size && nfsi->npages == 0) { | ||
1272 | inode->i_size = fattr->size; | ||
1273 | nfsi->cache_change_attribute = jiffies; | ||
1274 | } | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1255 | /** | 1278 | /** |
1256 | * nfs_check_inode_attributes - verify consistency of the inode attribute cache | 1279 | * nfs_check_inode_attributes - verify consistency of the inode attribute cache |
1257 | * @inode - pointer to inode | 1280 | * @inode - pointer to inode |
@@ -1268,22 +1291,20 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
1268 | int data_unstable; | 1291 | int data_unstable; |
1269 | 1292 | ||
1270 | 1293 | ||
1294 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | ||
1295 | return 0; | ||
1296 | |||
1271 | /* Are we in the process of updating data on the server? */ | 1297 | /* Are we in the process of updating data on the server? */ |
1272 | data_unstable = nfs_caches_unstable(inode); | 1298 | data_unstable = nfs_caches_unstable(inode); |
1273 | 1299 | ||
1274 | if (fattr->valid & NFS_ATTR_FATTR_V4) { | 1300 | /* Do atomic weak cache consistency updates */ |
1275 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 | 1301 | nfs_wcc_update_inode(inode, fattr); |
1276 | && nfsi->change_attr == fattr->pre_change_attr) | ||
1277 | nfsi->change_attr = fattr->change_attr; | ||
1278 | if (nfsi->change_attr != fattr->change_attr) { | ||
1279 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
1280 | if (!data_unstable) | ||
1281 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | ||
1282 | } | ||
1283 | } | ||
1284 | 1302 | ||
1285 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) { | 1303 | if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && |
1286 | return 0; | 1304 | nfsi->change_attr != fattr->change_attr) { |
1305 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
1306 | if (!data_unstable) | ||
1307 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | ||
1287 | } | 1308 | } |
1288 | 1309 | ||
1289 | /* Has the inode gone and changed behind our back? */ | 1310 | /* Has the inode gone and changed behind our back? */ |
@@ -1295,14 +1316,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
1295 | cur_size = i_size_read(inode); | 1316 | cur_size = i_size_read(inode); |
1296 | new_isize = nfs_size_to_loff_t(fattr->size); | 1317 | new_isize = nfs_size_to_loff_t(fattr->size); |
1297 | 1318 | ||
1298 | /* If we have atomic WCC data, we may update some attributes */ | ||
1299 | if ((fattr->valid & NFS_ATTR_WCC) != 0) { | ||
1300 | if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) | ||
1301 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | ||
1302 | if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) | ||
1303 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | ||
1304 | } | ||
1305 | |||
1306 | /* Verify a few of the more important attributes */ | 1319 | /* Verify a few of the more important attributes */ |
1307 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { | 1320 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1308 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1321 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
@@ -1410,14 +1423,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1410 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1423 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
1411 | return 0; | 1424 | return 0; |
1412 | 1425 | ||
1413 | if (nfsi->fileid != fattr->fileid) { | 1426 | if (nfsi->fileid != fattr->fileid) |
1414 | printk(KERN_ERR "%s: inode number mismatch\n" | 1427 | goto out_fileid; |
1415 | "expected (%s/0x%Lx), got (%s/0x%Lx)\n", | ||
1416 | __FUNCTION__, | ||
1417 | inode->i_sb->s_id, (long long)nfsi->fileid, | ||
1418 | inode->i_sb->s_id, (long long)fattr->fileid); | ||
1419 | goto out_err; | ||
1420 | } | ||
1421 | 1428 | ||
1422 | /* | 1429 | /* |
1423 | * Make sure the inode's type hasn't changed. | 1430 | * Make sure the inode's type hasn't changed. |
@@ -1436,6 +1443,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1436 | if (data_stable) | 1443 | if (data_stable) |
1437 | nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); | 1444 | nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); |
1438 | 1445 | ||
1446 | /* Do atomic weak cache consistency updates */ | ||
1447 | nfs_wcc_update_inode(inode, fattr); | ||
1448 | |||
1439 | /* Check if our cached file size is stale */ | 1449 | /* Check if our cached file size is stale */ |
1440 | new_isize = nfs_size_to_loff_t(fattr->size); | 1450 | new_isize = nfs_size_to_loff_t(fattr->size); |
1441 | cur_isize = i_size_read(inode); | 1451 | cur_isize = i_size_read(inode); |
@@ -1539,6 +1549,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1539 | */ | 1549 | */ |
1540 | nfs_invalidate_inode(inode); | 1550 | nfs_invalidate_inode(inode); |
1541 | return -ESTALE; | 1551 | return -ESTALE; |
1552 | |||
1553 | out_fileid: | ||
1554 | printk(KERN_ERR "NFS: server %s error: fileid changed\n" | ||
1555 | "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", | ||
1556 | NFS_SERVER(inode)->hostname, inode->i_sb->s_id, | ||
1557 | (long long)nfsi->fileid, (long long)fattr->fileid); | ||
1558 | goto out_err; | ||
1542 | } | 1559 | } |
1543 | 1560 | ||
1544 | /* | 1561 | /* |
@@ -1820,25 +1837,10 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1820 | } | 1837 | } |
1821 | clnt->cl_intr = 1; | 1838 | clnt->cl_intr = 1; |
1822 | clnt->cl_softrtry = 1; | 1839 | clnt->cl_softrtry = 1; |
1823 | clnt->cl_chatty = 1; | ||
1824 | clp->cl_rpcclient = clnt; | 1840 | clp->cl_rpcclient = clnt; |
1825 | clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0); | ||
1826 | if (IS_ERR(clp->cl_cred)) { | ||
1827 | up_write(&clp->cl_sem); | ||
1828 | err = PTR_ERR(clp->cl_cred); | ||
1829 | clp->cl_cred = NULL; | ||
1830 | goto out_fail; | ||
1831 | } | ||
1832 | memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); | 1841 | memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); |
1833 | nfs_idmap_new(clp); | 1842 | nfs_idmap_new(clp); |
1834 | } | 1843 | } |
1835 | if (list_empty(&clp->cl_superblocks)) { | ||
1836 | err = nfs4_init_client(clp); | ||
1837 | if (err != 0) { | ||
1838 | up_write(&clp->cl_sem); | ||
1839 | goto out_fail; | ||
1840 | } | ||
1841 | } | ||
1842 | list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); | 1844 | list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); |
1843 | clnt = rpc_clone_client(clp->cl_rpcclient); | 1845 | clnt = rpc_clone_client(clp->cl_rpcclient); |
1844 | if (!IS_ERR(clnt)) | 1846 | if (!IS_ERR(clnt)) |
@@ -2033,6 +2035,35 @@ static struct file_system_type nfs4_fs_type = { | |||
2033 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 2035 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
2034 | }; | 2036 | }; |
2035 | 2037 | ||
2038 | static const int nfs_set_port_min = 0; | ||
2039 | static const int nfs_set_port_max = 65535; | ||
2040 | static int param_set_port(const char *val, struct kernel_param *kp) | ||
2041 | { | ||
2042 | char *endp; | ||
2043 | int num = simple_strtol(val, &endp, 0); | ||
2044 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | ||
2045 | return -EINVAL; | ||
2046 | *((int *)kp->arg) = num; | ||
2047 | return 0; | ||
2048 | } | ||
2049 | |||
2050 | module_param_call(callback_tcpport, param_set_port, param_get_int, | ||
2051 | &nfs_callback_set_tcpport, 0644); | ||
2052 | |||
2053 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
2054 | { | ||
2055 | char *endp; | ||
2056 | int num = simple_strtol(val, &endp, 0); | ||
2057 | int jif = num * HZ; | ||
2058 | if (endp == val || *endp || num < 0 || jif < num) | ||
2059 | return -EINVAL; | ||
2060 | *((int *)kp->arg) = jif; | ||
2061 | return 0; | ||
2062 | } | ||
2063 | |||
2064 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
2065 | &nfs_idmap_cache_timeout, 0644); | ||
2066 | |||
2036 | #define nfs4_init_once(nfsi) \ | 2067 | #define nfs4_init_once(nfsi) \ |
2037 | do { \ | 2068 | do { \ |
2038 | INIT_LIST_HEAD(&(nfsi)->open_states); \ | 2069 | INIT_LIST_HEAD(&(nfsi)->open_states); \ |
@@ -2040,8 +2071,25 @@ static struct file_system_type nfs4_fs_type = { | |||
2040 | nfsi->delegation_state = 0; \ | 2071 | nfsi->delegation_state = 0; \ |
2041 | init_rwsem(&nfsi->rwsem); \ | 2072 | init_rwsem(&nfsi->rwsem); \ |
2042 | } while(0) | 2073 | } while(0) |
2043 | #define register_nfs4fs() register_filesystem(&nfs4_fs_type) | 2074 | |
2044 | #define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type) | 2075 | static inline int register_nfs4fs(void) |
2076 | { | ||
2077 | int ret; | ||
2078 | |||
2079 | ret = nfs_register_sysctl(); | ||
2080 | if (ret != 0) | ||
2081 | return ret; | ||
2082 | ret = register_filesystem(&nfs4_fs_type); | ||
2083 | if (ret != 0) | ||
2084 | nfs_unregister_sysctl(); | ||
2085 | return ret; | ||
2086 | } | ||
2087 | |||
2088 | static inline void unregister_nfs4fs(void) | ||
2089 | { | ||
2090 | unregister_filesystem(&nfs4_fs_type); | ||
2091 | nfs_unregister_sysctl(); | ||
2092 | } | ||
2045 | #else | 2093 | #else |
2046 | #define nfs4_init_once(nfsi) \ | 2094 | #define nfs4_init_once(nfsi) \ |
2047 | do { } while (0) | 2095 | do { } while (0) |
@@ -2166,11 +2214,11 @@ out: | |||
2166 | #ifdef CONFIG_PROC_FS | 2214 | #ifdef CONFIG_PROC_FS |
2167 | rpc_proc_unregister("nfs"); | 2215 | rpc_proc_unregister("nfs"); |
2168 | #endif | 2216 | #endif |
2169 | nfs_destroy_writepagecache(); | ||
2170 | #ifdef CONFIG_NFS_DIRECTIO | 2217 | #ifdef CONFIG_NFS_DIRECTIO |
2171 | out0: | ||
2172 | nfs_destroy_directcache(); | 2218 | nfs_destroy_directcache(); |
2219 | out0: | ||
2173 | #endif | 2220 | #endif |
2221 | nfs_destroy_writepagecache(); | ||
2174 | out1: | 2222 | out1: |
2175 | nfs_destroy_readpagecache(); | 2223 | nfs_destroy_readpagecache(); |
2176 | out2: | 2224 | out2: |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 0e82617f2de0..db99b8f678f8 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -82,7 +82,6 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | |||
82 | RPC_AUTH_UNIX); | 82 | RPC_AUTH_UNIX); |
83 | if (!IS_ERR(clnt)) { | 83 | if (!IS_ERR(clnt)) { |
84 | clnt->cl_softrtry = 1; | 84 | clnt->cl_softrtry = 1; |
85 | clnt->cl_chatty = 1; | ||
86 | clnt->cl_oneshot = 1; | 85 | clnt->cl_oneshot = 1; |
87 | clnt->cl_intr = 1; | 86 | clnt->cl_intr = 1; |
88 | } | 87 | } |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 59049e864ca7..7fc0560c89c9 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -146,23 +146,23 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) | |||
146 | return p; | 146 | return p; |
147 | } | 147 | } |
148 | 148 | ||
149 | #define SATTR(p, attr, flag, field) \ | ||
150 | *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0 | ||
151 | static inline u32 * | 149 | static inline u32 * |
152 | xdr_encode_sattr(u32 *p, struct iattr *attr) | 150 | xdr_encode_sattr(u32 *p, struct iattr *attr) |
153 | { | 151 | { |
154 | SATTR(p, attr, ATTR_MODE, ia_mode); | 152 | const u32 not_set = __constant_htonl(0xFFFFFFFF); |
155 | SATTR(p, attr, ATTR_UID, ia_uid); | 153 | |
156 | SATTR(p, attr, ATTR_GID, ia_gid); | 154 | *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set; |
157 | SATTR(p, attr, ATTR_SIZE, ia_size); | 155 | *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set; |
156 | *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set; | ||
157 | *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set; | ||
158 | 158 | ||
159 | if (attr->ia_valid & ATTR_ATIME_SET) { | 159 | if (attr->ia_valid & ATTR_ATIME_SET) { |
160 | p = xdr_encode_time(p, &attr->ia_atime); | 160 | p = xdr_encode_time(p, &attr->ia_atime); |
161 | } else if (attr->ia_valid & ATTR_ATIME) { | 161 | } else if (attr->ia_valid & ATTR_ATIME) { |
162 | p = xdr_encode_current_server_time(p, &attr->ia_atime); | 162 | p = xdr_encode_current_server_time(p, &attr->ia_atime); |
163 | } else { | 163 | } else { |
164 | *p++ = ~(u32) 0; | 164 | *p++ = not_set; |
165 | *p++ = ~(u32) 0; | 165 | *p++ = not_set; |
166 | } | 166 | } |
167 | 167 | ||
168 | if (attr->ia_valid & ATTR_MTIME_SET) { | 168 | if (attr->ia_valid & ATTR_MTIME_SET) { |
@@ -170,12 +170,11 @@ xdr_encode_sattr(u32 *p, struct iattr *attr) | |||
170 | } else if (attr->ia_valid & ATTR_MTIME) { | 170 | } else if (attr->ia_valid & ATTR_MTIME) { |
171 | p = xdr_encode_current_server_time(p, &attr->ia_mtime); | 171 | p = xdr_encode_current_server_time(p, &attr->ia_mtime); |
172 | } else { | 172 | } else { |
173 | *p++ = ~(u32) 0; | 173 | *p++ = not_set; |
174 | *p++ = ~(u32) 0; | 174 | *p++ = not_set; |
175 | } | 175 | } |
176 | return p; | 176 | return p; |
177 | } | 177 | } |
178 | #undef SATTR | ||
179 | 178 | ||
180 | /* | 179 | /* |
181 | * NFS encode functions | 180 | * NFS encode functions |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 92c870d19ccd..ed67567f0556 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -68,27 +68,39 @@ nfs3_async_handle_jukebox(struct rpc_task *task) | |||
68 | return 1; | 68 | return 1; |
69 | } | 69 | } |
70 | 70 | ||
71 | /* | ||
72 | * Bare-bones access to getattr: this is for nfs_read_super. | ||
73 | */ | ||
74 | static int | 71 | static int |
75 | nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 72 | do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, |
76 | struct nfs_fsinfo *info) | 73 | struct nfs_fsinfo *info) |
77 | { | 74 | { |
78 | int status; | 75 | int status; |
79 | 76 | ||
80 | dprintk("%s: call fsinfo\n", __FUNCTION__); | 77 | dprintk("%s: call fsinfo\n", __FUNCTION__); |
81 | nfs_fattr_init(info->fattr); | 78 | nfs_fattr_init(info->fattr); |
82 | status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); | 79 | status = rpc_call(client, NFS3PROC_FSINFO, fhandle, info, 0); |
83 | dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); | 80 | dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); |
84 | if (!(info->fattr->valid & NFS_ATTR_FATTR)) { | 81 | if (!(info->fattr->valid & NFS_ATTR_FATTR)) { |
85 | status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0); | 82 | status = rpc_call(client, NFS3PROC_GETATTR, fhandle, info->fattr, 0); |
86 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); | 83 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); |
87 | } | 84 | } |
88 | return status; | 85 | return status; |
89 | } | 86 | } |
90 | 87 | ||
91 | /* | 88 | /* |
89 | * Bare-bones access to getattr: this is for nfs_read_super. | ||
90 | */ | ||
91 | static int | ||
92 | nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | ||
93 | struct nfs_fsinfo *info) | ||
94 | { | ||
95 | int status; | ||
96 | |||
97 | status = do_proc_get_root(server->client, fhandle, info); | ||
98 | if (status && server->client_sys != server->client) | ||
99 | status = do_proc_get_root(server->client_sys, fhandle, info); | ||
100 | return status; | ||
101 | } | ||
102 | |||
103 | /* | ||
92 | * One function for each procedure in the NFS protocol. | 104 | * One function for each procedure in the NFS protocol. |
93 | */ | 105 | */ |
94 | static int | 106 | static int |
@@ -732,19 +744,23 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
732 | 744 | ||
733 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); | 745 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); |
734 | 746 | ||
735 | static void | 747 | static void nfs3_read_done(struct rpc_task *task, void *calldata) |
736 | nfs3_read_done(struct rpc_task *task) | ||
737 | { | 748 | { |
738 | struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; | 749 | struct nfs_read_data *data = calldata; |
739 | 750 | ||
740 | if (nfs3_async_handle_jukebox(task)) | 751 | if (nfs3_async_handle_jukebox(task)) |
741 | return; | 752 | return; |
742 | /* Call back common NFS readpage processing */ | 753 | /* Call back common NFS readpage processing */ |
743 | if (task->tk_status >= 0) | 754 | if (task->tk_status >= 0) |
744 | nfs_refresh_inode(data->inode, &data->fattr); | 755 | nfs_refresh_inode(data->inode, &data->fattr); |
745 | nfs_readpage_result(task); | 756 | nfs_readpage_result(task, calldata); |
746 | } | 757 | } |
747 | 758 | ||
759 | static const struct rpc_call_ops nfs3_read_ops = { | ||
760 | .rpc_call_done = nfs3_read_done, | ||
761 | .rpc_release = nfs_readdata_release, | ||
762 | }; | ||
763 | |||
748 | static void | 764 | static void |
749 | nfs3_proc_read_setup(struct nfs_read_data *data) | 765 | nfs3_proc_read_setup(struct nfs_read_data *data) |
750 | { | 766 | { |
@@ -762,23 +778,26 @@ nfs3_proc_read_setup(struct nfs_read_data *data) | |||
762 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 778 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
763 | 779 | ||
764 | /* Finalize the task. */ | 780 | /* Finalize the task. */ |
765 | rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags); | 781 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_read_ops, data); |
766 | rpc_call_setup(task, &msg, 0); | 782 | rpc_call_setup(task, &msg, 0); |
767 | } | 783 | } |
768 | 784 | ||
769 | static void | 785 | static void nfs3_write_done(struct rpc_task *task, void *calldata) |
770 | nfs3_write_done(struct rpc_task *task) | ||
771 | { | 786 | { |
772 | struct nfs_write_data *data; | 787 | struct nfs_write_data *data = calldata; |
773 | 788 | ||
774 | if (nfs3_async_handle_jukebox(task)) | 789 | if (nfs3_async_handle_jukebox(task)) |
775 | return; | 790 | return; |
776 | data = (struct nfs_write_data *)task->tk_calldata; | ||
777 | if (task->tk_status >= 0) | 791 | if (task->tk_status >= 0) |
778 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 792 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
779 | nfs_writeback_done(task); | 793 | nfs_writeback_done(task, calldata); |
780 | } | 794 | } |
781 | 795 | ||
796 | static const struct rpc_call_ops nfs3_write_ops = { | ||
797 | .rpc_call_done = nfs3_write_done, | ||
798 | .rpc_release = nfs_writedata_release, | ||
799 | }; | ||
800 | |||
782 | static void | 801 | static void |
783 | nfs3_proc_write_setup(struct nfs_write_data *data, int how) | 802 | nfs3_proc_write_setup(struct nfs_write_data *data, int how) |
784 | { | 803 | { |
@@ -806,23 +825,26 @@ nfs3_proc_write_setup(struct nfs_write_data *data, int how) | |||
806 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 825 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
807 | 826 | ||
808 | /* Finalize the task. */ | 827 | /* Finalize the task. */ |
809 | rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags); | 828 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_write_ops, data); |
810 | rpc_call_setup(task, &msg, 0); | 829 | rpc_call_setup(task, &msg, 0); |
811 | } | 830 | } |
812 | 831 | ||
813 | static void | 832 | static void nfs3_commit_done(struct rpc_task *task, void *calldata) |
814 | nfs3_commit_done(struct rpc_task *task) | ||
815 | { | 833 | { |
816 | struct nfs_write_data *data; | 834 | struct nfs_write_data *data = calldata; |
817 | 835 | ||
818 | if (nfs3_async_handle_jukebox(task)) | 836 | if (nfs3_async_handle_jukebox(task)) |
819 | return; | 837 | return; |
820 | data = (struct nfs_write_data *)task->tk_calldata; | ||
821 | if (task->tk_status >= 0) | 838 | if (task->tk_status >= 0) |
822 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 839 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
823 | nfs_commit_done(task); | 840 | nfs_commit_done(task, calldata); |
824 | } | 841 | } |
825 | 842 | ||
843 | static const struct rpc_call_ops nfs3_commit_ops = { | ||
844 | .rpc_call_done = nfs3_commit_done, | ||
845 | .rpc_release = nfs_commit_release, | ||
846 | }; | ||
847 | |||
826 | static void | 848 | static void |
827 | nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | 849 | nfs3_proc_commit_setup(struct nfs_write_data *data, int how) |
828 | { | 850 | { |
@@ -840,7 +862,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | |||
840 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 862 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
841 | 863 | ||
842 | /* Finalize the task. */ | 864 | /* Finalize the task. */ |
843 | rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags); | 865 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_commit_ops, data); |
844 | rpc_call_setup(task, &msg, 0); | 866 | rpc_call_setup(task, &msg, 0); |
845 | } | 867 | } |
846 | 868 | ||
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 0498bd36602c..b6c0b5012bce 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -182,7 +182,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr) | |||
182 | { | 182 | { |
183 | if (attr->ia_valid & ATTR_MODE) { | 183 | if (attr->ia_valid & ATTR_MODE) { |
184 | *p++ = xdr_one; | 184 | *p++ = xdr_one; |
185 | *p++ = htonl(attr->ia_mode); | 185 | *p++ = htonl(attr->ia_mode & S_IALLUGO); |
186 | } else { | 186 | } else { |
187 | *p++ = xdr_zero; | 187 | *p++ = xdr_zero; |
188 | } | 188 | } |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index b7f262dcb6e3..0f5e4e7cddec 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -38,7 +38,8 @@ struct idmap; | |||
38 | ((err) != NFSERR_NOFILEHANDLE)) | 38 | ((err) != NFSERR_NOFILEHANDLE)) |
39 | 39 | ||
40 | enum nfs4_client_state { | 40 | enum nfs4_client_state { |
41 | NFS4CLNT_OK = 0, | 41 | NFS4CLNT_STATE_RECOVER = 0, |
42 | NFS4CLNT_LEASE_EXPIRED, | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | /* | 45 | /* |
@@ -67,7 +68,6 @@ struct nfs4_client { | |||
67 | atomic_t cl_count; | 68 | atomic_t cl_count; |
68 | 69 | ||
69 | struct rpc_clnt * cl_rpcclient; | 70 | struct rpc_clnt * cl_rpcclient; |
70 | struct rpc_cred * cl_cred; | ||
71 | 71 | ||
72 | struct list_head cl_superblocks; /* List of nfs_server structs */ | 72 | struct list_head cl_superblocks; /* List of nfs_server structs */ |
73 | 73 | ||
@@ -76,7 +76,6 @@ struct nfs4_client { | |||
76 | struct work_struct cl_renewd; | 76 | struct work_struct cl_renewd; |
77 | struct work_struct cl_recoverd; | 77 | struct work_struct cl_recoverd; |
78 | 78 | ||
79 | wait_queue_head_t cl_waitq; | ||
80 | struct rpc_wait_queue cl_rpcwaitq; | 79 | struct rpc_wait_queue cl_rpcwaitq; |
81 | 80 | ||
82 | /* used for the setclientid verifier */ | 81 | /* used for the setclientid verifier */ |
@@ -182,8 +181,9 @@ struct nfs4_state { | |||
182 | 181 | ||
183 | nfs4_stateid stateid; | 182 | nfs4_stateid stateid; |
184 | 183 | ||
185 | unsigned int nreaders; | 184 | unsigned int n_rdonly; |
186 | unsigned int nwriters; | 185 | unsigned int n_wronly; |
186 | unsigned int n_rdwr; | ||
187 | int state; /* State on the server (R,W, or RW) */ | 187 | int state; /* State on the server (R,W, or RW) */ |
188 | atomic_t count; | 188 | atomic_t count; |
189 | }; | 189 | }; |
@@ -210,10 +210,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
210 | 210 | ||
211 | /* nfs4proc.c */ | 211 | /* nfs4proc.c */ |
212 | extern int nfs4_map_errors(int err); | 212 | extern int nfs4_map_errors(int err); |
213 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); | 213 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *); |
214 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); | 214 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *); |
215 | extern int nfs4_proc_async_renew(struct nfs4_client *); | 215 | extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *); |
216 | extern int nfs4_proc_renew(struct nfs4_client *); | 216 | extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *); |
217 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); | 217 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); |
218 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 218 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
219 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 219 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -237,8 +237,8 @@ extern void init_nfsv4_state(struct nfs_server *); | |||
237 | extern void destroy_nfsv4_state(struct nfs_server *); | 237 | extern void destroy_nfsv4_state(struct nfs_server *); |
238 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | 238 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); |
239 | extern void nfs4_put_client(struct nfs4_client *clp); | 239 | extern void nfs4_put_client(struct nfs4_client *clp); |
240 | extern int nfs4_init_client(struct nfs4_client *clp); | ||
241 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | 240 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); |
241 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp); | ||
242 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | 242 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); |
243 | 243 | ||
244 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 244 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f988a9417b13..984ca3454d04 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -57,11 +57,13 @@ | |||
57 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 57 | #define NFS4_POLL_RETRY_MIN (1*HZ) |
58 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 58 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
59 | 59 | ||
60 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); | 60 | struct nfs4_opendata; |
61 | static int _nfs4_proc_open(struct nfs4_opendata *data); | ||
61 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 62 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
62 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 63 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
63 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 64 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
64 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 65 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
66 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); | ||
65 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 67 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
66 | extern struct rpc_procinfo nfs4_procedures[]; | 68 | extern struct rpc_procinfo nfs4_procedures[]; |
67 | 69 | ||
@@ -173,8 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
173 | kunmap_atomic(start, KM_USER0); | 175 | kunmap_atomic(start, KM_USER0); |
174 | } | 176 | } |
175 | 177 | ||
176 | static void | 178 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
177 | renew_lease(struct nfs_server *server, unsigned long timestamp) | ||
178 | { | 179 | { |
179 | struct nfs4_client *clp = server->nfs4_state; | 180 | struct nfs4_client *clp = server->nfs4_state; |
180 | spin_lock(&clp->cl_lock); | 181 | spin_lock(&clp->cl_lock); |
@@ -194,21 +195,123 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf | |||
194 | spin_unlock(&inode->i_lock); | 195 | spin_unlock(&inode->i_lock); |
195 | } | 196 | } |
196 | 197 | ||
198 | struct nfs4_opendata { | ||
199 | atomic_t count; | ||
200 | struct nfs_openargs o_arg; | ||
201 | struct nfs_openres o_res; | ||
202 | struct nfs_open_confirmargs c_arg; | ||
203 | struct nfs_open_confirmres c_res; | ||
204 | struct nfs_fattr f_attr; | ||
205 | struct nfs_fattr dir_attr; | ||
206 | struct dentry *dentry; | ||
207 | struct dentry *dir; | ||
208 | struct nfs4_state_owner *owner; | ||
209 | struct iattr attrs; | ||
210 | unsigned long timestamp; | ||
211 | int rpc_status; | ||
212 | int cancelled; | ||
213 | }; | ||
214 | |||
215 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | ||
216 | struct nfs4_state_owner *sp, int flags, | ||
217 | const struct iattr *attrs) | ||
218 | { | ||
219 | struct dentry *parent = dget_parent(dentry); | ||
220 | struct inode *dir = parent->d_inode; | ||
221 | struct nfs_server *server = NFS_SERVER(dir); | ||
222 | struct nfs4_opendata *p; | ||
223 | |||
224 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
225 | if (p == NULL) | ||
226 | goto err; | ||
227 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
228 | if (p->o_arg.seqid == NULL) | ||
229 | goto err_free; | ||
230 | atomic_set(&p->count, 1); | ||
231 | p->dentry = dget(dentry); | ||
232 | p->dir = parent; | ||
233 | p->owner = sp; | ||
234 | atomic_inc(&sp->so_count); | ||
235 | p->o_arg.fh = NFS_FH(dir); | ||
236 | p->o_arg.open_flags = flags, | ||
237 | p->o_arg.clientid = server->nfs4_state->cl_clientid; | ||
238 | p->o_arg.id = sp->so_id; | ||
239 | p->o_arg.name = &dentry->d_name; | ||
240 | p->o_arg.server = server; | ||
241 | p->o_arg.bitmask = server->attr_bitmask; | ||
242 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | ||
243 | p->o_res.f_attr = &p->f_attr; | ||
244 | p->o_res.dir_attr = &p->dir_attr; | ||
245 | p->o_res.server = server; | ||
246 | nfs_fattr_init(&p->f_attr); | ||
247 | nfs_fattr_init(&p->dir_attr); | ||
248 | if (flags & O_EXCL) { | ||
249 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
250 | s[0] = jiffies; | ||
251 | s[1] = current->pid; | ||
252 | } else if (flags & O_CREAT) { | ||
253 | p->o_arg.u.attrs = &p->attrs; | ||
254 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
255 | } | ||
256 | p->c_arg.fh = &p->o_res.fh; | ||
257 | p->c_arg.stateid = &p->o_res.stateid; | ||
258 | p->c_arg.seqid = p->o_arg.seqid; | ||
259 | return p; | ||
260 | err_free: | ||
261 | kfree(p); | ||
262 | err: | ||
263 | dput(parent); | ||
264 | return NULL; | ||
265 | } | ||
266 | |||
267 | static void nfs4_opendata_free(struct nfs4_opendata *p) | ||
268 | { | ||
269 | if (p != NULL && atomic_dec_and_test(&p->count)) { | ||
270 | nfs_free_seqid(p->o_arg.seqid); | ||
271 | nfs4_put_state_owner(p->owner); | ||
272 | dput(p->dir); | ||
273 | dput(p->dentry); | ||
274 | kfree(p); | ||
275 | } | ||
276 | } | ||
277 | |||
197 | /* Helper for asynchronous RPC calls */ | 278 | /* Helper for asynchronous RPC calls */ |
198 | static int nfs4_call_async(struct rpc_clnt *clnt, rpc_action tk_begin, | 279 | static int nfs4_call_async(struct rpc_clnt *clnt, |
199 | rpc_action tk_exit, void *calldata) | 280 | const struct rpc_call_ops *tk_ops, void *calldata) |
200 | { | 281 | { |
201 | struct rpc_task *task; | 282 | struct rpc_task *task; |
202 | 283 | ||
203 | if (!(task = rpc_new_task(clnt, tk_exit, RPC_TASK_ASYNC))) | 284 | if (!(task = rpc_new_task(clnt, RPC_TASK_ASYNC, tk_ops, calldata))) |
204 | return -ENOMEM; | 285 | return -ENOMEM; |
205 | |||
206 | task->tk_calldata = calldata; | ||
207 | task->tk_action = tk_begin; | ||
208 | rpc_execute(task); | 286 | rpc_execute(task); |
209 | return 0; | 287 | return 0; |
210 | } | 288 | } |
211 | 289 | ||
290 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | ||
291 | { | ||
292 | sigset_t oldset; | ||
293 | int ret; | ||
294 | |||
295 | rpc_clnt_sigmask(task->tk_client, &oldset); | ||
296 | ret = rpc_wait_for_completion_task(task); | ||
297 | rpc_clnt_sigunmask(task->tk_client, &oldset); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | ||
302 | { | ||
303 | switch (open_flags) { | ||
304 | case FMODE_WRITE: | ||
305 | state->n_wronly++; | ||
306 | break; | ||
307 | case FMODE_READ: | ||
308 | state->n_rdonly++; | ||
309 | break; | ||
310 | case FMODE_READ|FMODE_WRITE: | ||
311 | state->n_rdwr++; | ||
312 | } | ||
313 | } | ||
314 | |||
212 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 315 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
213 | { | 316 | { |
214 | struct inode *inode = state->inode; | 317 | struct inode *inode = state->inode; |
@@ -218,41 +321,134 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, | |||
218 | spin_lock(&state->owner->so_lock); | 321 | spin_lock(&state->owner->so_lock); |
219 | spin_lock(&inode->i_lock); | 322 | spin_lock(&inode->i_lock); |
220 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); | 323 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); |
221 | if ((open_flags & FMODE_WRITE)) | 324 | update_open_stateflags(state, open_flags); |
222 | state->nwriters++; | ||
223 | if (open_flags & FMODE_READ) | ||
224 | state->nreaders++; | ||
225 | nfs4_state_set_mode_locked(state, state->state | open_flags); | 325 | nfs4_state_set_mode_locked(state, state->state | open_flags); |
226 | spin_unlock(&inode->i_lock); | 326 | spin_unlock(&inode->i_lock); |
227 | spin_unlock(&state->owner->so_lock); | 327 | spin_unlock(&state->owner->so_lock); |
228 | } | 328 | } |
229 | 329 | ||
330 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | ||
331 | { | ||
332 | struct inode *inode; | ||
333 | struct nfs4_state *state = NULL; | ||
334 | |||
335 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | ||
336 | goto out; | ||
337 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | ||
338 | if (inode == NULL) | ||
339 | goto out; | ||
340 | state = nfs4_get_open_state(inode, data->owner); | ||
341 | if (state == NULL) | ||
342 | goto put_inode; | ||
343 | update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); | ||
344 | put_inode: | ||
345 | iput(inode); | ||
346 | out: | ||
347 | return state; | ||
348 | } | ||
349 | |||
350 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) | ||
351 | { | ||
352 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
353 | struct nfs_open_context *ctx; | ||
354 | |||
355 | spin_lock(&state->inode->i_lock); | ||
356 | list_for_each_entry(ctx, &nfsi->open_files, list) { | ||
357 | if (ctx->state != state) | ||
358 | continue; | ||
359 | get_nfs_open_context(ctx); | ||
360 | spin_unlock(&state->inode->i_lock); | ||
361 | return ctx; | ||
362 | } | ||
363 | spin_unlock(&state->inode->i_lock); | ||
364 | return ERR_PTR(-ENOENT); | ||
365 | } | ||
366 | |||
367 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) | ||
368 | { | ||
369 | int ret; | ||
370 | |||
371 | opendata->o_arg.open_flags = openflags; | ||
372 | ret = _nfs4_proc_open(opendata); | ||
373 | if (ret != 0) | ||
374 | return ret; | ||
375 | memcpy(stateid->data, opendata->o_res.stateid.data, | ||
376 | sizeof(stateid->data)); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | ||
381 | { | ||
382 | nfs4_stateid stateid; | ||
383 | struct nfs4_state *newstate; | ||
384 | int mode = 0; | ||
385 | int delegation = 0; | ||
386 | int ret; | ||
387 | |||
388 | /* memory barrier prior to reading state->n_* */ | ||
389 | smp_rmb(); | ||
390 | if (state->n_rdwr != 0) { | ||
391 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); | ||
392 | if (ret != 0) | ||
393 | return ret; | ||
394 | mode |= FMODE_READ|FMODE_WRITE; | ||
395 | if (opendata->o_res.delegation_type != 0) | ||
396 | delegation = opendata->o_res.delegation_type; | ||
397 | smp_rmb(); | ||
398 | } | ||
399 | if (state->n_wronly != 0) { | ||
400 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); | ||
401 | if (ret != 0) | ||
402 | return ret; | ||
403 | mode |= FMODE_WRITE; | ||
404 | if (opendata->o_res.delegation_type != 0) | ||
405 | delegation = opendata->o_res.delegation_type; | ||
406 | smp_rmb(); | ||
407 | } | ||
408 | if (state->n_rdonly != 0) { | ||
409 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); | ||
410 | if (ret != 0) | ||
411 | return ret; | ||
412 | mode |= FMODE_READ; | ||
413 | } | ||
414 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
415 | if (mode == 0) | ||
416 | return 0; | ||
417 | if (opendata->o_res.delegation_type == 0) | ||
418 | opendata->o_res.delegation_type = delegation; | ||
419 | opendata->o_arg.open_flags |= mode; | ||
420 | newstate = nfs4_opendata_to_nfs4_state(opendata); | ||
421 | if (newstate != NULL) { | ||
422 | if (opendata->o_res.delegation_type != 0) { | ||
423 | struct nfs_inode *nfsi = NFS_I(newstate->inode); | ||
424 | int delegation_flags = 0; | ||
425 | if (nfsi->delegation) | ||
426 | delegation_flags = nfsi->delegation->flags; | ||
427 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
428 | nfs_inode_set_delegation(newstate->inode, | ||
429 | opendata->owner->so_cred, | ||
430 | &opendata->o_res); | ||
431 | else | ||
432 | nfs_inode_reclaim_delegation(newstate->inode, | ||
433 | opendata->owner->so_cred, | ||
434 | &opendata->o_res); | ||
435 | } | ||
436 | nfs4_close_state(newstate, opendata->o_arg.open_flags); | ||
437 | } | ||
438 | if (newstate != state) | ||
439 | return -ESTALE; | ||
440 | return 0; | ||
441 | } | ||
442 | |||
230 | /* | 443 | /* |
231 | * OPEN_RECLAIM: | 444 | * OPEN_RECLAIM: |
232 | * reclaim state on the server after a reboot. | 445 | * reclaim state on the server after a reboot. |
233 | */ | 446 | */ |
234 | static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | 447 | static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
235 | { | 448 | { |
236 | struct inode *inode = state->inode; | 449 | struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; |
237 | struct nfs_server *server = NFS_SERVER(inode); | 450 | struct nfs4_opendata *opendata; |
238 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 451 | int delegation_type = 0; |
239 | struct nfs_openargs o_arg = { | ||
240 | .fh = NFS_FH(inode), | ||
241 | .id = sp->so_id, | ||
242 | .open_flags = state->state, | ||
243 | .clientid = server->nfs4_state->cl_clientid, | ||
244 | .claim = NFS4_OPEN_CLAIM_PREVIOUS, | ||
245 | .bitmask = server->attr_bitmask, | ||
246 | }; | ||
247 | struct nfs_openres o_res = { | ||
248 | .server = server, /* Grrr */ | ||
249 | }; | ||
250 | struct rpc_message msg = { | ||
251 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], | ||
252 | .rpc_argp = &o_arg, | ||
253 | .rpc_resp = &o_res, | ||
254 | .rpc_cred = sp->so_cred, | ||
255 | }; | ||
256 | int status; | 452 | int status; |
257 | 453 | ||
258 | if (delegation != NULL) { | 454 | if (delegation != NULL) { |
@@ -262,38 +458,27 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
262 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 458 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
263 | return 0; | 459 | return 0; |
264 | } | 460 | } |
265 | o_arg.u.delegation_type = delegation->type; | 461 | delegation_type = delegation->type; |
266 | } | 462 | } |
267 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 463 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); |
268 | if (o_arg.seqid == NULL) | 464 | if (opendata == NULL) |
269 | return -ENOMEM; | 465 | return -ENOMEM; |
270 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 466 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; |
271 | /* Confirm the sequence as being established */ | 467 | opendata->o_arg.fh = NFS_FH(state->inode); |
272 | nfs_confirm_seqid(&sp->so_seqid, status); | 468 | nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); |
273 | nfs_increment_open_seqid(status, o_arg.seqid); | 469 | opendata->o_arg.u.delegation_type = delegation_type; |
274 | if (status == 0) { | 470 | status = nfs4_open_recover(opendata, state); |
275 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); | 471 | nfs4_opendata_free(opendata); |
276 | if (o_res.delegation_type != 0) { | ||
277 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); | ||
278 | /* Did the server issue an immediate delegation recall? */ | ||
279 | if (o_res.do_recall) | ||
280 | nfs_async_inode_return_delegation(inode, &o_res.stateid); | ||
281 | } | ||
282 | } | ||
283 | nfs_free_seqid(o_arg.seqid); | ||
284 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
285 | /* Ensure we update the inode attributes */ | ||
286 | NFS_CACHEINV(inode); | ||
287 | return status; | 472 | return status; |
288 | } | 473 | } |
289 | 474 | ||
290 | static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | 475 | static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
291 | { | 476 | { |
292 | struct nfs_server *server = NFS_SERVER(state->inode); | 477 | struct nfs_server *server = NFS_SERVER(state->inode); |
293 | struct nfs4_exception exception = { }; | 478 | struct nfs4_exception exception = { }; |
294 | int err; | 479 | int err; |
295 | do { | 480 | do { |
296 | err = _nfs4_open_reclaim(sp, state); | 481 | err = _nfs4_do_open_reclaim(sp, state, dentry); |
297 | if (err != -NFS4ERR_DELAY) | 482 | if (err != -NFS4ERR_DELAY) |
298 | break; | 483 | break; |
299 | nfs4_handle_exception(server, err, &exception); | 484 | nfs4_handle_exception(server, err, &exception); |
@@ -301,63 +486,36 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
301 | return err; | 486 | return err; |
302 | } | 487 | } |
303 | 488 | ||
489 | static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | ||
490 | { | ||
491 | struct nfs_open_context *ctx; | ||
492 | int ret; | ||
493 | |||
494 | ctx = nfs4_state_find_open_context(state); | ||
495 | if (IS_ERR(ctx)) | ||
496 | return PTR_ERR(ctx); | ||
497 | ret = nfs4_do_open_reclaim(sp, state, ctx->dentry); | ||
498 | put_nfs_open_context(ctx); | ||
499 | return ret; | ||
500 | } | ||
501 | |||
304 | static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 502 | static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) |
305 | { | 503 | { |
306 | struct nfs4_state_owner *sp = state->owner; | 504 | struct nfs4_state_owner *sp = state->owner; |
307 | struct inode *inode = dentry->d_inode; | 505 | struct nfs4_opendata *opendata; |
308 | struct nfs_server *server = NFS_SERVER(inode); | 506 | int ret; |
309 | struct dentry *parent = dget_parent(dentry); | ||
310 | struct nfs_openargs arg = { | ||
311 | .fh = NFS_FH(parent->d_inode), | ||
312 | .clientid = server->nfs4_state->cl_clientid, | ||
313 | .name = &dentry->d_name, | ||
314 | .id = sp->so_id, | ||
315 | .server = server, | ||
316 | .bitmask = server->attr_bitmask, | ||
317 | .claim = NFS4_OPEN_CLAIM_DELEGATE_CUR, | ||
318 | }; | ||
319 | struct nfs_openres res = { | ||
320 | .server = server, | ||
321 | }; | ||
322 | struct rpc_message msg = { | ||
323 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], | ||
324 | .rpc_argp = &arg, | ||
325 | .rpc_resp = &res, | ||
326 | .rpc_cred = sp->so_cred, | ||
327 | }; | ||
328 | int status = 0; | ||
329 | 507 | ||
330 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 508 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
331 | goto out; | 509 | return 0; |
332 | if (state->state == 0) | 510 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); |
333 | goto out; | 511 | if (opendata == NULL) |
334 | arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 512 | return -ENOMEM; |
335 | status = -ENOMEM; | 513 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; |
336 | if (arg.seqid == NULL) | 514 | memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, |
337 | goto out; | 515 | sizeof(opendata->o_arg.u.delegation.data)); |
338 | arg.open_flags = state->state; | 516 | ret = nfs4_open_recover(opendata, state); |
339 | memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); | 517 | nfs4_opendata_free(opendata); |
340 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 518 | return ret; |
341 | nfs_increment_open_seqid(status, arg.seqid); | ||
342 | if (status != 0) | ||
343 | goto out_free; | ||
344 | if(res.rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
345 | status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), | ||
346 | sp, &res.stateid, arg.seqid); | ||
347 | if (status != 0) | ||
348 | goto out_free; | ||
349 | } | ||
350 | nfs_confirm_seqid(&sp->so_seqid, 0); | ||
351 | if (status >= 0) { | ||
352 | memcpy(state->stateid.data, res.stateid.data, | ||
353 | sizeof(state->stateid.data)); | ||
354 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
355 | } | ||
356 | out_free: | ||
357 | nfs_free_seqid(arg.seqid); | ||
358 | out: | ||
359 | dput(parent); | ||
360 | return status; | ||
361 | } | 519 | } |
362 | 520 | ||
363 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 521 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) |
@@ -382,82 +540,202 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
382 | return err; | 540 | return err; |
383 | } | 541 | } |
384 | 542 | ||
385 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid) | 543 | static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) |
386 | { | 544 | { |
387 | struct nfs_open_confirmargs arg = { | 545 | struct nfs4_opendata *data = calldata; |
388 | .fh = fh, | 546 | struct rpc_message msg = { |
389 | .seqid = seqid, | 547 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], |
390 | .stateid = *stateid, | 548 | .rpc_argp = &data->c_arg, |
391 | }; | 549 | .rpc_resp = &data->c_res, |
392 | struct nfs_open_confirmres res; | 550 | .rpc_cred = data->owner->so_cred, |
393 | struct rpc_message msg = { | ||
394 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
395 | .rpc_argp = &arg, | ||
396 | .rpc_resp = &res, | ||
397 | .rpc_cred = sp->so_cred, | ||
398 | }; | 551 | }; |
552 | data->timestamp = jiffies; | ||
553 | rpc_call_setup(task, &msg, 0); | ||
554 | } | ||
555 | |||
556 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | ||
557 | { | ||
558 | struct nfs4_opendata *data = calldata; | ||
559 | |||
560 | data->rpc_status = task->tk_status; | ||
561 | if (RPC_ASSASSINATED(task)) | ||
562 | return; | ||
563 | if (data->rpc_status == 0) { | ||
564 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | ||
565 | sizeof(data->o_res.stateid.data)); | ||
566 | renew_lease(data->o_res.server, data->timestamp); | ||
567 | } | ||
568 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
569 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); | ||
570 | } | ||
571 | |||
572 | static void nfs4_open_confirm_release(void *calldata) | ||
573 | { | ||
574 | struct nfs4_opendata *data = calldata; | ||
575 | struct nfs4_state *state = NULL; | ||
576 | |||
577 | /* If this request hasn't been cancelled, do nothing */ | ||
578 | if (data->cancelled == 0) | ||
579 | goto out_free; | ||
580 | /* In case of error, no cleanup! */ | ||
581 | if (data->rpc_status != 0) | ||
582 | goto out_free; | ||
583 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
584 | state = nfs4_opendata_to_nfs4_state(data); | ||
585 | if (state != NULL) | ||
586 | nfs4_close_state(state, data->o_arg.open_flags); | ||
587 | out_free: | ||
588 | nfs4_opendata_free(data); | ||
589 | } | ||
590 | |||
591 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | ||
592 | .rpc_call_prepare = nfs4_open_confirm_prepare, | ||
593 | .rpc_call_done = nfs4_open_confirm_done, | ||
594 | .rpc_release = nfs4_open_confirm_release, | ||
595 | }; | ||
596 | |||
597 | /* | ||
598 | * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata | ||
599 | */ | ||
600 | static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | ||
601 | { | ||
602 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); | ||
603 | struct rpc_task *task; | ||
399 | int status; | 604 | int status; |
400 | 605 | ||
401 | status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); | 606 | atomic_inc(&data->count); |
402 | /* Confirm the sequence as being established */ | 607 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); |
403 | nfs_confirm_seqid(&sp->so_seqid, status); | 608 | if (IS_ERR(task)) { |
404 | nfs_increment_open_seqid(status, seqid); | 609 | nfs4_opendata_free(data); |
405 | if (status >= 0) | 610 | return PTR_ERR(task); |
406 | memcpy(stateid, &res.stateid, sizeof(*stateid)); | 611 | } |
612 | status = nfs4_wait_for_completion_rpc_task(task); | ||
613 | if (status != 0) { | ||
614 | data->cancelled = 1; | ||
615 | smp_wmb(); | ||
616 | } else | ||
617 | status = data->rpc_status; | ||
618 | rpc_release_task(task); | ||
407 | return status; | 619 | return status; |
408 | } | 620 | } |
409 | 621 | ||
410 | static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res) | 622 | static void nfs4_open_prepare(struct rpc_task *task, void *calldata) |
411 | { | 623 | { |
412 | struct nfs_server *server = NFS_SERVER(dir); | 624 | struct nfs4_opendata *data = calldata; |
625 | struct nfs4_state_owner *sp = data->owner; | ||
413 | struct rpc_message msg = { | 626 | struct rpc_message msg = { |
414 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], | 627 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], |
415 | .rpc_argp = o_arg, | 628 | .rpc_argp = &data->o_arg, |
416 | .rpc_resp = o_res, | 629 | .rpc_resp = &data->o_res, |
417 | .rpc_cred = sp->so_cred, | 630 | .rpc_cred = sp->so_cred, |
418 | }; | 631 | }; |
419 | int status; | 632 | |
633 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | ||
634 | return; | ||
635 | /* Update sequence id. */ | ||
636 | data->o_arg.id = sp->so_id; | ||
637 | data->o_arg.clientid = sp->so_client->cl_clientid; | ||
638 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) | ||
639 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | ||
640 | data->timestamp = jiffies; | ||
641 | rpc_call_setup(task, &msg, 0); | ||
642 | } | ||
420 | 643 | ||
421 | /* Update sequence id. The caller must serialize! */ | 644 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
422 | o_arg->id = sp->so_id; | 645 | { |
423 | o_arg->clientid = sp->so_client->cl_clientid; | 646 | struct nfs4_opendata *data = calldata; |
424 | 647 | ||
425 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 648 | data->rpc_status = task->tk_status; |
426 | if (status == 0) { | 649 | if (RPC_ASSASSINATED(task)) |
427 | /* OPEN on anything except a regular file is disallowed in NFSv4 */ | 650 | return; |
428 | switch (o_res->f_attr->mode & S_IFMT) { | 651 | if (task->tk_status == 0) { |
652 | switch (data->o_res.f_attr->mode & S_IFMT) { | ||
429 | case S_IFREG: | 653 | case S_IFREG: |
430 | break; | 654 | break; |
431 | case S_IFLNK: | 655 | case S_IFLNK: |
432 | status = -ELOOP; | 656 | data->rpc_status = -ELOOP; |
433 | break; | 657 | break; |
434 | case S_IFDIR: | 658 | case S_IFDIR: |
435 | status = -EISDIR; | 659 | data->rpc_status = -EISDIR; |
436 | break; | 660 | break; |
437 | default: | 661 | default: |
438 | status = -ENOTDIR; | 662 | data->rpc_status = -ENOTDIR; |
439 | } | 663 | } |
664 | renew_lease(data->o_res.server, data->timestamp); | ||
440 | } | 665 | } |
666 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | ||
667 | } | ||
668 | |||
669 | static void nfs4_open_release(void *calldata) | ||
670 | { | ||
671 | struct nfs4_opendata *data = calldata; | ||
672 | struct nfs4_state *state = NULL; | ||
441 | 673 | ||
442 | nfs_increment_open_seqid(status, o_arg->seqid); | 674 | /* If this request hasn't been cancelled, do nothing */ |
675 | if (data->cancelled == 0) | ||
676 | goto out_free; | ||
677 | /* In case of error, no cleanup! */ | ||
678 | if (data->rpc_status != 0) | ||
679 | goto out_free; | ||
680 | /* In case we need an open_confirm, no cleanup! */ | ||
681 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) | ||
682 | goto out_free; | ||
683 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
684 | state = nfs4_opendata_to_nfs4_state(data); | ||
685 | if (state != NULL) | ||
686 | nfs4_close_state(state, data->o_arg.open_flags); | ||
687 | out_free: | ||
688 | nfs4_opendata_free(data); | ||
689 | } | ||
690 | |||
691 | static const struct rpc_call_ops nfs4_open_ops = { | ||
692 | .rpc_call_prepare = nfs4_open_prepare, | ||
693 | .rpc_call_done = nfs4_open_done, | ||
694 | .rpc_release = nfs4_open_release, | ||
695 | }; | ||
696 | |||
697 | /* | ||
698 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | ||
699 | */ | ||
700 | static int _nfs4_proc_open(struct nfs4_opendata *data) | ||
701 | { | ||
702 | struct inode *dir = data->dir->d_inode; | ||
703 | struct nfs_server *server = NFS_SERVER(dir); | ||
704 | struct nfs_openargs *o_arg = &data->o_arg; | ||
705 | struct nfs_openres *o_res = &data->o_res; | ||
706 | struct rpc_task *task; | ||
707 | int status; | ||
708 | |||
709 | atomic_inc(&data->count); | ||
710 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | ||
711 | if (IS_ERR(task)) { | ||
712 | nfs4_opendata_free(data); | ||
713 | return PTR_ERR(task); | ||
714 | } | ||
715 | status = nfs4_wait_for_completion_rpc_task(task); | ||
716 | if (status != 0) { | ||
717 | data->cancelled = 1; | ||
718 | smp_wmb(); | ||
719 | } else | ||
720 | status = data->rpc_status; | ||
721 | rpc_release_task(task); | ||
443 | if (status != 0) | 722 | if (status != 0) |
444 | goto out; | 723 | return status; |
724 | |||
445 | if (o_arg->open_flags & O_CREAT) { | 725 | if (o_arg->open_flags & O_CREAT) { |
446 | update_changeattr(dir, &o_res->cinfo); | 726 | update_changeattr(dir, &o_res->cinfo); |
447 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 727 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
448 | } else | 728 | } else |
449 | nfs_refresh_inode(dir, o_res->dir_attr); | 729 | nfs_refresh_inode(dir, o_res->dir_attr); |
450 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 730 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
451 | status = _nfs4_proc_open_confirm(server->client, &o_res->fh, | 731 | status = _nfs4_proc_open_confirm(data); |
452 | sp, &o_res->stateid, o_arg->seqid); | ||
453 | if (status != 0) | 732 | if (status != 0) |
454 | goto out; | 733 | return status; |
455 | } | 734 | } |
456 | nfs_confirm_seqid(&sp->so_seqid, 0); | 735 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
457 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 736 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
458 | status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 737 | return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
459 | out: | 738 | return 0; |
460 | return status; | ||
461 | } | 739 | } |
462 | 740 | ||
463 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) | 741 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) |
@@ -488,6 +766,15 @@ out: | |||
488 | return -EACCES; | 766 | return -EACCES; |
489 | } | 767 | } |
490 | 768 | ||
769 | int nfs4_recover_expired_lease(struct nfs_server *server) | ||
770 | { | ||
771 | struct nfs4_client *clp = server->nfs4_state; | ||
772 | |||
773 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||
774 | nfs4_schedule_state_recovery(clp); | ||
775 | return nfs4_wait_clnt_recover(server->client, clp); | ||
776 | } | ||
777 | |||
491 | /* | 778 | /* |
492 | * OPEN_EXPIRED: | 779 | * OPEN_EXPIRED: |
493 | * reclaim state on the server after a network partition. | 780 | * reclaim state on the server after a network partition. |
@@ -495,77 +782,31 @@ out: | |||
495 | */ | 782 | */ |
496 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 783 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
497 | { | 784 | { |
498 | struct dentry *parent = dget_parent(dentry); | ||
499 | struct inode *dir = parent->d_inode; | ||
500 | struct inode *inode = state->inode; | 785 | struct inode *inode = state->inode; |
501 | struct nfs_server *server = NFS_SERVER(dir); | ||
502 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 786 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; |
503 | struct nfs_fattr f_attr, dir_attr; | 787 | struct nfs4_opendata *opendata; |
504 | struct nfs_openargs o_arg = { | 788 | int openflags = state->state & (FMODE_READ|FMODE_WRITE); |
505 | .fh = NFS_FH(dir), | 789 | int ret; |
506 | .open_flags = state->state, | ||
507 | .name = &dentry->d_name, | ||
508 | .bitmask = server->attr_bitmask, | ||
509 | .claim = NFS4_OPEN_CLAIM_NULL, | ||
510 | }; | ||
511 | struct nfs_openres o_res = { | ||
512 | .f_attr = &f_attr, | ||
513 | .dir_attr = &dir_attr, | ||
514 | .server = server, | ||
515 | }; | ||
516 | int status = 0; | ||
517 | 790 | ||
518 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | 791 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { |
519 | status = _nfs4_do_access(inode, sp->so_cred, state->state); | 792 | ret = _nfs4_do_access(inode, sp->so_cred, openflags); |
520 | if (status < 0) | 793 | if (ret < 0) |
521 | goto out; | 794 | return ret; |
522 | memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); | 795 | memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); |
523 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 796 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
524 | goto out; | 797 | return 0; |
525 | } | 798 | } |
526 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 799 | opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL); |
527 | status = -ENOMEM; | 800 | if (opendata == NULL) |
528 | if (o_arg.seqid == NULL) | 801 | return -ENOMEM; |
529 | goto out; | 802 | ret = nfs4_open_recover(opendata, state); |
530 | nfs_fattr_init(&f_attr); | 803 | if (ret == -ESTALE) { |
531 | nfs_fattr_init(&dir_attr); | 804 | /* Invalidate the state owner so we don't ever use it again */ |
532 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | 805 | nfs4_drop_state_owner(sp); |
533 | if (status != 0) | 806 | d_drop(dentry); |
534 | goto out_nodeleg; | ||
535 | /* Check if files differ */ | ||
536 | if ((f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT)) | ||
537 | goto out_stale; | ||
538 | /* Has the file handle changed? */ | ||
539 | if (nfs_compare_fh(&o_res.fh, NFS_FH(inode)) != 0) { | ||
540 | /* Verify if the change attributes are the same */ | ||
541 | if (f_attr.change_attr != NFS_I(inode)->change_attr) | ||
542 | goto out_stale; | ||
543 | if (nfs_size_to_loff_t(f_attr.size) != inode->i_size) | ||
544 | goto out_stale; | ||
545 | /* Lets just pretend that this is the same file */ | ||
546 | nfs_copy_fh(NFS_FH(inode), &o_res.fh); | ||
547 | NFS_I(inode)->fileid = f_attr.fileid; | ||
548 | } | ||
549 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); | ||
550 | if (o_res.delegation_type != 0) { | ||
551 | if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
552 | nfs_inode_set_delegation(inode, sp->so_cred, &o_res); | ||
553 | else | ||
554 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); | ||
555 | } | 807 | } |
556 | out_nodeleg: | 808 | nfs4_opendata_free(opendata); |
557 | nfs_free_seqid(o_arg.seqid); | 809 | return ret; |
558 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
559 | out: | ||
560 | dput(parent); | ||
561 | return status; | ||
562 | out_stale: | ||
563 | status = -ESTALE; | ||
564 | /* Invalidate the state owner so we don't ever use it again */ | ||
565 | nfs4_drop_state_owner(sp); | ||
566 | d_drop(dentry); | ||
567 | /* Should we be trying to close that stateid? */ | ||
568 | goto out_nodeleg; | ||
569 | } | 810 | } |
570 | 811 | ||
571 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 812 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
@@ -584,26 +825,19 @@ static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_ | |||
584 | 825 | ||
585 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 826 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
586 | { | 827 | { |
587 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
588 | struct nfs_open_context *ctx; | 828 | struct nfs_open_context *ctx; |
589 | int status; | 829 | int ret; |
590 | 830 | ||
591 | spin_lock(&state->inode->i_lock); | 831 | ctx = nfs4_state_find_open_context(state); |
592 | list_for_each_entry(ctx, &nfsi->open_files, list) { | 832 | if (IS_ERR(ctx)) |
593 | if (ctx->state != state) | 833 | return PTR_ERR(ctx); |
594 | continue; | 834 | ret = nfs4_do_open_expired(sp, state, ctx->dentry); |
595 | get_nfs_open_context(ctx); | 835 | put_nfs_open_context(ctx); |
596 | spin_unlock(&state->inode->i_lock); | 836 | return ret; |
597 | status = nfs4_do_open_expired(sp, state, ctx->dentry); | ||
598 | put_nfs_open_context(ctx); | ||
599 | return status; | ||
600 | } | ||
601 | spin_unlock(&state->inode->i_lock); | ||
602 | return -ENOENT; | ||
603 | } | 837 | } |
604 | 838 | ||
605 | /* | 839 | /* |
606 | * Returns an nfs4_state + an extra reference to the inode | 840 | * Returns a referenced nfs4_state if there is an open delegation on the file |
607 | */ | 841 | */ |
608 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) | 842 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) |
609 | { | 843 | { |
@@ -616,6 +850,14 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
616 | int open_flags = flags & (FMODE_READ|FMODE_WRITE); | 850 | int open_flags = flags & (FMODE_READ|FMODE_WRITE); |
617 | int err; | 851 | int err; |
618 | 852 | ||
853 | err = -ENOMEM; | ||
854 | if (!(sp = nfs4_get_state_owner(server, cred))) { | ||
855 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | ||
856 | return err; | ||
857 | } | ||
858 | err = nfs4_recover_expired_lease(server); | ||
859 | if (err != 0) | ||
860 | goto out_put_state_owner; | ||
619 | /* Protect against reboot recovery - NOTE ORDER! */ | 861 | /* Protect against reboot recovery - NOTE ORDER! */ |
620 | down_read(&clp->cl_sem); | 862 | down_read(&clp->cl_sem); |
621 | /* Protect against delegation recall */ | 863 | /* Protect against delegation recall */ |
@@ -625,10 +867,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
625 | if (delegation == NULL || (delegation->type & open_flags) != open_flags) | 867 | if (delegation == NULL || (delegation->type & open_flags) != open_flags) |
626 | goto out_err; | 868 | goto out_err; |
627 | err = -ENOMEM; | 869 | err = -ENOMEM; |
628 | if (!(sp = nfs4_get_state_owner(server, cred))) { | ||
629 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | ||
630 | goto out_err; | ||
631 | } | ||
632 | state = nfs4_get_open_state(inode, sp); | 870 | state = nfs4_get_open_state(inode, sp); |
633 | if (state == NULL) | 871 | if (state == NULL) |
634 | goto out_err; | 872 | goto out_err; |
@@ -636,39 +874,34 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
636 | err = -ENOENT; | 874 | err = -ENOENT; |
637 | if ((state->state & open_flags) == open_flags) { | 875 | if ((state->state & open_flags) == open_flags) { |
638 | spin_lock(&inode->i_lock); | 876 | spin_lock(&inode->i_lock); |
639 | if (open_flags & FMODE_READ) | 877 | update_open_stateflags(state, open_flags); |
640 | state->nreaders++; | ||
641 | if (open_flags & FMODE_WRITE) | ||
642 | state->nwriters++; | ||
643 | spin_unlock(&inode->i_lock); | 878 | spin_unlock(&inode->i_lock); |
644 | goto out_ok; | 879 | goto out_ok; |
645 | } else if (state->state != 0) | 880 | } else if (state->state != 0) |
646 | goto out_err; | 881 | goto out_put_open_state; |
647 | 882 | ||
648 | lock_kernel(); | 883 | lock_kernel(); |
649 | err = _nfs4_do_access(inode, cred, open_flags); | 884 | err = _nfs4_do_access(inode, cred, open_flags); |
650 | unlock_kernel(); | 885 | unlock_kernel(); |
651 | if (err != 0) | 886 | if (err != 0) |
652 | goto out_err; | 887 | goto out_put_open_state; |
653 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 888 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
654 | update_open_stateid(state, &delegation->stateid, open_flags); | 889 | update_open_stateid(state, &delegation->stateid, open_flags); |
655 | out_ok: | 890 | out_ok: |
656 | nfs4_put_state_owner(sp); | 891 | nfs4_put_state_owner(sp); |
657 | up_read(&nfsi->rwsem); | 892 | up_read(&nfsi->rwsem); |
658 | up_read(&clp->cl_sem); | 893 | up_read(&clp->cl_sem); |
659 | igrab(inode); | ||
660 | *res = state; | 894 | *res = state; |
661 | return 0; | 895 | return 0; |
896 | out_put_open_state: | ||
897 | nfs4_put_open_state(state); | ||
662 | out_err: | 898 | out_err: |
663 | if (sp != NULL) { | ||
664 | if (state != NULL) | ||
665 | nfs4_put_open_state(state); | ||
666 | nfs4_put_state_owner(sp); | ||
667 | } | ||
668 | up_read(&nfsi->rwsem); | 899 | up_read(&nfsi->rwsem); |
669 | up_read(&clp->cl_sem); | 900 | up_read(&clp->cl_sem); |
670 | if (err != -EACCES) | 901 | if (err != -EACCES) |
671 | nfs_inode_return_delegation(inode); | 902 | nfs_inode_return_delegation(inode); |
903 | out_put_state_owner: | ||
904 | nfs4_put_state_owner(sp); | ||
672 | return err; | 905 | return err; |
673 | } | 906 | } |
674 | 907 | ||
@@ -689,7 +922,7 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st | |||
689 | } | 922 | } |
690 | 923 | ||
691 | /* | 924 | /* |
692 | * Returns an nfs4_state + an referenced inode | 925 | * Returns a referenced nfs4_state |
693 | */ | 926 | */ |
694 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 927 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
695 | { | 928 | { |
@@ -697,73 +930,46 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
697 | struct nfs4_state *state = NULL; | 930 | struct nfs4_state *state = NULL; |
698 | struct nfs_server *server = NFS_SERVER(dir); | 931 | struct nfs_server *server = NFS_SERVER(dir); |
699 | struct nfs4_client *clp = server->nfs4_state; | 932 | struct nfs4_client *clp = server->nfs4_state; |
700 | struct inode *inode = NULL; | 933 | struct nfs4_opendata *opendata; |
701 | int status; | 934 | int status; |
702 | struct nfs_fattr f_attr, dir_attr; | ||
703 | struct nfs_openargs o_arg = { | ||
704 | .fh = NFS_FH(dir), | ||
705 | .open_flags = flags, | ||
706 | .name = &dentry->d_name, | ||
707 | .server = server, | ||
708 | .bitmask = server->attr_bitmask, | ||
709 | .claim = NFS4_OPEN_CLAIM_NULL, | ||
710 | }; | ||
711 | struct nfs_openres o_res = { | ||
712 | .f_attr = &f_attr, | ||
713 | .dir_attr = &dir_attr, | ||
714 | .server = server, | ||
715 | }; | ||
716 | 935 | ||
717 | /* Protect against reboot recovery conflicts */ | 936 | /* Protect against reboot recovery conflicts */ |
718 | down_read(&clp->cl_sem); | ||
719 | status = -ENOMEM; | 937 | status = -ENOMEM; |
720 | if (!(sp = nfs4_get_state_owner(server, cred))) { | 938 | if (!(sp = nfs4_get_state_owner(server, cred))) { |
721 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); | 939 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); |
722 | goto out_err; | 940 | goto out_err; |
723 | } | 941 | } |
724 | if (flags & O_EXCL) { | 942 | status = nfs4_recover_expired_lease(server); |
725 | u32 *p = (u32 *) o_arg.u.verifier.data; | 943 | if (status != 0) |
726 | p[0] = jiffies; | 944 | goto err_put_state_owner; |
727 | p[1] = current->pid; | 945 | down_read(&clp->cl_sem); |
728 | } else | 946 | status = -ENOMEM; |
729 | o_arg.u.attrs = sattr; | 947 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); |
730 | /* Serialization for the sequence id */ | 948 | if (opendata == NULL) |
949 | goto err_put_state_owner; | ||
731 | 950 | ||
732 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 951 | status = _nfs4_proc_open(opendata); |
733 | if (o_arg.seqid == NULL) | ||
734 | return -ENOMEM; | ||
735 | nfs_fattr_init(&f_attr); | ||
736 | nfs_fattr_init(&dir_attr); | ||
737 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | ||
738 | if (status != 0) | 952 | if (status != 0) |
739 | goto out_err; | 953 | goto err_opendata_free; |
740 | 954 | ||
741 | status = -ENOMEM; | 955 | status = -ENOMEM; |
742 | inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); | 956 | state = nfs4_opendata_to_nfs4_state(opendata); |
743 | if (!inode) | 957 | if (state == NULL) |
744 | goto out_err; | 958 | goto err_opendata_free; |
745 | state = nfs4_get_open_state(inode, sp); | 959 | if (opendata->o_res.delegation_type != 0) |
746 | if (!state) | 960 | nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); |
747 | goto out_err; | 961 | nfs4_opendata_free(opendata); |
748 | update_open_stateid(state, &o_res.stateid, flags); | ||
749 | if (o_res.delegation_type != 0) | ||
750 | nfs_inode_set_delegation(inode, cred, &o_res); | ||
751 | nfs_free_seqid(o_arg.seqid); | ||
752 | nfs4_put_state_owner(sp); | 962 | nfs4_put_state_owner(sp); |
753 | up_read(&clp->cl_sem); | 963 | up_read(&clp->cl_sem); |
754 | *res = state; | 964 | *res = state; |
755 | return 0; | 965 | return 0; |
966 | err_opendata_free: | ||
967 | nfs4_opendata_free(opendata); | ||
968 | err_put_state_owner: | ||
969 | nfs4_put_state_owner(sp); | ||
756 | out_err: | 970 | out_err: |
757 | if (sp != NULL) { | ||
758 | if (state != NULL) | ||
759 | nfs4_put_open_state(state); | ||
760 | nfs_free_seqid(o_arg.seqid); | ||
761 | nfs4_put_state_owner(sp); | ||
762 | } | ||
763 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ | 971 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ |
764 | up_read(&clp->cl_sem); | 972 | up_read(&clp->cl_sem); |
765 | if (inode != NULL) | ||
766 | iput(inode); | ||
767 | *res = NULL; | 973 | *res = NULL; |
768 | return status; | 974 | return status; |
769 | } | 975 | } |
@@ -830,6 +1036,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
830 | .rpc_argp = &arg, | 1036 | .rpc_argp = &arg, |
831 | .rpc_resp = &res, | 1037 | .rpc_resp = &res, |
832 | }; | 1038 | }; |
1039 | unsigned long timestamp = jiffies; | ||
833 | int status; | 1040 | int status; |
834 | 1041 | ||
835 | nfs_fattr_init(fattr); | 1042 | nfs_fattr_init(fattr); |
@@ -841,6 +1048,8 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
841 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1048 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
842 | 1049 | ||
843 | status = rpc_call_sync(server->client, &msg, 0); | 1050 | status = rpc_call_sync(server->client, &msg, 0); |
1051 | if (status == 0 && state != NULL) | ||
1052 | renew_lease(server, timestamp); | ||
844 | return status; | 1053 | return status; |
845 | } | 1054 | } |
846 | 1055 | ||
@@ -865,12 +1074,13 @@ struct nfs4_closedata { | |||
865 | struct nfs_closeargs arg; | 1074 | struct nfs_closeargs arg; |
866 | struct nfs_closeres res; | 1075 | struct nfs_closeres res; |
867 | struct nfs_fattr fattr; | 1076 | struct nfs_fattr fattr; |
1077 | unsigned long timestamp; | ||
868 | }; | 1078 | }; |
869 | 1079 | ||
870 | static void nfs4_free_closedata(struct nfs4_closedata *calldata) | 1080 | static void nfs4_free_closedata(void *data) |
871 | { | 1081 | { |
872 | struct nfs4_state *state = calldata->state; | 1082 | struct nfs4_closedata *calldata = data; |
873 | struct nfs4_state_owner *sp = state->owner; | 1083 | struct nfs4_state_owner *sp = calldata->state->owner; |
874 | 1084 | ||
875 | nfs4_put_open_state(calldata->state); | 1085 | nfs4_put_open_state(calldata->state); |
876 | nfs_free_seqid(calldata->arg.seqid); | 1086 | nfs_free_seqid(calldata->arg.seqid); |
@@ -878,12 +1088,14 @@ static void nfs4_free_closedata(struct nfs4_closedata *calldata) | |||
878 | kfree(calldata); | 1088 | kfree(calldata); |
879 | } | 1089 | } |
880 | 1090 | ||
881 | static void nfs4_close_done(struct rpc_task *task) | 1091 | static void nfs4_close_done(struct rpc_task *task, void *data) |
882 | { | 1092 | { |
883 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | 1093 | struct nfs4_closedata *calldata = data; |
884 | struct nfs4_state *state = calldata->state; | 1094 | struct nfs4_state *state = calldata->state; |
885 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1095 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
886 | 1096 | ||
1097 | if (RPC_ASSASSINATED(task)) | ||
1098 | return; | ||
887 | /* hmm. we are done with the inode, and in the process of freeing | 1099 | /* hmm. we are done with the inode, and in the process of freeing |
888 | * the state_owner. we keep this around to process errors | 1100 | * the state_owner. we keep this around to process errors |
889 | */ | 1101 | */ |
@@ -892,6 +1104,7 @@ static void nfs4_close_done(struct rpc_task *task) | |||
892 | case 0: | 1104 | case 0: |
893 | memcpy(&state->stateid, &calldata->res.stateid, | 1105 | memcpy(&state->stateid, &calldata->res.stateid, |
894 | sizeof(state->stateid)); | 1106 | sizeof(state->stateid)); |
1107 | renew_lease(server, calldata->timestamp); | ||
895 | break; | 1108 | break; |
896 | case -NFS4ERR_STALE_STATEID: | 1109 | case -NFS4ERR_STALE_STATEID: |
897 | case -NFS4ERR_EXPIRED: | 1110 | case -NFS4ERR_EXPIRED: |
@@ -904,12 +1117,11 @@ static void nfs4_close_done(struct rpc_task *task) | |||
904 | } | 1117 | } |
905 | } | 1118 | } |
906 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1119 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
907 | nfs4_free_closedata(calldata); | ||
908 | } | 1120 | } |
909 | 1121 | ||
910 | static void nfs4_close_begin(struct rpc_task *task) | 1122 | static void nfs4_close_prepare(struct rpc_task *task, void *data) |
911 | { | 1123 | { |
912 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | 1124 | struct nfs4_closedata *calldata = data; |
913 | struct nfs4_state *state = calldata->state; | 1125 | struct nfs4_state *state = calldata->state; |
914 | struct rpc_message msg = { | 1126 | struct rpc_message msg = { |
915 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | 1127 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], |
@@ -918,10 +1130,8 @@ static void nfs4_close_begin(struct rpc_task *task) | |||
918 | .rpc_cred = state->owner->so_cred, | 1130 | .rpc_cred = state->owner->so_cred, |
919 | }; | 1131 | }; |
920 | int mode = 0, old_mode; | 1132 | int mode = 0, old_mode; |
921 | int status; | ||
922 | 1133 | ||
923 | status = nfs_wait_on_sequence(calldata->arg.seqid, task); | 1134 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
924 | if (status != 0) | ||
925 | return; | 1135 | return; |
926 | /* Recalculate the new open mode in case someone reopened the file | 1136 | /* Recalculate the new open mode in case someone reopened the file |
927 | * while we were waiting in line to be scheduled. | 1137 | * while we were waiting in line to be scheduled. |
@@ -929,26 +1139,34 @@ static void nfs4_close_begin(struct rpc_task *task) | |||
929 | spin_lock(&state->owner->so_lock); | 1139 | spin_lock(&state->owner->so_lock); |
930 | spin_lock(&calldata->inode->i_lock); | 1140 | spin_lock(&calldata->inode->i_lock); |
931 | mode = old_mode = state->state; | 1141 | mode = old_mode = state->state; |
932 | if (state->nreaders == 0) | 1142 | if (state->n_rdwr == 0) { |
933 | mode &= ~FMODE_READ; | 1143 | if (state->n_rdonly == 0) |
934 | if (state->nwriters == 0) | 1144 | mode &= ~FMODE_READ; |
935 | mode &= ~FMODE_WRITE; | 1145 | if (state->n_wronly == 0) |
1146 | mode &= ~FMODE_WRITE; | ||
1147 | } | ||
936 | nfs4_state_set_mode_locked(state, mode); | 1148 | nfs4_state_set_mode_locked(state, mode); |
937 | spin_unlock(&calldata->inode->i_lock); | 1149 | spin_unlock(&calldata->inode->i_lock); |
938 | spin_unlock(&state->owner->so_lock); | 1150 | spin_unlock(&state->owner->so_lock); |
939 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 1151 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
940 | nfs4_free_closedata(calldata); | 1152 | /* Note: exit _without_ calling nfs4_close_done */ |
941 | task->tk_exit = NULL; | 1153 | task->tk_action = NULL; |
942 | rpc_exit(task, 0); | ||
943 | return; | 1154 | return; |
944 | } | 1155 | } |
945 | nfs_fattr_init(calldata->res.fattr); | 1156 | nfs_fattr_init(calldata->res.fattr); |
946 | if (mode != 0) | 1157 | if (mode != 0) |
947 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1158 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
948 | calldata->arg.open_flags = mode; | 1159 | calldata->arg.open_flags = mode; |
1160 | calldata->timestamp = jiffies; | ||
949 | rpc_call_setup(task, &msg, 0); | 1161 | rpc_call_setup(task, &msg, 0); |
950 | } | 1162 | } |
951 | 1163 | ||
1164 | static const struct rpc_call_ops nfs4_close_ops = { | ||
1165 | .rpc_call_prepare = nfs4_close_prepare, | ||
1166 | .rpc_call_done = nfs4_close_done, | ||
1167 | .rpc_release = nfs4_free_closedata, | ||
1168 | }; | ||
1169 | |||
952 | /* | 1170 | /* |
953 | * It is possible for data to be read/written from a mem-mapped file | 1171 | * It is possible for data to be read/written from a mem-mapped file |
954 | * after the sys_close call (which hits the vfs layer as a flush). | 1172 | * after the sys_close call (which hits the vfs layer as a flush). |
@@ -981,8 +1199,7 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | |||
981 | calldata->res.fattr = &calldata->fattr; | 1199 | calldata->res.fattr = &calldata->fattr; |
982 | calldata->res.server = server; | 1200 | calldata->res.server = server; |
983 | 1201 | ||
984 | status = nfs4_call_async(server->client, nfs4_close_begin, | 1202 | status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); |
985 | nfs4_close_done, calldata); | ||
986 | if (status == 0) | 1203 | if (status == 0) |
987 | goto out; | 1204 | goto out; |
988 | 1205 | ||
@@ -1034,7 +1251,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1034 | d_add(dentry, NULL); | 1251 | d_add(dentry, NULL); |
1035 | return (struct dentry *)state; | 1252 | return (struct dentry *)state; |
1036 | } | 1253 | } |
1037 | res = d_add_unique(dentry, state->inode); | 1254 | res = d_add_unique(dentry, igrab(state->inode)); |
1038 | if (res != NULL) | 1255 | if (res != NULL) |
1039 | dentry = res; | 1256 | dentry = res; |
1040 | nfs4_intent_set_file(nd, dentry, state); | 1257 | nfs4_intent_set_file(nd, dentry, state); |
@@ -1046,7 +1263,6 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1046 | { | 1263 | { |
1047 | struct rpc_cred *cred; | 1264 | struct rpc_cred *cred; |
1048 | struct nfs4_state *state; | 1265 | struct nfs4_state *state; |
1049 | struct inode *inode; | ||
1050 | 1266 | ||
1051 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1267 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); |
1052 | if (IS_ERR(cred)) | 1268 | if (IS_ERR(cred)) |
@@ -1070,9 +1286,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1070 | } | 1286 | } |
1071 | goto out_drop; | 1287 | goto out_drop; |
1072 | } | 1288 | } |
1073 | inode = state->inode; | 1289 | if (state->inode == dentry->d_inode) { |
1074 | iput(inode); | ||
1075 | if (inode == dentry->d_inode) { | ||
1076 | nfs4_intent_set_file(nd, dentry, state); | 1290 | nfs4_intent_set_file(nd, dentry, state); |
1077 | return 1; | 1291 | return 1; |
1078 | } | 1292 | } |
@@ -1508,11 +1722,13 @@ static int _nfs4_proc_write(struct nfs_write_data *wdata) | |||
1508 | 1722 | ||
1509 | wdata->args.bitmask = server->attr_bitmask; | 1723 | wdata->args.bitmask = server->attr_bitmask; |
1510 | wdata->res.server = server; | 1724 | wdata->res.server = server; |
1725 | wdata->timestamp = jiffies; | ||
1511 | nfs_fattr_init(fattr); | 1726 | nfs_fattr_init(fattr); |
1512 | status = rpc_call_sync(server->client, &msg, rpcflags); | 1727 | status = rpc_call_sync(server->client, &msg, rpcflags); |
1513 | dprintk("NFS reply write: %d\n", status); | 1728 | dprintk("NFS reply write: %d\n", status); |
1514 | if (status < 0) | 1729 | if (status < 0) |
1515 | return status; | 1730 | return status; |
1731 | renew_lease(server, wdata->timestamp); | ||
1516 | nfs_post_op_update_inode(inode, fattr); | 1732 | nfs_post_op_update_inode(inode, fattr); |
1517 | return wdata->res.count; | 1733 | return wdata->res.count; |
1518 | } | 1734 | } |
@@ -1547,8 +1763,11 @@ static int _nfs4_proc_commit(struct nfs_write_data *cdata) | |||
1547 | 1763 | ||
1548 | cdata->args.bitmask = server->attr_bitmask; | 1764 | cdata->args.bitmask = server->attr_bitmask; |
1549 | cdata->res.server = server; | 1765 | cdata->res.server = server; |
1766 | cdata->timestamp = jiffies; | ||
1550 | nfs_fattr_init(fattr); | 1767 | nfs_fattr_init(fattr); |
1551 | status = rpc_call_sync(server->client, &msg, 0); | 1768 | status = rpc_call_sync(server->client, &msg, 0); |
1769 | if (status >= 0) | ||
1770 | renew_lease(server, cdata->timestamp); | ||
1552 | dprintk("NFS reply commit: %d\n", status); | 1771 | dprintk("NFS reply commit: %d\n", status); |
1553 | if (status >= 0) | 1772 | if (status >= 0) |
1554 | nfs_post_op_update_inode(inode, fattr); | 1773 | nfs_post_op_update_inode(inode, fattr); |
@@ -1601,7 +1820,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1601 | status = PTR_ERR(state); | 1820 | status = PTR_ERR(state); |
1602 | goto out; | 1821 | goto out; |
1603 | } | 1822 | } |
1604 | d_instantiate(dentry, state->inode); | 1823 | d_instantiate(dentry, igrab(state->inode)); |
1605 | if (flags & O_EXCL) { | 1824 | if (flags & O_EXCL) { |
1606 | struct nfs_fattr fattr; | 1825 | struct nfs_fattr fattr; |
1607 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, | 1826 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, |
@@ -2125,10 +2344,9 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2125 | return err; | 2344 | return err; |
2126 | } | 2345 | } |
2127 | 2346 | ||
2128 | static void | 2347 | static void nfs4_read_done(struct rpc_task *task, void *calldata) |
2129 | nfs4_read_done(struct rpc_task *task) | ||
2130 | { | 2348 | { |
2131 | struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; | 2349 | struct nfs_read_data *data = calldata; |
2132 | struct inode *inode = data->inode; | 2350 | struct inode *inode = data->inode; |
2133 | 2351 | ||
2134 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2352 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
@@ -2138,9 +2356,14 @@ nfs4_read_done(struct rpc_task *task) | |||
2138 | if (task->tk_status > 0) | 2356 | if (task->tk_status > 0) |
2139 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2357 | renew_lease(NFS_SERVER(inode), data->timestamp); |
2140 | /* Call back common NFS readpage processing */ | 2358 | /* Call back common NFS readpage processing */ |
2141 | nfs_readpage_result(task); | 2359 | nfs_readpage_result(task, calldata); |
2142 | } | 2360 | } |
2143 | 2361 | ||
2362 | static const struct rpc_call_ops nfs4_read_ops = { | ||
2363 | .rpc_call_done = nfs4_read_done, | ||
2364 | .rpc_release = nfs_readdata_release, | ||
2365 | }; | ||
2366 | |||
2144 | static void | 2367 | static void |
2145 | nfs4_proc_read_setup(struct nfs_read_data *data) | 2368 | nfs4_proc_read_setup(struct nfs_read_data *data) |
2146 | { | 2369 | { |
@@ -2160,14 +2383,13 @@ nfs4_proc_read_setup(struct nfs_read_data *data) | |||
2160 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 2383 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
2161 | 2384 | ||
2162 | /* Finalize the task. */ | 2385 | /* Finalize the task. */ |
2163 | rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags); | 2386 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_read_ops, data); |
2164 | rpc_call_setup(task, &msg, 0); | 2387 | rpc_call_setup(task, &msg, 0); |
2165 | } | 2388 | } |
2166 | 2389 | ||
2167 | static void | 2390 | static void nfs4_write_done(struct rpc_task *task, void *calldata) |
2168 | nfs4_write_done(struct rpc_task *task) | ||
2169 | { | 2391 | { |
2170 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 2392 | struct nfs_write_data *data = calldata; |
2171 | struct inode *inode = data->inode; | 2393 | struct inode *inode = data->inode; |
2172 | 2394 | ||
2173 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2395 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
@@ -2179,9 +2401,14 @@ nfs4_write_done(struct rpc_task *task) | |||
2179 | nfs_post_op_update_inode(inode, data->res.fattr); | 2401 | nfs_post_op_update_inode(inode, data->res.fattr); |
2180 | } | 2402 | } |
2181 | /* Call back common NFS writeback processing */ | 2403 | /* Call back common NFS writeback processing */ |
2182 | nfs_writeback_done(task); | 2404 | nfs_writeback_done(task, calldata); |
2183 | } | 2405 | } |
2184 | 2406 | ||
2407 | static const struct rpc_call_ops nfs4_write_ops = { | ||
2408 | .rpc_call_done = nfs4_write_done, | ||
2409 | .rpc_release = nfs_writedata_release, | ||
2410 | }; | ||
2411 | |||
2185 | static void | 2412 | static void |
2186 | nfs4_proc_write_setup(struct nfs_write_data *data, int how) | 2413 | nfs4_proc_write_setup(struct nfs_write_data *data, int how) |
2187 | { | 2414 | { |
@@ -2214,14 +2441,13 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2214 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 2441 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
2215 | 2442 | ||
2216 | /* Finalize the task. */ | 2443 | /* Finalize the task. */ |
2217 | rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags); | 2444 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_write_ops, data); |
2218 | rpc_call_setup(task, &msg, 0); | 2445 | rpc_call_setup(task, &msg, 0); |
2219 | } | 2446 | } |
2220 | 2447 | ||
2221 | static void | 2448 | static void nfs4_commit_done(struct rpc_task *task, void *calldata) |
2222 | nfs4_commit_done(struct rpc_task *task) | ||
2223 | { | 2449 | { |
2224 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 2450 | struct nfs_write_data *data = calldata; |
2225 | struct inode *inode = data->inode; | 2451 | struct inode *inode = data->inode; |
2226 | 2452 | ||
2227 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2453 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
@@ -2231,9 +2457,14 @@ nfs4_commit_done(struct rpc_task *task) | |||
2231 | if (task->tk_status >= 0) | 2457 | if (task->tk_status >= 0) |
2232 | nfs_post_op_update_inode(inode, data->res.fattr); | 2458 | nfs_post_op_update_inode(inode, data->res.fattr); |
2233 | /* Call back common NFS writeback processing */ | 2459 | /* Call back common NFS writeback processing */ |
2234 | nfs_commit_done(task); | 2460 | nfs_commit_done(task, calldata); |
2235 | } | 2461 | } |
2236 | 2462 | ||
2463 | static const struct rpc_call_ops nfs4_commit_ops = { | ||
2464 | .rpc_call_done = nfs4_commit_done, | ||
2465 | .rpc_release = nfs_commit_release, | ||
2466 | }; | ||
2467 | |||
2237 | static void | 2468 | static void |
2238 | nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | 2469 | nfs4_proc_commit_setup(struct nfs_write_data *data, int how) |
2239 | { | 2470 | { |
@@ -2255,7 +2486,7 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2255 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 2486 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
2256 | 2487 | ||
2257 | /* Finalize the task. */ | 2488 | /* Finalize the task. */ |
2258 | rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); | 2489 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_commit_ops, data); |
2259 | rpc_call_setup(task, &msg, 0); | 2490 | rpc_call_setup(task, &msg, 0); |
2260 | } | 2491 | } |
2261 | 2492 | ||
@@ -2263,11 +2494,10 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2263 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 2494 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
2264 | * standalone procedure for queueing an asynchronous RENEW. | 2495 | * standalone procedure for queueing an asynchronous RENEW. |
2265 | */ | 2496 | */ |
2266 | static void | 2497 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
2267 | renew_done(struct rpc_task *task) | ||
2268 | { | 2498 | { |
2269 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; | 2499 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; |
2270 | unsigned long timestamp = (unsigned long)task->tk_calldata; | 2500 | unsigned long timestamp = (unsigned long)data; |
2271 | 2501 | ||
2272 | if (task->tk_status < 0) { | 2502 | if (task->tk_status < 0) { |
2273 | switch (task->tk_status) { | 2503 | switch (task->tk_status) { |
@@ -2284,26 +2514,28 @@ renew_done(struct rpc_task *task) | |||
2284 | spin_unlock(&clp->cl_lock); | 2514 | spin_unlock(&clp->cl_lock); |
2285 | } | 2515 | } |
2286 | 2516 | ||
2287 | int | 2517 | static const struct rpc_call_ops nfs4_renew_ops = { |
2288 | nfs4_proc_async_renew(struct nfs4_client *clp) | 2518 | .rpc_call_done = nfs4_renew_done, |
2519 | }; | ||
2520 | |||
2521 | int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | ||
2289 | { | 2522 | { |
2290 | struct rpc_message msg = { | 2523 | struct rpc_message msg = { |
2291 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2524 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
2292 | .rpc_argp = clp, | 2525 | .rpc_argp = clp, |
2293 | .rpc_cred = clp->cl_cred, | 2526 | .rpc_cred = cred, |
2294 | }; | 2527 | }; |
2295 | 2528 | ||
2296 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 2529 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
2297 | renew_done, (void *)jiffies); | 2530 | &nfs4_renew_ops, (void *)jiffies); |
2298 | } | 2531 | } |
2299 | 2532 | ||
2300 | int | 2533 | int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred) |
2301 | nfs4_proc_renew(struct nfs4_client *clp) | ||
2302 | { | 2534 | { |
2303 | struct rpc_message msg = { | 2535 | struct rpc_message msg = { |
2304 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2536 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
2305 | .rpc_argp = clp, | 2537 | .rpc_argp = clp, |
2306 | .rpc_cred = clp->cl_cred, | 2538 | .rpc_cred = cred, |
2307 | }; | 2539 | }; |
2308 | unsigned long now = jiffies; | 2540 | unsigned long now = jiffies; |
2309 | int status; | 2541 | int status; |
@@ -2519,7 +2751,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2519 | case -NFS4ERR_EXPIRED: | 2751 | case -NFS4ERR_EXPIRED: |
2520 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); | 2752 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); |
2521 | nfs4_schedule_state_recovery(clp); | 2753 | nfs4_schedule_state_recovery(clp); |
2522 | if (test_bit(NFS4CLNT_OK, &clp->cl_state)) | 2754 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) |
2523 | rpc_wake_up_task(task); | 2755 | rpc_wake_up_task(task); |
2524 | task->tk_status = 0; | 2756 | task->tk_status = 0; |
2525 | return -EAGAIN; | 2757 | return -EAGAIN; |
@@ -2536,25 +2768,25 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2536 | return 0; | 2768 | return 0; |
2537 | } | 2769 | } |
2538 | 2770 | ||
2771 | static int nfs4_wait_bit_interruptible(void *word) | ||
2772 | { | ||
2773 | if (signal_pending(current)) | ||
2774 | return -ERESTARTSYS; | ||
2775 | schedule(); | ||
2776 | return 0; | ||
2777 | } | ||
2778 | |||
2539 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) | 2779 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) |
2540 | { | 2780 | { |
2541 | DEFINE_WAIT(wait); | ||
2542 | sigset_t oldset; | 2781 | sigset_t oldset; |
2543 | int interruptible, res = 0; | 2782 | int res; |
2544 | 2783 | ||
2545 | might_sleep(); | 2784 | might_sleep(); |
2546 | 2785 | ||
2547 | rpc_clnt_sigmask(clnt, &oldset); | 2786 | rpc_clnt_sigmask(clnt, &oldset); |
2548 | interruptible = TASK_UNINTERRUPTIBLE; | 2787 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, |
2549 | if (clnt->cl_intr) | 2788 | nfs4_wait_bit_interruptible, |
2550 | interruptible = TASK_INTERRUPTIBLE; | 2789 | TASK_INTERRUPTIBLE); |
2551 | prepare_to_wait(&clp->cl_waitq, &wait, interruptible); | ||
2552 | nfs4_schedule_state_recovery(clp); | ||
2553 | if (clnt->cl_intr && signalled()) | ||
2554 | res = -ERESTARTSYS; | ||
2555 | else if (!test_bit(NFS4CLNT_OK, &clp->cl_state)) | ||
2556 | schedule(); | ||
2557 | finish_wait(&clp->cl_waitq, &wait); | ||
2558 | rpc_clnt_sigunmask(clnt, &oldset); | 2790 | rpc_clnt_sigunmask(clnt, &oldset); |
2559 | return res; | 2791 | return res; |
2560 | } | 2792 | } |
@@ -2597,6 +2829,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2597 | case -NFS4ERR_STALE_CLIENTID: | 2829 | case -NFS4ERR_STALE_CLIENTID: |
2598 | case -NFS4ERR_STALE_STATEID: | 2830 | case -NFS4ERR_STALE_STATEID: |
2599 | case -NFS4ERR_EXPIRED: | 2831 | case -NFS4ERR_EXPIRED: |
2832 | nfs4_schedule_state_recovery(clp); | ||
2600 | ret = nfs4_wait_clnt_recover(server->client, clp); | 2833 | ret = nfs4_wait_clnt_recover(server->client, clp); |
2601 | if (ret == 0) | 2834 | if (ret == 0) |
2602 | exception->retry = 1; | 2835 | exception->retry = 1; |
@@ -2613,7 +2846,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2613 | return nfs4_map_errors(ret); | 2846 | return nfs4_map_errors(ret); |
2614 | } | 2847 | } |
2615 | 2848 | ||
2616 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port) | 2849 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2617 | { | 2850 | { |
2618 | nfs4_verifier sc_verifier; | 2851 | nfs4_verifier sc_verifier; |
2619 | struct nfs4_setclientid setclientid = { | 2852 | struct nfs4_setclientid setclientid = { |
@@ -2624,7 +2857,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2624 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], | 2857 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], |
2625 | .rpc_argp = &setclientid, | 2858 | .rpc_argp = &setclientid, |
2626 | .rpc_resp = clp, | 2859 | .rpc_resp = clp, |
2627 | .rpc_cred = clp->cl_cred, | 2860 | .rpc_cred = cred, |
2628 | }; | 2861 | }; |
2629 | u32 *p; | 2862 | u32 *p; |
2630 | int loop = 0; | 2863 | int loop = 0; |
@@ -2638,7 +2871,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2638 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2871 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
2639 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2872 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", |
2640 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), | 2873 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), |
2641 | clp->cl_cred->cr_ops->cr_name, | 2874 | cred->cr_ops->cr_name, |
2642 | clp->cl_id_uniquifier); | 2875 | clp->cl_id_uniquifier); |
2643 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2876 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
2644 | sizeof(setclientid.sc_netid), "tcp"); | 2877 | sizeof(setclientid.sc_netid), "tcp"); |
@@ -2661,14 +2894,14 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2661 | } | 2894 | } |
2662 | 2895 | ||
2663 | int | 2896 | int |
2664 | nfs4_proc_setclientid_confirm(struct nfs4_client *clp) | 2897 | nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) |
2665 | { | 2898 | { |
2666 | struct nfs_fsinfo fsinfo; | 2899 | struct nfs_fsinfo fsinfo; |
2667 | struct rpc_message msg = { | 2900 | struct rpc_message msg = { |
2668 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], | 2901 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], |
2669 | .rpc_argp = clp, | 2902 | .rpc_argp = clp, |
2670 | .rpc_resp = &fsinfo, | 2903 | .rpc_resp = &fsinfo, |
2671 | .rpc_cred = clp->cl_cred, | 2904 | .rpc_cred = cred, |
2672 | }; | 2905 | }; |
2673 | unsigned long now; | 2906 | unsigned long now; |
2674 | int status; | 2907 | int status; |
@@ -2679,24 +2912,92 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) | |||
2679 | spin_lock(&clp->cl_lock); | 2912 | spin_lock(&clp->cl_lock); |
2680 | clp->cl_lease_time = fsinfo.lease_time * HZ; | 2913 | clp->cl_lease_time = fsinfo.lease_time * HZ; |
2681 | clp->cl_last_renewal = now; | 2914 | clp->cl_last_renewal = now; |
2915 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
2682 | spin_unlock(&clp->cl_lock); | 2916 | spin_unlock(&clp->cl_lock); |
2683 | } | 2917 | } |
2684 | return status; | 2918 | return status; |
2685 | } | 2919 | } |
2686 | 2920 | ||
2687 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 2921 | struct nfs4_delegreturndata { |
2922 | struct nfs4_delegreturnargs args; | ||
2923 | struct nfs4_delegreturnres res; | ||
2924 | struct nfs_fh fh; | ||
2925 | nfs4_stateid stateid; | ||
2926 | struct rpc_cred *cred; | ||
2927 | unsigned long timestamp; | ||
2928 | struct nfs_fattr fattr; | ||
2929 | int rpc_status; | ||
2930 | }; | ||
2931 | |||
2932 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *calldata) | ||
2688 | { | 2933 | { |
2689 | struct nfs4_delegreturnargs args = { | 2934 | struct nfs4_delegreturndata *data = calldata; |
2690 | .fhandle = NFS_FH(inode), | ||
2691 | .stateid = stateid, | ||
2692 | }; | ||
2693 | struct rpc_message msg = { | 2935 | struct rpc_message msg = { |
2694 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], | 2936 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], |
2695 | .rpc_argp = &args, | 2937 | .rpc_argp = &data->args, |
2696 | .rpc_cred = cred, | 2938 | .rpc_resp = &data->res, |
2939 | .rpc_cred = data->cred, | ||
2697 | }; | 2940 | }; |
2941 | nfs_fattr_init(data->res.fattr); | ||
2942 | rpc_call_setup(task, &msg, 0); | ||
2943 | } | ||
2698 | 2944 | ||
2699 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2945 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
2946 | { | ||
2947 | struct nfs4_delegreturndata *data = calldata; | ||
2948 | data->rpc_status = task->tk_status; | ||
2949 | if (data->rpc_status == 0) | ||
2950 | renew_lease(data->res.server, data->timestamp); | ||
2951 | } | ||
2952 | |||
2953 | static void nfs4_delegreturn_release(void *calldata) | ||
2954 | { | ||
2955 | struct nfs4_delegreturndata *data = calldata; | ||
2956 | |||
2957 | put_rpccred(data->cred); | ||
2958 | kfree(calldata); | ||
2959 | } | ||
2960 | |||
2961 | const static struct rpc_call_ops nfs4_delegreturn_ops = { | ||
2962 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
2963 | .rpc_call_done = nfs4_delegreturn_done, | ||
2964 | .rpc_release = nfs4_delegreturn_release, | ||
2965 | }; | ||
2966 | |||
2967 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | ||
2968 | { | ||
2969 | struct nfs4_delegreturndata *data; | ||
2970 | struct nfs_server *server = NFS_SERVER(inode); | ||
2971 | struct rpc_task *task; | ||
2972 | int status; | ||
2973 | |||
2974 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
2975 | if (data == NULL) | ||
2976 | return -ENOMEM; | ||
2977 | data->args.fhandle = &data->fh; | ||
2978 | data->args.stateid = &data->stateid; | ||
2979 | data->args.bitmask = server->attr_bitmask; | ||
2980 | nfs_copy_fh(&data->fh, NFS_FH(inode)); | ||
2981 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | ||
2982 | data->res.fattr = &data->fattr; | ||
2983 | data->res.server = server; | ||
2984 | data->cred = get_rpccred(cred); | ||
2985 | data->timestamp = jiffies; | ||
2986 | data->rpc_status = 0; | ||
2987 | |||
2988 | task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data); | ||
2989 | if (IS_ERR(task)) { | ||
2990 | nfs4_delegreturn_release(data); | ||
2991 | return PTR_ERR(task); | ||
2992 | } | ||
2993 | status = nfs4_wait_for_completion_rpc_task(task); | ||
2994 | if (status == 0) { | ||
2995 | status = data->rpc_status; | ||
2996 | if (status == 0) | ||
2997 | nfs_post_op_update_inode(inode, &data->fattr); | ||
2998 | } | ||
2999 | rpc_release_task(task); | ||
3000 | return status; | ||
2700 | } | 3001 | } |
2701 | 3002 | ||
2702 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 3003 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) |
@@ -2734,43 +3035,17 @@ nfs4_set_lock_task_retry(unsigned long timeout) | |||
2734 | return timeout; | 3035 | return timeout; |
2735 | } | 3036 | } |
2736 | 3037 | ||
2737 | static inline int | ||
2738 | nfs4_lck_type(int cmd, struct file_lock *request) | ||
2739 | { | ||
2740 | /* set lock type */ | ||
2741 | switch (request->fl_type) { | ||
2742 | case F_RDLCK: | ||
2743 | return IS_SETLKW(cmd) ? NFS4_READW_LT : NFS4_READ_LT; | ||
2744 | case F_WRLCK: | ||
2745 | return IS_SETLKW(cmd) ? NFS4_WRITEW_LT : NFS4_WRITE_LT; | ||
2746 | case F_UNLCK: | ||
2747 | return NFS4_WRITE_LT; | ||
2748 | } | ||
2749 | BUG(); | ||
2750 | return 0; | ||
2751 | } | ||
2752 | |||
2753 | static inline uint64_t | ||
2754 | nfs4_lck_length(struct file_lock *request) | ||
2755 | { | ||
2756 | if (request->fl_end == OFFSET_MAX) | ||
2757 | return ~(uint64_t)0; | ||
2758 | return request->fl_end - request->fl_start + 1; | ||
2759 | } | ||
2760 | |||
2761 | static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3038 | static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
2762 | { | 3039 | { |
2763 | struct inode *inode = state->inode; | 3040 | struct inode *inode = state->inode; |
2764 | struct nfs_server *server = NFS_SERVER(inode); | 3041 | struct nfs_server *server = NFS_SERVER(inode); |
2765 | struct nfs4_client *clp = server->nfs4_state; | 3042 | struct nfs4_client *clp = server->nfs4_state; |
2766 | struct nfs_lockargs arg = { | 3043 | struct nfs_lockt_args arg = { |
2767 | .fh = NFS_FH(inode), | 3044 | .fh = NFS_FH(inode), |
2768 | .type = nfs4_lck_type(cmd, request), | 3045 | .fl = request, |
2769 | .offset = request->fl_start, | ||
2770 | .length = nfs4_lck_length(request), | ||
2771 | }; | 3046 | }; |
2772 | struct nfs_lockres res = { | 3047 | struct nfs_lockt_res res = { |
2773 | .server = server, | 3048 | .denied = request, |
2774 | }; | 3049 | }; |
2775 | struct rpc_message msg = { | 3050 | struct rpc_message msg = { |
2776 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], | 3051 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], |
@@ -2778,36 +3053,23 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2778 | .rpc_resp = &res, | 3053 | .rpc_resp = &res, |
2779 | .rpc_cred = state->owner->so_cred, | 3054 | .rpc_cred = state->owner->so_cred, |
2780 | }; | 3055 | }; |
2781 | struct nfs_lowner nlo; | ||
2782 | struct nfs4_lock_state *lsp; | 3056 | struct nfs4_lock_state *lsp; |
2783 | int status; | 3057 | int status; |
2784 | 3058 | ||
2785 | down_read(&clp->cl_sem); | 3059 | down_read(&clp->cl_sem); |
2786 | nlo.clientid = clp->cl_clientid; | 3060 | arg.lock_owner.clientid = clp->cl_clientid; |
2787 | status = nfs4_set_lock_state(state, request); | 3061 | status = nfs4_set_lock_state(state, request); |
2788 | if (status != 0) | 3062 | if (status != 0) |
2789 | goto out; | 3063 | goto out; |
2790 | lsp = request->fl_u.nfs4_fl.owner; | 3064 | lsp = request->fl_u.nfs4_fl.owner; |
2791 | nlo.id = lsp->ls_id; | 3065 | arg.lock_owner.id = lsp->ls_id; |
2792 | arg.u.lockt = &nlo; | ||
2793 | status = rpc_call_sync(server->client, &msg, 0); | 3066 | status = rpc_call_sync(server->client, &msg, 0); |
2794 | if (!status) { | 3067 | switch (status) { |
2795 | request->fl_type = F_UNLCK; | 3068 | case 0: |
2796 | } else if (status == -NFS4ERR_DENIED) { | 3069 | request->fl_type = F_UNLCK; |
2797 | int64_t len, start, end; | 3070 | break; |
2798 | start = res.u.denied.offset; | 3071 | case -NFS4ERR_DENIED: |
2799 | len = res.u.denied.length; | 3072 | status = 0; |
2800 | end = start + len - 1; | ||
2801 | if (end < 0 || len == 0) | ||
2802 | request->fl_end = OFFSET_MAX; | ||
2803 | else | ||
2804 | request->fl_end = (loff_t)end; | ||
2805 | request->fl_start = (loff_t)start; | ||
2806 | request->fl_type = F_WRLCK; | ||
2807 | if (res.u.denied.type & 1) | ||
2808 | request->fl_type = F_RDLCK; | ||
2809 | request->fl_pid = 0; | ||
2810 | status = 0; | ||
2811 | } | 3073 | } |
2812 | out: | 3074 | out: |
2813 | up_read(&clp->cl_sem); | 3075 | up_read(&clp->cl_sem); |
@@ -2847,196 +3109,314 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
2847 | } | 3109 | } |
2848 | 3110 | ||
2849 | struct nfs4_unlockdata { | 3111 | struct nfs4_unlockdata { |
2850 | struct nfs_lockargs arg; | 3112 | struct nfs_locku_args arg; |
2851 | struct nfs_locku_opargs luargs; | 3113 | struct nfs_locku_res res; |
2852 | struct nfs_lockres res; | ||
2853 | struct nfs4_lock_state *lsp; | 3114 | struct nfs4_lock_state *lsp; |
2854 | struct nfs_open_context *ctx; | 3115 | struct nfs_open_context *ctx; |
2855 | atomic_t refcount; | 3116 | struct file_lock fl; |
2856 | struct completion completion; | 3117 | const struct nfs_server *server; |
3118 | unsigned long timestamp; | ||
2857 | }; | 3119 | }; |
2858 | 3120 | ||
2859 | static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata) | 3121 | static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, |
2860 | { | 3122 | struct nfs_open_context *ctx, |
2861 | if (atomic_dec_and_test(&calldata->refcount)) { | 3123 | struct nfs4_lock_state *lsp, |
2862 | nfs_free_seqid(calldata->luargs.seqid); | 3124 | struct nfs_seqid *seqid) |
2863 | nfs4_put_lock_state(calldata->lsp); | 3125 | { |
2864 | put_nfs_open_context(calldata->ctx); | 3126 | struct nfs4_unlockdata *p; |
2865 | kfree(calldata); | 3127 | struct inode *inode = lsp->ls_state->inode; |
2866 | } | 3128 | |
3129 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
3130 | if (p == NULL) | ||
3131 | return NULL; | ||
3132 | p->arg.fh = NFS_FH(inode); | ||
3133 | p->arg.fl = &p->fl; | ||
3134 | p->arg.seqid = seqid; | ||
3135 | p->arg.stateid = &lsp->ls_stateid; | ||
3136 | p->lsp = lsp; | ||
3137 | atomic_inc(&lsp->ls_count); | ||
3138 | /* Ensure we don't close file until we're done freeing locks! */ | ||
3139 | p->ctx = get_nfs_open_context(ctx); | ||
3140 | memcpy(&p->fl, fl, sizeof(p->fl)); | ||
3141 | p->server = NFS_SERVER(inode); | ||
3142 | return p; | ||
2867 | } | 3143 | } |
2868 | 3144 | ||
2869 | static void nfs4_locku_complete(struct nfs4_unlockdata *calldata) | 3145 | static void nfs4_locku_release_calldata(void *data) |
2870 | { | 3146 | { |
2871 | complete(&calldata->completion); | 3147 | struct nfs4_unlockdata *calldata = data; |
2872 | nfs4_locku_release_calldata(calldata); | 3148 | nfs_free_seqid(calldata->arg.seqid); |
3149 | nfs4_put_lock_state(calldata->lsp); | ||
3150 | put_nfs_open_context(calldata->ctx); | ||
3151 | kfree(calldata); | ||
2873 | } | 3152 | } |
2874 | 3153 | ||
2875 | static void nfs4_locku_done(struct rpc_task *task) | 3154 | static void nfs4_locku_done(struct rpc_task *task, void *data) |
2876 | { | 3155 | { |
2877 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | 3156 | struct nfs4_unlockdata *calldata = data; |
2878 | 3157 | ||
2879 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); | 3158 | if (RPC_ASSASSINATED(task)) |
3159 | return; | ||
3160 | nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid); | ||
2880 | switch (task->tk_status) { | 3161 | switch (task->tk_status) { |
2881 | case 0: | 3162 | case 0: |
2882 | memcpy(calldata->lsp->ls_stateid.data, | 3163 | memcpy(calldata->lsp->ls_stateid.data, |
2883 | calldata->res.u.stateid.data, | 3164 | calldata->res.stateid.data, |
2884 | sizeof(calldata->lsp->ls_stateid.data)); | 3165 | sizeof(calldata->lsp->ls_stateid.data)); |
3166 | renew_lease(calldata->server, calldata->timestamp); | ||
2885 | break; | 3167 | break; |
2886 | case -NFS4ERR_STALE_STATEID: | 3168 | case -NFS4ERR_STALE_STATEID: |
2887 | case -NFS4ERR_EXPIRED: | 3169 | case -NFS4ERR_EXPIRED: |
2888 | nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); | 3170 | nfs4_schedule_state_recovery(calldata->server->nfs4_state); |
2889 | break; | 3171 | break; |
2890 | default: | 3172 | default: |
2891 | if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { | 3173 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { |
2892 | rpc_restart_call(task); | 3174 | rpc_restart_call(task); |
2893 | return; | ||
2894 | } | 3175 | } |
2895 | } | 3176 | } |
2896 | nfs4_locku_complete(calldata); | ||
2897 | } | 3177 | } |
2898 | 3178 | ||
2899 | static void nfs4_locku_begin(struct rpc_task *task) | 3179 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
2900 | { | 3180 | { |
2901 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | 3181 | struct nfs4_unlockdata *calldata = data; |
2902 | struct rpc_message msg = { | 3182 | struct rpc_message msg = { |
2903 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | 3183 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], |
2904 | .rpc_argp = &calldata->arg, | 3184 | .rpc_argp = &calldata->arg, |
2905 | .rpc_resp = &calldata->res, | 3185 | .rpc_resp = &calldata->res, |
2906 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, | 3186 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, |
2907 | }; | 3187 | }; |
2908 | int status; | ||
2909 | 3188 | ||
2910 | status = nfs_wait_on_sequence(calldata->luargs.seqid, task); | 3189 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
2911 | if (status != 0) | ||
2912 | return; | 3190 | return; |
2913 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { | 3191 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { |
2914 | nfs4_locku_complete(calldata); | 3192 | /* Note: exit _without_ running nfs4_locku_done */ |
2915 | task->tk_exit = NULL; | 3193 | task->tk_action = NULL; |
2916 | rpc_exit(task, 0); | ||
2917 | return; | 3194 | return; |
2918 | } | 3195 | } |
3196 | calldata->timestamp = jiffies; | ||
2919 | rpc_call_setup(task, &msg, 0); | 3197 | rpc_call_setup(task, &msg, 0); |
2920 | } | 3198 | } |
2921 | 3199 | ||
3200 | static const struct rpc_call_ops nfs4_locku_ops = { | ||
3201 | .rpc_call_prepare = nfs4_locku_prepare, | ||
3202 | .rpc_call_done = nfs4_locku_done, | ||
3203 | .rpc_release = nfs4_locku_release_calldata, | ||
3204 | }; | ||
3205 | |||
3206 | static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | ||
3207 | struct nfs_open_context *ctx, | ||
3208 | struct nfs4_lock_state *lsp, | ||
3209 | struct nfs_seqid *seqid) | ||
3210 | { | ||
3211 | struct nfs4_unlockdata *data; | ||
3212 | struct rpc_task *task; | ||
3213 | |||
3214 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | ||
3215 | if (data == NULL) { | ||
3216 | nfs_free_seqid(seqid); | ||
3217 | return ERR_PTR(-ENOMEM); | ||
3218 | } | ||
3219 | |||
3220 | /* Unlock _before_ we do the RPC call */ | ||
3221 | do_vfs_lock(fl->fl_file, fl); | ||
3222 | task = rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | ||
3223 | if (IS_ERR(task)) | ||
3224 | nfs4_locku_release_calldata(data); | ||
3225 | return task; | ||
3226 | } | ||
3227 | |||
2922 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3228 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
2923 | { | 3229 | { |
2924 | struct nfs4_unlockdata *calldata; | 3230 | struct nfs_seqid *seqid; |
2925 | struct inode *inode = state->inode; | ||
2926 | struct nfs_server *server = NFS_SERVER(inode); | ||
2927 | struct nfs4_lock_state *lsp; | 3231 | struct nfs4_lock_state *lsp; |
2928 | int status; | 3232 | struct rpc_task *task; |
3233 | int status = 0; | ||
2929 | 3234 | ||
2930 | /* Is this a delegated lock? */ | 3235 | /* Is this a delegated lock? */ |
2931 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 3236 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
2932 | return do_vfs_lock(request->fl_file, request); | 3237 | goto out_unlock; |
3238 | /* Is this open_owner holding any locks on the server? */ | ||
3239 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | ||
3240 | goto out_unlock; | ||
2933 | 3241 | ||
2934 | status = nfs4_set_lock_state(state, request); | 3242 | status = nfs4_set_lock_state(state, request); |
2935 | if (status != 0) | 3243 | if (status != 0) |
2936 | return status; | 3244 | goto out_unlock; |
2937 | lsp = request->fl_u.nfs4_fl.owner; | 3245 | lsp = request->fl_u.nfs4_fl.owner; |
2938 | /* We might have lost the locks! */ | 3246 | status = -ENOMEM; |
2939 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) | 3247 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2940 | return 0; | 3248 | if (seqid == NULL) |
2941 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 3249 | goto out_unlock; |
2942 | if (calldata == NULL) | 3250 | task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); |
2943 | return -ENOMEM; | 3251 | status = PTR_ERR(task); |
2944 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3252 | if (IS_ERR(task)) |
2945 | if (calldata->luargs.seqid == NULL) { | 3253 | goto out_unlock; |
2946 | kfree(calldata); | 3254 | status = nfs4_wait_for_completion_rpc_task(task); |
2947 | return -ENOMEM; | 3255 | rpc_release_task(task); |
2948 | } | 3256 | return status; |
2949 | calldata->luargs.stateid = &lsp->ls_stateid; | 3257 | out_unlock: |
2950 | calldata->arg.fh = NFS_FH(inode); | ||
2951 | calldata->arg.type = nfs4_lck_type(cmd, request); | ||
2952 | calldata->arg.offset = request->fl_start; | ||
2953 | calldata->arg.length = nfs4_lck_length(request); | ||
2954 | calldata->arg.u.locku = &calldata->luargs; | ||
2955 | calldata->res.server = server; | ||
2956 | calldata->lsp = lsp; | ||
2957 | atomic_inc(&lsp->ls_count); | ||
2958 | |||
2959 | /* Ensure we don't close file until we're done freeing locks! */ | ||
2960 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); | ||
2961 | |||
2962 | atomic_set(&calldata->refcount, 2); | ||
2963 | init_completion(&calldata->completion); | ||
2964 | |||
2965 | status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_locku_begin, | ||
2966 | nfs4_locku_done, calldata); | ||
2967 | if (status == 0) | ||
2968 | wait_for_completion_interruptible(&calldata->completion); | ||
2969 | do_vfs_lock(request->fl_file, request); | 3258 | do_vfs_lock(request->fl_file, request); |
2970 | nfs4_locku_release_calldata(calldata); | ||
2971 | return status; | 3259 | return status; |
2972 | } | 3260 | } |
2973 | 3261 | ||
2974 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) | 3262 | struct nfs4_lockdata { |
3263 | struct nfs_lock_args arg; | ||
3264 | struct nfs_lock_res res; | ||
3265 | struct nfs4_lock_state *lsp; | ||
3266 | struct nfs_open_context *ctx; | ||
3267 | struct file_lock fl; | ||
3268 | unsigned long timestamp; | ||
3269 | int rpc_status; | ||
3270 | int cancelled; | ||
3271 | }; | ||
3272 | |||
3273 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | ||
3274 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp) | ||
2975 | { | 3275 | { |
2976 | struct inode *inode = state->inode; | 3276 | struct nfs4_lockdata *p; |
3277 | struct inode *inode = lsp->ls_state->inode; | ||
2977 | struct nfs_server *server = NFS_SERVER(inode); | 3278 | struct nfs_server *server = NFS_SERVER(inode); |
2978 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; | 3279 | |
2979 | struct nfs_lock_opargs largs = { | 3280 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
2980 | .lock_stateid = &lsp->ls_stateid, | 3281 | if (p == NULL) |
2981 | .open_stateid = &state->stateid, | 3282 | return NULL; |
2982 | .lock_owner = { | 3283 | |
2983 | .clientid = server->nfs4_state->cl_clientid, | 3284 | p->arg.fh = NFS_FH(inode); |
2984 | .id = lsp->ls_id, | 3285 | p->arg.fl = &p->fl; |
2985 | }, | 3286 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2986 | .reclaim = reclaim, | 3287 | if (p->arg.lock_seqid == NULL) |
2987 | }; | 3288 | goto out_free; |
2988 | struct nfs_lockargs arg = { | 3289 | p->arg.lock_stateid = &lsp->ls_stateid; |
2989 | .fh = NFS_FH(inode), | 3290 | p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; |
2990 | .type = nfs4_lck_type(cmd, request), | 3291 | p->arg.lock_owner.id = lsp->ls_id; |
2991 | .offset = request->fl_start, | 3292 | p->lsp = lsp; |
2992 | .length = nfs4_lck_length(request), | 3293 | atomic_inc(&lsp->ls_count); |
2993 | .u = { | 3294 | p->ctx = get_nfs_open_context(ctx); |
2994 | .lock = &largs, | 3295 | memcpy(&p->fl, fl, sizeof(p->fl)); |
2995 | }, | 3296 | return p; |
2996 | }; | 3297 | out_free: |
2997 | struct nfs_lockres res = { | 3298 | kfree(p); |
2998 | .server = server, | 3299 | return NULL; |
2999 | }; | 3300 | } |
3301 | |||
3302 | static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | ||
3303 | { | ||
3304 | struct nfs4_lockdata *data = calldata; | ||
3305 | struct nfs4_state *state = data->lsp->ls_state; | ||
3306 | struct nfs4_state_owner *sp = state->owner; | ||
3000 | struct rpc_message msg = { | 3307 | struct rpc_message msg = { |
3001 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | 3308 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], |
3002 | .rpc_argp = &arg, | 3309 | .rpc_argp = &data->arg, |
3003 | .rpc_resp = &res, | 3310 | .rpc_resp = &data->res, |
3004 | .rpc_cred = state->owner->so_cred, | 3311 | .rpc_cred = sp->so_cred, |
3005 | }; | 3312 | }; |
3006 | int status = -ENOMEM; | ||
3007 | |||
3008 | largs.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | ||
3009 | if (largs.lock_seqid == NULL) | ||
3010 | return -ENOMEM; | ||
3011 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | ||
3012 | struct nfs4_state_owner *owner = state->owner; | ||
3013 | 3313 | ||
3014 | largs.open_seqid = nfs_alloc_seqid(&owner->so_seqid); | 3314 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) |
3015 | if (largs.open_seqid == NULL) | 3315 | return; |
3316 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3317 | /* Do we need to do an open_to_lock_owner? */ | ||
3318 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { | ||
3319 | data->arg.open_seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
3320 | if (data->arg.open_seqid == NULL) { | ||
3321 | data->rpc_status = -ENOMEM; | ||
3322 | task->tk_action = NULL; | ||
3016 | goto out; | 3323 | goto out; |
3017 | largs.new_lock_owner = 1; | ||
3018 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | ||
3019 | /* increment open seqid on success, and seqid mutating errors */ | ||
3020 | if (largs.new_lock_owner != 0) { | ||
3021 | nfs_increment_open_seqid(status, largs.open_seqid); | ||
3022 | if (status == 0) | ||
3023 | nfs_confirm_seqid(&lsp->ls_seqid, 0); | ||
3024 | } | 3324 | } |
3025 | nfs_free_seqid(largs.open_seqid); | 3325 | data->arg.open_stateid = &state->stateid; |
3026 | } else | 3326 | data->arg.new_lock_owner = 1; |
3027 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3327 | } |
3028 | /* increment lock seqid on success, and seqid mutating errors*/ | 3328 | data->timestamp = jiffies; |
3029 | nfs_increment_lock_seqid(status, largs.lock_seqid); | 3329 | rpc_call_setup(task, &msg, 0); |
3030 | /* save the returned stateid. */ | ||
3031 | if (status == 0) { | ||
3032 | memcpy(lsp->ls_stateid.data, res.u.stateid.data, | ||
3033 | sizeof(lsp->ls_stateid.data)); | ||
3034 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
3035 | } else if (status == -NFS4ERR_DENIED) | ||
3036 | status = -EAGAIN; | ||
3037 | out: | 3330 | out: |
3038 | nfs_free_seqid(largs.lock_seqid); | 3331 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); |
3039 | return status; | 3332 | } |
3333 | |||
3334 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) | ||
3335 | { | ||
3336 | struct nfs4_lockdata *data = calldata; | ||
3337 | |||
3338 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3339 | |||
3340 | data->rpc_status = task->tk_status; | ||
3341 | if (RPC_ASSASSINATED(task)) | ||
3342 | goto out; | ||
3343 | if (data->arg.new_lock_owner != 0) { | ||
3344 | nfs_increment_open_seqid(data->rpc_status, data->arg.open_seqid); | ||
3345 | if (data->rpc_status == 0) | ||
3346 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | ||
3347 | else | ||
3348 | goto out; | ||
3349 | } | ||
3350 | if (data->rpc_status == 0) { | ||
3351 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | ||
3352 | sizeof(data->lsp->ls_stateid.data)); | ||
3353 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
3354 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); | ||
3355 | } | ||
3356 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | ||
3357 | out: | ||
3358 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); | ||
3359 | } | ||
3360 | |||
3361 | static void nfs4_lock_release(void *calldata) | ||
3362 | { | ||
3363 | struct nfs4_lockdata *data = calldata; | ||
3364 | |||
3365 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3366 | if (data->arg.open_seqid != NULL) | ||
3367 | nfs_free_seqid(data->arg.open_seqid); | ||
3368 | if (data->cancelled != 0) { | ||
3369 | struct rpc_task *task; | ||
3370 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | ||
3371 | data->arg.lock_seqid); | ||
3372 | if (!IS_ERR(task)) | ||
3373 | rpc_release_task(task); | ||
3374 | dprintk("%s: cancelling lock!\n", __FUNCTION__); | ||
3375 | } else | ||
3376 | nfs_free_seqid(data->arg.lock_seqid); | ||
3377 | nfs4_put_lock_state(data->lsp); | ||
3378 | put_nfs_open_context(data->ctx); | ||
3379 | kfree(data); | ||
3380 | dprintk("%s: done!\n", __FUNCTION__); | ||
3381 | } | ||
3382 | |||
3383 | static const struct rpc_call_ops nfs4_lock_ops = { | ||
3384 | .rpc_call_prepare = nfs4_lock_prepare, | ||
3385 | .rpc_call_done = nfs4_lock_done, | ||
3386 | .rpc_release = nfs4_lock_release, | ||
3387 | }; | ||
3388 | |||
3389 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) | ||
3390 | { | ||
3391 | struct nfs4_lockdata *data; | ||
3392 | struct rpc_task *task; | ||
3393 | int ret; | ||
3394 | |||
3395 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3396 | data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data, | ||
3397 | fl->fl_u.nfs4_fl.owner); | ||
3398 | if (data == NULL) | ||
3399 | return -ENOMEM; | ||
3400 | if (IS_SETLKW(cmd)) | ||
3401 | data->arg.block = 1; | ||
3402 | if (reclaim != 0) | ||
3403 | data->arg.reclaim = 1; | ||
3404 | task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, | ||
3405 | &nfs4_lock_ops, data); | ||
3406 | if (IS_ERR(task)) { | ||
3407 | nfs4_lock_release(data); | ||
3408 | return PTR_ERR(task); | ||
3409 | } | ||
3410 | ret = nfs4_wait_for_completion_rpc_task(task); | ||
3411 | if (ret == 0) { | ||
3412 | ret = data->rpc_status; | ||
3413 | if (ret == -NFS4ERR_DENIED) | ||
3414 | ret = -EAGAIN; | ||
3415 | } else | ||
3416 | data->cancelled = 1; | ||
3417 | rpc_release_task(task); | ||
3418 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); | ||
3419 | return ret; | ||
3040 | } | 3420 | } |
3041 | 3421 | ||
3042 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 3422 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index a3001628ad32..5d764d8e6d8a 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/nfs4.h> | 54 | #include <linux/nfs4.h> |
55 | #include <linux/nfs_fs.h> | 55 | #include <linux/nfs_fs.h> |
56 | #include "nfs4_fs.h" | 56 | #include "nfs4_fs.h" |
57 | #include "delegation.h" | ||
57 | 58 | ||
58 | #define NFSDBG_FACILITY NFSDBG_PROC | 59 | #define NFSDBG_FACILITY NFSDBG_PROC |
59 | 60 | ||
@@ -61,6 +62,7 @@ void | |||
61 | nfs4_renew_state(void *data) | 62 | nfs4_renew_state(void *data) |
62 | { | 63 | { |
63 | struct nfs4_client *clp = (struct nfs4_client *)data; | 64 | struct nfs4_client *clp = (struct nfs4_client *)data; |
65 | struct rpc_cred *cred; | ||
64 | long lease, timeout; | 66 | long lease, timeout; |
65 | unsigned long last, now; | 67 | unsigned long last, now; |
66 | 68 | ||
@@ -68,7 +70,7 @@ nfs4_renew_state(void *data) | |||
68 | dprintk("%s: start\n", __FUNCTION__); | 70 | dprintk("%s: start\n", __FUNCTION__); |
69 | /* Are there any active superblocks? */ | 71 | /* Are there any active superblocks? */ |
70 | if (list_empty(&clp->cl_superblocks)) | 72 | if (list_empty(&clp->cl_superblocks)) |
71 | goto out; | 73 | goto out; |
72 | spin_lock(&clp->cl_lock); | 74 | spin_lock(&clp->cl_lock); |
73 | lease = clp->cl_lease_time; | 75 | lease = clp->cl_lease_time; |
74 | last = clp->cl_last_renewal; | 76 | last = clp->cl_last_renewal; |
@@ -76,9 +78,17 @@ nfs4_renew_state(void *data) | |||
76 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 78 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
77 | /* Are we close to a lease timeout? */ | 79 | /* Are we close to a lease timeout? */ |
78 | if (time_after(now, last + lease/3)) { | 80 | if (time_after(now, last + lease/3)) { |
81 | cred = nfs4_get_renew_cred(clp); | ||
82 | if (cred == NULL) { | ||
83 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
84 | spin_unlock(&clp->cl_lock); | ||
85 | nfs_expire_all_delegations(clp); | ||
86 | goto out; | ||
87 | } | ||
79 | spin_unlock(&clp->cl_lock); | 88 | spin_unlock(&clp->cl_lock); |
80 | /* Queue an asynchronous RENEW. */ | 89 | /* Queue an asynchronous RENEW. */ |
81 | nfs4_proc_async_renew(clp); | 90 | nfs4_proc_async_renew(clp, cred); |
91 | put_rpccred(cred); | ||
82 | timeout = (2 * lease) / 3; | 92 | timeout = (2 * lease) / 3; |
83 | spin_lock(&clp->cl_lock); | 93 | spin_lock(&clp->cl_lock); |
84 | } else | 94 | } else |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5ef4c57618fe..afad0255e7db 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -43,6 +43,8 @@ | |||
43 | #include <linux/smp_lock.h> | 43 | #include <linux/smp_lock.h> |
44 | #include <linux/nfs_fs.h> | 44 | #include <linux/nfs_fs.h> |
45 | #include <linux/nfs_idmap.h> | 45 | #include <linux/nfs_idmap.h> |
46 | #include <linux/kthread.h> | ||
47 | #include <linux/module.h> | ||
46 | #include <linux/workqueue.h> | 48 | #include <linux/workqueue.h> |
47 | #include <linux/bitops.h> | 49 | #include <linux/bitops.h> |
48 | 50 | ||
@@ -57,8 +59,6 @@ const nfs4_stateid zero_stateid; | |||
57 | static DEFINE_SPINLOCK(state_spinlock); | 59 | static DEFINE_SPINLOCK(state_spinlock); |
58 | static LIST_HEAD(nfs4_clientid_list); | 60 | static LIST_HEAD(nfs4_clientid_list); |
59 | 61 | ||
60 | static void nfs4_recover_state(void *); | ||
61 | |||
62 | void | 62 | void |
63 | init_nfsv4_state(struct nfs_server *server) | 63 | init_nfsv4_state(struct nfs_server *server) |
64 | { | 64 | { |
@@ -91,11 +91,10 @@ nfs4_alloc_client(struct in_addr *addr) | |||
91 | 91 | ||
92 | if (nfs_callback_up() < 0) | 92 | if (nfs_callback_up() < 0) |
93 | return NULL; | 93 | return NULL; |
94 | if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { | 94 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { |
95 | nfs_callback_down(); | 95 | nfs_callback_down(); |
96 | return NULL; | 96 | return NULL; |
97 | } | 97 | } |
98 | memset(clp, 0, sizeof(*clp)); | ||
99 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | 98 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); |
100 | init_rwsem(&clp->cl_sem); | 99 | init_rwsem(&clp->cl_sem); |
101 | INIT_LIST_HEAD(&clp->cl_delegations); | 100 | INIT_LIST_HEAD(&clp->cl_delegations); |
@@ -103,14 +102,12 @@ nfs4_alloc_client(struct in_addr *addr) | |||
103 | INIT_LIST_HEAD(&clp->cl_unused); | 102 | INIT_LIST_HEAD(&clp->cl_unused); |
104 | spin_lock_init(&clp->cl_lock); | 103 | spin_lock_init(&clp->cl_lock); |
105 | atomic_set(&clp->cl_count, 1); | 104 | atomic_set(&clp->cl_count, 1); |
106 | INIT_WORK(&clp->cl_recoverd, nfs4_recover_state, clp); | ||
107 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | 105 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); |
108 | INIT_LIST_HEAD(&clp->cl_superblocks); | 106 | INIT_LIST_HEAD(&clp->cl_superblocks); |
109 | init_waitqueue_head(&clp->cl_waitq); | ||
110 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | 107 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); |
111 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 108 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
112 | clp->cl_boot_time = CURRENT_TIME; | 109 | clp->cl_boot_time = CURRENT_TIME; |
113 | clp->cl_state = 1 << NFS4CLNT_OK; | 110 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
114 | return clp; | 111 | return clp; |
115 | } | 112 | } |
116 | 113 | ||
@@ -127,8 +124,6 @@ nfs4_free_client(struct nfs4_client *clp) | |||
127 | kfree(sp); | 124 | kfree(sp); |
128 | } | 125 | } |
129 | BUG_ON(!list_empty(&clp->cl_state_owners)); | 126 | BUG_ON(!list_empty(&clp->cl_state_owners)); |
130 | if (clp->cl_cred) | ||
131 | put_rpccred(clp->cl_cred); | ||
132 | nfs_idmap_delete(clp); | 127 | nfs_idmap_delete(clp); |
133 | if (!IS_ERR(clp->cl_rpcclient)) | 128 | if (!IS_ERR(clp->cl_rpcclient)) |
134 | rpc_shutdown_client(clp->cl_rpcclient); | 129 | rpc_shutdown_client(clp->cl_rpcclient); |
@@ -193,27 +188,22 @@ nfs4_put_client(struct nfs4_client *clp) | |||
193 | list_del(&clp->cl_servers); | 188 | list_del(&clp->cl_servers); |
194 | spin_unlock(&state_spinlock); | 189 | spin_unlock(&state_spinlock); |
195 | BUG_ON(!list_empty(&clp->cl_superblocks)); | 190 | BUG_ON(!list_empty(&clp->cl_superblocks)); |
196 | wake_up_all(&clp->cl_waitq); | ||
197 | rpc_wake_up(&clp->cl_rpcwaitq); | 191 | rpc_wake_up(&clp->cl_rpcwaitq); |
198 | nfs4_kill_renewd(clp); | 192 | nfs4_kill_renewd(clp); |
199 | nfs4_free_client(clp); | 193 | nfs4_free_client(clp); |
200 | } | 194 | } |
201 | 195 | ||
202 | static int __nfs4_init_client(struct nfs4_client *clp) | 196 | static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) |
203 | { | 197 | { |
204 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport); | 198 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, |
199 | nfs_callback_tcpport, cred); | ||
205 | if (status == 0) | 200 | if (status == 0) |
206 | status = nfs4_proc_setclientid_confirm(clp); | 201 | status = nfs4_proc_setclientid_confirm(clp, cred); |
207 | if (status == 0) | 202 | if (status == 0) |
208 | nfs4_schedule_state_renewal(clp); | 203 | nfs4_schedule_state_renewal(clp); |
209 | return status; | 204 | return status; |
210 | } | 205 | } |
211 | 206 | ||
212 | int nfs4_init_client(struct nfs4_client *clp) | ||
213 | { | ||
214 | return nfs4_map_errors(__nfs4_init_client(clp)); | ||
215 | } | ||
216 | |||
217 | u32 | 207 | u32 |
218 | nfs4_alloc_lockowner_id(struct nfs4_client *clp) | 208 | nfs4_alloc_lockowner_id(struct nfs4_client *clp) |
219 | { | 209 | { |
@@ -235,6 +225,32 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | |||
235 | return sp; | 225 | return sp; |
236 | } | 226 | } |
237 | 227 | ||
228 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | ||
229 | { | ||
230 | struct nfs4_state_owner *sp; | ||
231 | struct rpc_cred *cred = NULL; | ||
232 | |||
233 | list_for_each_entry(sp, &clp->cl_state_owners, so_list) { | ||
234 | if (list_empty(&sp->so_states)) | ||
235 | continue; | ||
236 | cred = get_rpccred(sp->so_cred); | ||
237 | break; | ||
238 | } | ||
239 | return cred; | ||
240 | } | ||
241 | |||
242 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | ||
243 | { | ||
244 | struct nfs4_state_owner *sp; | ||
245 | |||
246 | if (!list_empty(&clp->cl_state_owners)) { | ||
247 | sp = list_entry(clp->cl_state_owners.next, | ||
248 | struct nfs4_state_owner, so_list); | ||
249 | return get_rpccred(sp->so_cred); | ||
250 | } | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
238 | static struct nfs4_state_owner * | 254 | static struct nfs4_state_owner * |
239 | nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) | 255 | nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) |
240 | { | 256 | { |
@@ -349,14 +365,9 @@ nfs4_alloc_open_state(void) | |||
349 | { | 365 | { |
350 | struct nfs4_state *state; | 366 | struct nfs4_state *state; |
351 | 367 | ||
352 | state = kmalloc(sizeof(*state), GFP_KERNEL); | 368 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
353 | if (!state) | 369 | if (!state) |
354 | return NULL; | 370 | return NULL; |
355 | state->state = 0; | ||
356 | state->nreaders = 0; | ||
357 | state->nwriters = 0; | ||
358 | state->flags = 0; | ||
359 | memset(state->stateid.data, 0, sizeof(state->stateid.data)); | ||
360 | atomic_set(&state->count, 1); | 371 | atomic_set(&state->count, 1); |
361 | INIT_LIST_HEAD(&state->lock_states); | 372 | INIT_LIST_HEAD(&state->lock_states); |
362 | spin_lock_init(&state->state_lock); | 373 | spin_lock_init(&state->state_lock); |
@@ -475,15 +486,23 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) | |||
475 | /* Protect against nfs4_find_state() */ | 486 | /* Protect against nfs4_find_state() */ |
476 | spin_lock(&owner->so_lock); | 487 | spin_lock(&owner->so_lock); |
477 | spin_lock(&inode->i_lock); | 488 | spin_lock(&inode->i_lock); |
478 | if (mode & FMODE_READ) | 489 | switch (mode & (FMODE_READ | FMODE_WRITE)) { |
479 | state->nreaders--; | 490 | case FMODE_READ: |
480 | if (mode & FMODE_WRITE) | 491 | state->n_rdonly--; |
481 | state->nwriters--; | 492 | break; |
493 | case FMODE_WRITE: | ||
494 | state->n_wronly--; | ||
495 | break; | ||
496 | case FMODE_READ|FMODE_WRITE: | ||
497 | state->n_rdwr--; | ||
498 | } | ||
482 | oldstate = newstate = state->state; | 499 | oldstate = newstate = state->state; |
483 | if (state->nreaders == 0) | 500 | if (state->n_rdwr == 0) { |
484 | newstate &= ~FMODE_READ; | 501 | if (state->n_rdonly == 0) |
485 | if (state->nwriters == 0) | 502 | newstate &= ~FMODE_READ; |
486 | newstate &= ~FMODE_WRITE; | 503 | if (state->n_wronly == 0) |
504 | newstate &= ~FMODE_WRITE; | ||
505 | } | ||
487 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 506 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
488 | nfs4_state_set_mode_locked(state, newstate); | 507 | nfs4_state_set_mode_locked(state, newstate); |
489 | oldstate = newstate; | 508 | oldstate = newstate; |
@@ -733,45 +752,43 @@ out: | |||
733 | } | 752 | } |
734 | 753 | ||
735 | static int reclaimer(void *); | 754 | static int reclaimer(void *); |
736 | struct reclaimer_args { | 755 | |
737 | struct nfs4_client *clp; | 756 | static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) |
738 | struct completion complete; | 757 | { |
739 | }; | 758 | smp_mb__before_clear_bit(); |
759 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); | ||
760 | smp_mb__after_clear_bit(); | ||
761 | wake_up_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER); | ||
762 | rpc_wake_up(&clp->cl_rpcwaitq); | ||
763 | } | ||
740 | 764 | ||
741 | /* | 765 | /* |
742 | * State recovery routine | 766 | * State recovery routine |
743 | */ | 767 | */ |
744 | void | 768 | static void nfs4_recover_state(struct nfs4_client *clp) |
745 | nfs4_recover_state(void *data) | ||
746 | { | 769 | { |
747 | struct nfs4_client *clp = (struct nfs4_client *)data; | 770 | struct task_struct *task; |
748 | struct reclaimer_args args = { | ||
749 | .clp = clp, | ||
750 | }; | ||
751 | might_sleep(); | ||
752 | |||
753 | init_completion(&args.complete); | ||
754 | 771 | ||
755 | if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0) | 772 | __module_get(THIS_MODULE); |
756 | goto out_failed_clear; | 773 | atomic_inc(&clp->cl_count); |
757 | wait_for_completion(&args.complete); | 774 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", |
758 | return; | 775 | NIPQUAD(clp->cl_addr)); |
759 | out_failed_clear: | 776 | if (!IS_ERR(task)) |
760 | set_bit(NFS4CLNT_OK, &clp->cl_state); | 777 | return; |
761 | wake_up_all(&clp->cl_waitq); | 778 | nfs4_clear_recover_bit(clp); |
762 | rpc_wake_up(&clp->cl_rpcwaitq); | 779 | nfs4_put_client(clp); |
780 | module_put(THIS_MODULE); | ||
763 | } | 781 | } |
764 | 782 | ||
765 | /* | 783 | /* |
766 | * Schedule a state recovery attempt | 784 | * Schedule a state recovery attempt |
767 | */ | 785 | */ |
768 | void | 786 | void nfs4_schedule_state_recovery(struct nfs4_client *clp) |
769 | nfs4_schedule_state_recovery(struct nfs4_client *clp) | ||
770 | { | 787 | { |
771 | if (!clp) | 788 | if (!clp) |
772 | return; | 789 | return; |
773 | if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state)) | 790 | if (test_and_set_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) |
774 | schedule_work(&clp->cl_recoverd); | 791 | nfs4_recover_state(clp); |
775 | } | 792 | } |
776 | 793 | ||
777 | static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state) | 794 | static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state) |
@@ -887,18 +904,14 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | |||
887 | 904 | ||
888 | static int reclaimer(void *ptr) | 905 | static int reclaimer(void *ptr) |
889 | { | 906 | { |
890 | struct reclaimer_args *args = (struct reclaimer_args *)ptr; | 907 | struct nfs4_client *clp = ptr; |
891 | struct nfs4_client *clp = args->clp; | ||
892 | struct nfs4_state_owner *sp; | 908 | struct nfs4_state_owner *sp; |
893 | struct nfs4_state_recovery_ops *ops; | 909 | struct nfs4_state_recovery_ops *ops; |
910 | struct rpc_cred *cred; | ||
894 | int status = 0; | 911 | int status = 0; |
895 | 912 | ||
896 | daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr)); | ||
897 | allow_signal(SIGKILL); | 913 | allow_signal(SIGKILL); |
898 | 914 | ||
899 | atomic_inc(&clp->cl_count); | ||
900 | complete(&args->complete); | ||
901 | |||
902 | /* Ensure exclusive access to NFSv4 state */ | 915 | /* Ensure exclusive access to NFSv4 state */ |
903 | lock_kernel(); | 916 | lock_kernel(); |
904 | down_write(&clp->cl_sem); | 917 | down_write(&clp->cl_sem); |
@@ -906,20 +919,33 @@ static int reclaimer(void *ptr) | |||
906 | if (list_empty(&clp->cl_superblocks)) | 919 | if (list_empty(&clp->cl_superblocks)) |
907 | goto out; | 920 | goto out; |
908 | restart_loop: | 921 | restart_loop: |
909 | status = nfs4_proc_renew(clp); | 922 | ops = &nfs4_network_partition_recovery_ops; |
910 | switch (status) { | 923 | /* Are there any open files on this volume? */ |
911 | case 0: | 924 | cred = nfs4_get_renew_cred(clp); |
912 | case -NFS4ERR_CB_PATH_DOWN: | 925 | if (cred != NULL) { |
913 | goto out; | 926 | /* Yes there are: try to renew the old lease */ |
914 | case -NFS4ERR_STALE_CLIENTID: | 927 | status = nfs4_proc_renew(clp, cred); |
915 | case -NFS4ERR_LEASE_MOVED: | 928 | switch (status) { |
916 | ops = &nfs4_reboot_recovery_ops; | 929 | case 0: |
917 | break; | 930 | case -NFS4ERR_CB_PATH_DOWN: |
918 | default: | 931 | put_rpccred(cred); |
919 | ops = &nfs4_network_partition_recovery_ops; | 932 | goto out; |
920 | }; | 933 | case -NFS4ERR_STALE_CLIENTID: |
934 | case -NFS4ERR_LEASE_MOVED: | ||
935 | ops = &nfs4_reboot_recovery_ops; | ||
936 | } | ||
937 | } else { | ||
938 | /* "reboot" to ensure we clear all state on the server */ | ||
939 | clp->cl_boot_time = CURRENT_TIME; | ||
940 | cred = nfs4_get_setclientid_cred(clp); | ||
941 | } | ||
942 | /* We're going to have to re-establish a clientid */ | ||
921 | nfs4_state_mark_reclaim(clp); | 943 | nfs4_state_mark_reclaim(clp); |
922 | status = __nfs4_init_client(clp); | 944 | status = -ENOENT; |
945 | if (cred != NULL) { | ||
946 | status = nfs4_init_client(clp, cred); | ||
947 | put_rpccred(cred); | ||
948 | } | ||
923 | if (status) | 949 | if (status) |
924 | goto out_error; | 950 | goto out_error; |
925 | /* Mark all delegations for reclaim */ | 951 | /* Mark all delegations for reclaim */ |
@@ -940,14 +966,13 @@ restart_loop: | |||
940 | } | 966 | } |
941 | nfs_delegation_reap_unclaimed(clp); | 967 | nfs_delegation_reap_unclaimed(clp); |
942 | out: | 968 | out: |
943 | set_bit(NFS4CLNT_OK, &clp->cl_state); | ||
944 | up_write(&clp->cl_sem); | 969 | up_write(&clp->cl_sem); |
945 | unlock_kernel(); | 970 | unlock_kernel(); |
946 | wake_up_all(&clp->cl_waitq); | ||
947 | rpc_wake_up(&clp->cl_rpcwaitq); | ||
948 | if (status == -NFS4ERR_CB_PATH_DOWN) | 971 | if (status == -NFS4ERR_CB_PATH_DOWN) |
949 | nfs_handle_cb_pathdown(clp); | 972 | nfs_handle_cb_pathdown(clp); |
973 | nfs4_clear_recover_bit(clp); | ||
950 | nfs4_put_client(clp); | 974 | nfs4_put_client(clp); |
975 | module_put_and_exit(0); | ||
951 | return 0; | 976 | return 0; |
952 | out_error: | 977 | out_error: |
953 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 978 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index fbbace8a30c4..4bbf5ef57785 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -392,9 +392,11 @@ static int nfs_stat_to_errno(int); | |||
392 | decode_getattr_maxsz) | 392 | decode_getattr_maxsz) |
393 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 393 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
394 | encode_putfh_maxsz + \ | 394 | encode_putfh_maxsz + \ |
395 | encode_delegreturn_maxsz) | 395 | encode_delegreturn_maxsz + \ |
396 | encode_getattr_maxsz) | ||
396 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 397 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
397 | decode_delegreturn_maxsz) | 398 | decode_delegreturn_maxsz + \ |
399 | decode_getattr_maxsz) | ||
398 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | 400 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ |
399 | encode_putfh_maxsz + \ | 401 | encode_putfh_maxsz + \ |
400 | encode_getattr_maxsz) | 402 | encode_getattr_maxsz) |
@@ -564,7 +566,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
564 | } | 566 | } |
565 | if (iap->ia_valid & ATTR_MODE) { | 567 | if (iap->ia_valid & ATTR_MODE) { |
566 | bmval1 |= FATTR4_WORD1_MODE; | 568 | bmval1 |= FATTR4_WORD1_MODE; |
567 | WRITE32(iap->ia_mode); | 569 | WRITE32(iap->ia_mode & S_IALLUGO); |
568 | } | 570 | } |
569 | if (iap->ia_valid & ATTR_UID) { | 571 | if (iap->ia_valid & ATTR_UID) { |
570 | bmval1 |= FATTR4_WORD1_OWNER; | 572 | bmval1 |= FATTR4_WORD1_OWNER; |
@@ -742,69 +744,80 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name) | |||
742 | return 0; | 744 | return 0; |
743 | } | 745 | } |
744 | 746 | ||
747 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | ||
748 | { | ||
749 | if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK) | ||
750 | return block ? NFS4_READW_LT : NFS4_READ_LT; | ||
751 | return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT; | ||
752 | } | ||
753 | |||
754 | static inline uint64_t nfs4_lock_length(struct file_lock *fl) | ||
755 | { | ||
756 | if (fl->fl_end == OFFSET_MAX) | ||
757 | return ~(uint64_t)0; | ||
758 | return fl->fl_end - fl->fl_start + 1; | ||
759 | } | ||
760 | |||
745 | /* | 761 | /* |
746 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 | 762 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 |
747 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 | 763 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 |
748 | */ | 764 | */ |
749 | static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) | 765 | static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) |
750 | { | 766 | { |
751 | uint32_t *p; | 767 | uint32_t *p; |
752 | struct nfs_lock_opargs *opargs = arg->u.lock; | ||
753 | 768 | ||
754 | RESERVE_SPACE(32); | 769 | RESERVE_SPACE(32); |
755 | WRITE32(OP_LOCK); | 770 | WRITE32(OP_LOCK); |
756 | WRITE32(arg->type); | 771 | WRITE32(nfs4_lock_type(args->fl, args->block)); |
757 | WRITE32(opargs->reclaim); | 772 | WRITE32(args->reclaim); |
758 | WRITE64(arg->offset); | 773 | WRITE64(args->fl->fl_start); |
759 | WRITE64(arg->length); | 774 | WRITE64(nfs4_lock_length(args->fl)); |
760 | WRITE32(opargs->new_lock_owner); | 775 | WRITE32(args->new_lock_owner); |
761 | if (opargs->new_lock_owner){ | 776 | if (args->new_lock_owner){ |
762 | RESERVE_SPACE(40); | 777 | RESERVE_SPACE(40); |
763 | WRITE32(opargs->open_seqid->sequence->counter); | 778 | WRITE32(args->open_seqid->sequence->counter); |
764 | WRITEMEM(opargs->open_stateid->data, sizeof(opargs->open_stateid->data)); | 779 | WRITEMEM(args->open_stateid->data, sizeof(args->open_stateid->data)); |
765 | WRITE32(opargs->lock_seqid->sequence->counter); | 780 | WRITE32(args->lock_seqid->sequence->counter); |
766 | WRITE64(opargs->lock_owner.clientid); | 781 | WRITE64(args->lock_owner.clientid); |
767 | WRITE32(4); | 782 | WRITE32(4); |
768 | WRITE32(opargs->lock_owner.id); | 783 | WRITE32(args->lock_owner.id); |
769 | } | 784 | } |
770 | else { | 785 | else { |
771 | RESERVE_SPACE(20); | 786 | RESERVE_SPACE(20); |
772 | WRITEMEM(opargs->lock_stateid->data, sizeof(opargs->lock_stateid->data)); | 787 | WRITEMEM(args->lock_stateid->data, sizeof(args->lock_stateid->data)); |
773 | WRITE32(opargs->lock_seqid->sequence->counter); | 788 | WRITE32(args->lock_seqid->sequence->counter); |
774 | } | 789 | } |
775 | 790 | ||
776 | return 0; | 791 | return 0; |
777 | } | 792 | } |
778 | 793 | ||
779 | static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg) | 794 | static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args) |
780 | { | 795 | { |
781 | uint32_t *p; | 796 | uint32_t *p; |
782 | struct nfs_lowner *opargs = arg->u.lockt; | ||
783 | 797 | ||
784 | RESERVE_SPACE(40); | 798 | RESERVE_SPACE(40); |
785 | WRITE32(OP_LOCKT); | 799 | WRITE32(OP_LOCKT); |
786 | WRITE32(arg->type); | 800 | WRITE32(nfs4_lock_type(args->fl, 0)); |
787 | WRITE64(arg->offset); | 801 | WRITE64(args->fl->fl_start); |
788 | WRITE64(arg->length); | 802 | WRITE64(nfs4_lock_length(args->fl)); |
789 | WRITE64(opargs->clientid); | 803 | WRITE64(args->lock_owner.clientid); |
790 | WRITE32(4); | 804 | WRITE32(4); |
791 | WRITE32(opargs->id); | 805 | WRITE32(args->lock_owner.id); |
792 | 806 | ||
793 | return 0; | 807 | return 0; |
794 | } | 808 | } |
795 | 809 | ||
796 | static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) | 810 | static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args) |
797 | { | 811 | { |
798 | uint32_t *p; | 812 | uint32_t *p; |
799 | struct nfs_locku_opargs *opargs = arg->u.locku; | ||
800 | 813 | ||
801 | RESERVE_SPACE(44); | 814 | RESERVE_SPACE(44); |
802 | WRITE32(OP_LOCKU); | 815 | WRITE32(OP_LOCKU); |
803 | WRITE32(arg->type); | 816 | WRITE32(nfs4_lock_type(args->fl, 0)); |
804 | WRITE32(opargs->seqid->sequence->counter); | 817 | WRITE32(args->seqid->sequence->counter); |
805 | WRITEMEM(opargs->stateid->data, sizeof(opargs->stateid->data)); | 818 | WRITEMEM(args->stateid->data, sizeof(args->stateid->data)); |
806 | WRITE64(arg->offset); | 819 | WRITE64(args->fl->fl_start); |
807 | WRITE64(arg->length); | 820 | WRITE64(nfs4_lock_length(args->fl)); |
808 | 821 | ||
809 | return 0; | 822 | return 0; |
810 | } | 823 | } |
@@ -964,9 +977,9 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con | |||
964 | { | 977 | { |
965 | uint32_t *p; | 978 | uint32_t *p; |
966 | 979 | ||
967 | RESERVE_SPACE(8+sizeof(arg->stateid.data)); | 980 | RESERVE_SPACE(8+sizeof(arg->stateid->data)); |
968 | WRITE32(OP_OPEN_CONFIRM); | 981 | WRITE32(OP_OPEN_CONFIRM); |
969 | WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); | 982 | WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data)); |
970 | WRITE32(arg->seqid->sequence->counter); | 983 | WRITE32(arg->seqid->sequence->counter); |
971 | 984 | ||
972 | return 0; | 985 | return 0; |
@@ -1499,9 +1512,6 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena | |||
1499 | }; | 1512 | }; |
1500 | int status; | 1513 | int status; |
1501 | 1514 | ||
1502 | status = nfs_wait_on_sequence(args->seqid, req->rq_task); | ||
1503 | if (status != 0) | ||
1504 | goto out; | ||
1505 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1515 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1506 | encode_compound_hdr(&xdr, &hdr); | 1516 | encode_compound_hdr(&xdr, &hdr); |
1507 | status = encode_putfh(&xdr, args->fh); | 1517 | status = encode_putfh(&xdr, args->fh); |
@@ -1538,9 +1548,6 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct n | |||
1538 | }; | 1548 | }; |
1539 | int status; | 1549 | int status; |
1540 | 1550 | ||
1541 | status = nfs_wait_on_sequence(args->seqid, req->rq_task); | ||
1542 | if (status != 0) | ||
1543 | goto out; | ||
1544 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1551 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1545 | encode_compound_hdr(&xdr, &hdr); | 1552 | encode_compound_hdr(&xdr, &hdr); |
1546 | status = encode_putfh(&xdr, args->fh); | 1553 | status = encode_putfh(&xdr, args->fh); |
@@ -1558,19 +1565,19 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nf | |||
1558 | { | 1565 | { |
1559 | struct xdr_stream xdr; | 1566 | struct xdr_stream xdr; |
1560 | struct compound_hdr hdr = { | 1567 | struct compound_hdr hdr = { |
1561 | .nops = 2, | 1568 | .nops = 3, |
1562 | }; | 1569 | }; |
1563 | int status; | 1570 | int status; |
1564 | 1571 | ||
1565 | status = nfs_wait_on_sequence(args->seqid, req->rq_task); | ||
1566 | if (status != 0) | ||
1567 | goto out; | ||
1568 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1572 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1569 | encode_compound_hdr(&xdr, &hdr); | 1573 | encode_compound_hdr(&xdr, &hdr); |
1570 | status = encode_putfh(&xdr, args->fh); | 1574 | status = encode_putfh(&xdr, args->fh); |
1571 | if (status) | 1575 | if (status) |
1572 | goto out; | 1576 | goto out; |
1573 | status = encode_open(&xdr, args); | 1577 | status = encode_open(&xdr, args); |
1578 | if (status) | ||
1579 | goto out; | ||
1580 | status = encode_getfattr(&xdr, args->bitmask); | ||
1574 | out: | 1581 | out: |
1575 | return status; | 1582 | return status; |
1576 | } | 1583 | } |
@@ -1602,21 +1609,14 @@ out: | |||
1602 | /* | 1609 | /* |
1603 | * Encode a LOCK request | 1610 | * Encode a LOCK request |
1604 | */ | 1611 | */ |
1605 | static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) | 1612 | static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args) |
1606 | { | 1613 | { |
1607 | struct xdr_stream xdr; | 1614 | struct xdr_stream xdr; |
1608 | struct compound_hdr hdr = { | 1615 | struct compound_hdr hdr = { |
1609 | .nops = 2, | 1616 | .nops = 2, |
1610 | }; | 1617 | }; |
1611 | struct nfs_lock_opargs *opargs = args->u.lock; | ||
1612 | int status; | 1618 | int status; |
1613 | 1619 | ||
1614 | status = nfs_wait_on_sequence(opargs->lock_seqid, req->rq_task); | ||
1615 | if (status != 0) | ||
1616 | goto out; | ||
1617 | /* Do we need to do an open_to_lock_owner? */ | ||
1618 | if (opargs->lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED) | ||
1619 | opargs->new_lock_owner = 0; | ||
1620 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1620 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1621 | encode_compound_hdr(&xdr, &hdr); | 1621 | encode_compound_hdr(&xdr, &hdr); |
1622 | status = encode_putfh(&xdr, args->fh); | 1622 | status = encode_putfh(&xdr, args->fh); |
@@ -1630,7 +1630,7 @@ out: | |||
1630 | /* | 1630 | /* |
1631 | * Encode a LOCKT request | 1631 | * Encode a LOCKT request |
1632 | */ | 1632 | */ |
1633 | static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) | 1633 | static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args) |
1634 | { | 1634 | { |
1635 | struct xdr_stream xdr; | 1635 | struct xdr_stream xdr; |
1636 | struct compound_hdr hdr = { | 1636 | struct compound_hdr hdr = { |
@@ -1651,7 +1651,7 @@ out: | |||
1651 | /* | 1651 | /* |
1652 | * Encode a LOCKU request | 1652 | * Encode a LOCKU request |
1653 | */ | 1653 | */ |
1654 | static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) | 1654 | static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args) |
1655 | { | 1655 | { |
1656 | struct xdr_stream xdr; | 1656 | struct xdr_stream xdr; |
1657 | struct compound_hdr hdr = { | 1657 | struct compound_hdr hdr = { |
@@ -1985,14 +1985,20 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str | |||
1985 | { | 1985 | { |
1986 | struct xdr_stream xdr; | 1986 | struct xdr_stream xdr; |
1987 | struct compound_hdr hdr = { | 1987 | struct compound_hdr hdr = { |
1988 | .nops = 2, | 1988 | .nops = 3, |
1989 | }; | 1989 | }; |
1990 | int status; | 1990 | int status; |
1991 | 1991 | ||
1992 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1992 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1993 | encode_compound_hdr(&xdr, &hdr); | 1993 | encode_compound_hdr(&xdr, &hdr); |
1994 | if ((status = encode_putfh(&xdr, args->fhandle)) == 0) | 1994 | status = encode_putfh(&xdr, args->fhandle); |
1995 | status = encode_delegreturn(&xdr, args->stateid); | 1995 | if (status != 0) |
1996 | goto out; | ||
1997 | status = encode_delegreturn(&xdr, args->stateid); | ||
1998 | if (status != 0) | ||
1999 | goto out; | ||
2000 | status = encode_getfattr(&xdr, args->bitmask); | ||
2001 | out: | ||
1996 | return status; | 2002 | return status; |
1997 | } | 2003 | } |
1998 | 2004 | ||
@@ -2955,55 +2961,64 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | |||
2955 | /* | 2961 | /* |
2956 | * We create the owner, so we know a proper owner.id length is 4. | 2962 | * We create the owner, so we know a proper owner.id length is 4. |
2957 | */ | 2963 | */ |
2958 | static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied) | 2964 | static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) |
2959 | { | 2965 | { |
2966 | uint64_t offset, length, clientid; | ||
2960 | uint32_t *p; | 2967 | uint32_t *p; |
2961 | uint32_t namelen; | 2968 | uint32_t namelen, type; |
2962 | 2969 | ||
2963 | READ_BUF(32); | 2970 | READ_BUF(32); |
2964 | READ64(denied->offset); | 2971 | READ64(offset); |
2965 | READ64(denied->length); | 2972 | READ64(length); |
2966 | READ32(denied->type); | 2973 | READ32(type); |
2967 | READ64(denied->owner.clientid); | 2974 | if (fl != NULL) { |
2975 | fl->fl_start = (loff_t)offset; | ||
2976 | fl->fl_end = fl->fl_start + (loff_t)length - 1; | ||
2977 | if (length == ~(uint64_t)0) | ||
2978 | fl->fl_end = OFFSET_MAX; | ||
2979 | fl->fl_type = F_WRLCK; | ||
2980 | if (type & 1) | ||
2981 | fl->fl_type = F_RDLCK; | ||
2982 | fl->fl_pid = 0; | ||
2983 | } | ||
2984 | READ64(clientid); | ||
2968 | READ32(namelen); | 2985 | READ32(namelen); |
2969 | READ_BUF(namelen); | 2986 | READ_BUF(namelen); |
2970 | if (namelen == 4) | ||
2971 | READ32(denied->owner.id); | ||
2972 | return -NFS4ERR_DENIED; | 2987 | return -NFS4ERR_DENIED; |
2973 | } | 2988 | } |
2974 | 2989 | ||
2975 | static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res) | 2990 | static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) |
2976 | { | 2991 | { |
2977 | uint32_t *p; | 2992 | uint32_t *p; |
2978 | int status; | 2993 | int status; |
2979 | 2994 | ||
2980 | status = decode_op_hdr(xdr, OP_LOCK); | 2995 | status = decode_op_hdr(xdr, OP_LOCK); |
2981 | if (status == 0) { | 2996 | if (status == 0) { |
2982 | READ_BUF(sizeof(res->u.stateid.data)); | 2997 | READ_BUF(sizeof(res->stateid.data)); |
2983 | COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); | 2998 | COPYMEM(res->stateid.data, sizeof(res->stateid.data)); |
2984 | } else if (status == -NFS4ERR_DENIED) | 2999 | } else if (status == -NFS4ERR_DENIED) |
2985 | return decode_lock_denied(xdr, &res->u.denied); | 3000 | return decode_lock_denied(xdr, NULL); |
2986 | return status; | 3001 | return status; |
2987 | } | 3002 | } |
2988 | 3003 | ||
2989 | static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res) | 3004 | static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res) |
2990 | { | 3005 | { |
2991 | int status; | 3006 | int status; |
2992 | status = decode_op_hdr(xdr, OP_LOCKT); | 3007 | status = decode_op_hdr(xdr, OP_LOCKT); |
2993 | if (status == -NFS4ERR_DENIED) | 3008 | if (status == -NFS4ERR_DENIED) |
2994 | return decode_lock_denied(xdr, &res->u.denied); | 3009 | return decode_lock_denied(xdr, res->denied); |
2995 | return status; | 3010 | return status; |
2996 | } | 3011 | } |
2997 | 3012 | ||
2998 | static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) | 3013 | static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) |
2999 | { | 3014 | { |
3000 | uint32_t *p; | 3015 | uint32_t *p; |
3001 | int status; | 3016 | int status; |
3002 | 3017 | ||
3003 | status = decode_op_hdr(xdr, OP_LOCKU); | 3018 | status = decode_op_hdr(xdr, OP_LOCKU); |
3004 | if (status == 0) { | 3019 | if (status == 0) { |
3005 | READ_BUF(sizeof(res->u.stateid.data)); | 3020 | READ_BUF(sizeof(res->stateid.data)); |
3006 | COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); | 3021 | COPYMEM(res->stateid.data, sizeof(res->stateid.data)); |
3007 | } | 3022 | } |
3008 | return status; | 3023 | return status; |
3009 | } | 3024 | } |
@@ -3831,6 +3846,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct | |||
3831 | if (status) | 3846 | if (status) |
3832 | goto out; | 3847 | goto out; |
3833 | status = decode_open(&xdr, res); | 3848 | status = decode_open(&xdr, res); |
3849 | if (status) | ||
3850 | goto out; | ||
3851 | decode_getfattr(&xdr, res->f_attr, res->server); | ||
3834 | out: | 3852 | out: |
3835 | return status; | 3853 | return status; |
3836 | } | 3854 | } |
@@ -3864,7 +3882,7 @@ out: | |||
3864 | /* | 3882 | /* |
3865 | * Decode LOCK response | 3883 | * Decode LOCK response |
3866 | */ | 3884 | */ |
3867 | static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) | 3885 | static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res) |
3868 | { | 3886 | { |
3869 | struct xdr_stream xdr; | 3887 | struct xdr_stream xdr; |
3870 | struct compound_hdr hdr; | 3888 | struct compound_hdr hdr; |
@@ -3885,7 +3903,7 @@ out: | |||
3885 | /* | 3903 | /* |
3886 | * Decode LOCKT response | 3904 | * Decode LOCKT response |
3887 | */ | 3905 | */ |
3888 | static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) | 3906 | static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res) |
3889 | { | 3907 | { |
3890 | struct xdr_stream xdr; | 3908 | struct xdr_stream xdr; |
3891 | struct compound_hdr hdr; | 3909 | struct compound_hdr hdr; |
@@ -3906,7 +3924,7 @@ out: | |||
3906 | /* | 3924 | /* |
3907 | * Decode LOCKU response | 3925 | * Decode LOCKU response |
3908 | */ | 3926 | */ |
3909 | static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) | 3927 | static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res) |
3910 | { | 3928 | { |
3911 | struct xdr_stream xdr; | 3929 | struct xdr_stream xdr; |
3912 | struct compound_hdr hdr; | 3930 | struct compound_hdr hdr; |
@@ -4174,7 +4192,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s | |||
4174 | /* | 4192 | /* |
4175 | * DELEGRETURN request | 4193 | * DELEGRETURN request |
4176 | */ | 4194 | */ |
4177 | static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) | 4195 | static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res) |
4178 | { | 4196 | { |
4179 | struct xdr_stream xdr; | 4197 | struct xdr_stream xdr; |
4180 | struct compound_hdr hdr; | 4198 | struct compound_hdr hdr; |
@@ -4182,11 +4200,14 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *d | |||
4182 | 4200 | ||
4183 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4201 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
4184 | status = decode_compound_hdr(&xdr, &hdr); | 4202 | status = decode_compound_hdr(&xdr, &hdr); |
4185 | if (status == 0) { | 4203 | if (status != 0) |
4186 | status = decode_putfh(&xdr); | 4204 | goto out; |
4187 | if (status == 0) | 4205 | status = decode_putfh(&xdr); |
4188 | status = decode_delegreturn(&xdr); | 4206 | if (status != 0) |
4189 | } | 4207 | goto out; |
4208 | status = decode_delegreturn(&xdr); | ||
4209 | decode_getfattr(&xdr, res->fattr, res->server); | ||
4210 | out: | ||
4190 | return status; | 4211 | return status; |
4191 | } | 4212 | } |
4192 | 4213 | ||
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 1b272a135a31..985cc53b8dd5 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -296,8 +296,8 @@ static int __init root_nfs_name(char *name) | |||
296 | nfs_port = -1; | 296 | nfs_port = -1; |
297 | nfs_data.version = NFS_MOUNT_VERSION; | 297 | nfs_data.version = NFS_MOUNT_VERSION; |
298 | nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ | 298 | nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ |
299 | nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; | 299 | nfs_data.rsize = NFS_DEF_FILE_IO_SIZE; |
300 | nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; | 300 | nfs_data.wsize = NFS_DEF_FILE_IO_SIZE; |
301 | nfs_data.acregmin = 3; | 301 | nfs_data.acregmin = 3; |
302 | nfs_data.acregmax = 60; | 302 | nfs_data.acregmax = 60; |
303 | nfs_data.acdirmin = 30; | 303 | nfs_data.acdirmin = 30; |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index e1e3ca5d746b..f5150d71c03d 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -111,6 +111,9 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
111 | }; | 111 | }; |
112 | int status; | 112 | int status; |
113 | 113 | ||
114 | /* Mask out the non-modebit related stuff from attr->ia_mode */ | ||
115 | sattr->ia_mode &= S_IALLUGO; | ||
116 | |||
114 | dprintk("NFS call setattr\n"); | 117 | dprintk("NFS call setattr\n"); |
115 | nfs_fattr_init(fattr); | 118 | nfs_fattr_init(fattr); |
116 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); | 119 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); |
@@ -547,10 +550,9 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
547 | 550 | ||
548 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); | 551 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); |
549 | 552 | ||
550 | static void | 553 | static void nfs_read_done(struct rpc_task *task, void *calldata) |
551 | nfs_read_done(struct rpc_task *task) | ||
552 | { | 554 | { |
553 | struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; | 555 | struct nfs_read_data *data = calldata; |
554 | 556 | ||
555 | if (task->tk_status >= 0) { | 557 | if (task->tk_status >= 0) { |
556 | nfs_refresh_inode(data->inode, data->res.fattr); | 558 | nfs_refresh_inode(data->inode, data->res.fattr); |
@@ -560,9 +562,14 @@ nfs_read_done(struct rpc_task *task) | |||
560 | if (data->args.offset + data->args.count >= data->res.fattr->size) | 562 | if (data->args.offset + data->args.count >= data->res.fattr->size) |
561 | data->res.eof = 1; | 563 | data->res.eof = 1; |
562 | } | 564 | } |
563 | nfs_readpage_result(task); | 565 | nfs_readpage_result(task, calldata); |
564 | } | 566 | } |
565 | 567 | ||
568 | static const struct rpc_call_ops nfs_read_ops = { | ||
569 | .rpc_call_done = nfs_read_done, | ||
570 | .rpc_release = nfs_readdata_release, | ||
571 | }; | ||
572 | |||
566 | static void | 573 | static void |
567 | nfs_proc_read_setup(struct nfs_read_data *data) | 574 | nfs_proc_read_setup(struct nfs_read_data *data) |
568 | { | 575 | { |
@@ -580,20 +587,24 @@ nfs_proc_read_setup(struct nfs_read_data *data) | |||
580 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 587 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
581 | 588 | ||
582 | /* Finalize the task. */ | 589 | /* Finalize the task. */ |
583 | rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags); | 590 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_read_ops, data); |
584 | rpc_call_setup(task, &msg, 0); | 591 | rpc_call_setup(task, &msg, 0); |
585 | } | 592 | } |
586 | 593 | ||
587 | static void | 594 | static void nfs_write_done(struct rpc_task *task, void *calldata) |
588 | nfs_write_done(struct rpc_task *task) | ||
589 | { | 595 | { |
590 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 596 | struct nfs_write_data *data = calldata; |
591 | 597 | ||
592 | if (task->tk_status >= 0) | 598 | if (task->tk_status >= 0) |
593 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 599 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
594 | nfs_writeback_done(task); | 600 | nfs_writeback_done(task, calldata); |
595 | } | 601 | } |
596 | 602 | ||
603 | static const struct rpc_call_ops nfs_write_ops = { | ||
604 | .rpc_call_done = nfs_write_done, | ||
605 | .rpc_release = nfs_writedata_release, | ||
606 | }; | ||
607 | |||
597 | static void | 608 | static void |
598 | nfs_proc_write_setup(struct nfs_write_data *data, int how) | 609 | nfs_proc_write_setup(struct nfs_write_data *data, int how) |
599 | { | 610 | { |
@@ -614,7 +625,7 @@ nfs_proc_write_setup(struct nfs_write_data *data, int how) | |||
614 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 625 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
615 | 626 | ||
616 | /* Finalize the task. */ | 627 | /* Finalize the task. */ |
617 | rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags); | 628 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_write_ops, data); |
618 | rpc_call_setup(task, &msg, 0); | 629 | rpc_call_setup(task, &msg, 0); |
619 | } | 630 | } |
620 | 631 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 5f20eafba8ec..05eb43fadf8e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -42,9 +42,8 @@ mempool_t *nfs_rdata_mempool; | |||
42 | 42 | ||
43 | #define MIN_POOL_READ (32) | 43 | #define MIN_POOL_READ (32) |
44 | 44 | ||
45 | void nfs_readdata_release(struct rpc_task *task) | 45 | void nfs_readdata_release(void *data) |
46 | { | 46 | { |
47 | struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; | ||
48 | nfs_readdata_free(data); | 47 | nfs_readdata_free(data); |
49 | } | 48 | } |
50 | 49 | ||
@@ -84,7 +83,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
84 | int result; | 83 | int result; |
85 | struct nfs_read_data *rdata; | 84 | struct nfs_read_data *rdata; |
86 | 85 | ||
87 | rdata = nfs_readdata_alloc(); | 86 | rdata = nfs_readdata_alloc(1); |
88 | if (!rdata) | 87 | if (!rdata) |
89 | return -ENOMEM; | 88 | return -ENOMEM; |
90 | 89 | ||
@@ -220,9 +219,6 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
220 | NFS_PROTO(inode)->read_setup(data); | 219 | NFS_PROTO(inode)->read_setup(data); |
221 | 220 | ||
222 | data->task.tk_cookie = (unsigned long)inode; | 221 | data->task.tk_cookie = (unsigned long)inode; |
223 | data->task.tk_calldata = data; | ||
224 | /* Release requests */ | ||
225 | data->task.tk_release = nfs_readdata_release; | ||
226 | 222 | ||
227 | dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 223 | dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
228 | data->task.tk_pid, | 224 | data->task.tk_pid, |
@@ -287,7 +283,7 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
287 | 283 | ||
288 | nbytes = req->wb_bytes; | 284 | nbytes = req->wb_bytes; |
289 | for(;;) { | 285 | for(;;) { |
290 | data = nfs_readdata_alloc(); | 286 | data = nfs_readdata_alloc(1); |
291 | if (!data) | 287 | if (!data) |
292 | goto out_bad; | 288 | goto out_bad; |
293 | INIT_LIST_HEAD(&data->pages); | 289 | INIT_LIST_HEAD(&data->pages); |
@@ -343,7 +339,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode) | |||
343 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | 339 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
344 | return nfs_pagein_multi(head, inode); | 340 | return nfs_pagein_multi(head, inode); |
345 | 341 | ||
346 | data = nfs_readdata_alloc(); | 342 | data = nfs_readdata_alloc(NFS_SERVER(inode)->rpages); |
347 | if (!data) | 343 | if (!data) |
348 | goto out_bad; | 344 | goto out_bad; |
349 | 345 | ||
@@ -452,9 +448,9 @@ static void nfs_readpage_result_full(struct nfs_read_data *data, int status) | |||
452 | * This is the callback from RPC telling us whether a reply was | 448 | * This is the callback from RPC telling us whether a reply was |
453 | * received or some error occurred (timeout or socket shutdown). | 449 | * received or some error occurred (timeout or socket shutdown). |
454 | */ | 450 | */ |
455 | void nfs_readpage_result(struct rpc_task *task) | 451 | void nfs_readpage_result(struct rpc_task *task, void *calldata) |
456 | { | 452 | { |
457 | struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; | 453 | struct nfs_read_data *data = calldata; |
458 | struct nfs_readargs *argp = &data->args; | 454 | struct nfs_readargs *argp = &data->args; |
459 | struct nfs_readres *resp = &data->res; | 455 | struct nfs_readres *resp = &data->res; |
460 | int status = task->tk_status; | 456 | int status = task->tk_status; |
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c new file mode 100644 index 000000000000..4c486eb867ca --- /dev/null +++ b/fs/nfs/sysctl.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/sysctl.c | ||
3 | * | ||
4 | * Sysctl interface to NFS parameters | ||
5 | */ | ||
6 | #include <linux/config.h> | ||
7 | #include <linux/types.h> | ||
8 | #include <linux/linkage.h> | ||
9 | #include <linux/ctype.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/sysctl.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/nfs4.h> | ||
14 | #include <linux/nfs_idmap.h> | ||
15 | |||
16 | #include "callback.h" | ||
17 | |||
18 | static const int nfs_set_port_min = 0; | ||
19 | static const int nfs_set_port_max = 65535; | ||
20 | static struct ctl_table_header *nfs_callback_sysctl_table; | ||
21 | /* | ||
22 | * Something that isn't CTL_ANY, CTL_NONE or a value that may clash. | ||
23 | * Use the same values as fs/lockd/svc.c | ||
24 | */ | ||
25 | #define CTL_UNNUMBERED -2 | ||
26 | |||
27 | static ctl_table nfs_cb_sysctls[] = { | ||
28 | #ifdef CONFIG_NFS_V4 | ||
29 | { | ||
30 | .ctl_name = CTL_UNNUMBERED, | ||
31 | .procname = "nfs_callback_tcpport", | ||
32 | .data = &nfs_callback_set_tcpport, | ||
33 | .maxlen = sizeof(int), | ||
34 | .mode = 0644, | ||
35 | .proc_handler = &proc_dointvec_minmax, | ||
36 | .extra1 = (int *)&nfs_set_port_min, | ||
37 | .extra2 = (int *)&nfs_set_port_max, | ||
38 | }, | ||
39 | { | ||
40 | .ctl_name = CTL_UNNUMBERED, | ||
41 | .procname = "idmap_cache_timeout", | ||
42 | .data = &nfs_idmap_cache_timeout, | ||
43 | .maxlen = sizeof(int), | ||
44 | .mode = 0644, | ||
45 | .proc_handler = &proc_dointvec_jiffies, | ||
46 | .strategy = &sysctl_jiffies, | ||
47 | }, | ||
48 | #endif | ||
49 | { .ctl_name = 0 } | ||
50 | }; | ||
51 | |||
52 | static ctl_table nfs_cb_sysctl_dir[] = { | ||
53 | { | ||
54 | .ctl_name = CTL_UNNUMBERED, | ||
55 | .procname = "nfs", | ||
56 | .mode = 0555, | ||
57 | .child = nfs_cb_sysctls, | ||
58 | }, | ||
59 | { .ctl_name = 0 } | ||
60 | }; | ||
61 | |||
62 | static ctl_table nfs_cb_sysctl_root[] = { | ||
63 | { | ||
64 | .ctl_name = CTL_FS, | ||
65 | .procname = "fs", | ||
66 | .mode = 0555, | ||
67 | .child = nfs_cb_sysctl_dir, | ||
68 | }, | ||
69 | { .ctl_name = 0 } | ||
70 | }; | ||
71 | |||
72 | int nfs_register_sysctl(void) | ||
73 | { | ||
74 | nfs_callback_sysctl_table = register_sysctl_table(nfs_cb_sysctl_root, 0); | ||
75 | if (nfs_callback_sysctl_table == NULL) | ||
76 | return -ENOMEM; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | void nfs_unregister_sysctl(void) | ||
81 | { | ||
82 | unregister_sysctl_table(nfs_callback_sysctl_table); | ||
83 | nfs_callback_sysctl_table = NULL; | ||
84 | } | ||
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index d639d172d568..a65c7b53d558 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -87,10 +87,9 @@ nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) | |||
87 | * We delay initializing RPC info until after the call to dentry_iput() | 87 | * We delay initializing RPC info until after the call to dentry_iput() |
88 | * in order to minimize races against rename(). | 88 | * in order to minimize races against rename(). |
89 | */ | 89 | */ |
90 | static void | 90 | static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) |
91 | nfs_async_unlink_init(struct rpc_task *task) | ||
92 | { | 91 | { |
93 | struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; | 92 | struct nfs_unlinkdata *data = calldata; |
94 | struct dentry *dir = data->dir; | 93 | struct dentry *dir = data->dir; |
95 | struct rpc_message msg = { | 94 | struct rpc_message msg = { |
96 | .rpc_cred = data->cred, | 95 | .rpc_cred = data->cred, |
@@ -116,10 +115,9 @@ nfs_async_unlink_init(struct rpc_task *task) | |||
116 | * | 115 | * |
117 | * Do the directory attribute update. | 116 | * Do the directory attribute update. |
118 | */ | 117 | */ |
119 | static void | 118 | static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) |
120 | nfs_async_unlink_done(struct rpc_task *task) | ||
121 | { | 119 | { |
122 | struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; | 120 | struct nfs_unlinkdata *data = calldata; |
123 | struct dentry *dir = data->dir; | 121 | struct dentry *dir = data->dir; |
124 | struct inode *dir_i; | 122 | struct inode *dir_i; |
125 | 123 | ||
@@ -141,13 +139,18 @@ nfs_async_unlink_done(struct rpc_task *task) | |||
141 | * We need to call nfs_put_unlinkdata as a 'tk_release' task since the | 139 | * We need to call nfs_put_unlinkdata as a 'tk_release' task since the |
142 | * rpc_task would be freed too. | 140 | * rpc_task would be freed too. |
143 | */ | 141 | */ |
144 | static void | 142 | static void nfs_async_unlink_release(void *calldata) |
145 | nfs_async_unlink_release(struct rpc_task *task) | ||
146 | { | 143 | { |
147 | struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; | 144 | struct nfs_unlinkdata *data = calldata; |
148 | nfs_put_unlinkdata(data); | 145 | nfs_put_unlinkdata(data); |
149 | } | 146 | } |
150 | 147 | ||
148 | static const struct rpc_call_ops nfs_unlink_ops = { | ||
149 | .rpc_call_prepare = nfs_async_unlink_init, | ||
150 | .rpc_call_done = nfs_async_unlink_done, | ||
151 | .rpc_release = nfs_async_unlink_release, | ||
152 | }; | ||
153 | |||
151 | /** | 154 | /** |
152 | * nfs_async_unlink - asynchronous unlinking of a file | 155 | * nfs_async_unlink - asynchronous unlinking of a file |
153 | * @dentry: dentry to unlink | 156 | * @dentry: dentry to unlink |
@@ -157,7 +160,6 @@ nfs_async_unlink(struct dentry *dentry) | |||
157 | { | 160 | { |
158 | struct dentry *dir = dentry->d_parent; | 161 | struct dentry *dir = dentry->d_parent; |
159 | struct nfs_unlinkdata *data; | 162 | struct nfs_unlinkdata *data; |
160 | struct rpc_task *task; | ||
161 | struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); | 163 | struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); |
162 | int status = -ENOMEM; | 164 | int status = -ENOMEM; |
163 | 165 | ||
@@ -178,17 +180,13 @@ nfs_async_unlink(struct dentry *dentry) | |||
178 | nfs_deletes = data; | 180 | nfs_deletes = data; |
179 | data->count = 1; | 181 | data->count = 1; |
180 | 182 | ||
181 | task = &data->task; | 183 | rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data); |
182 | rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC); | ||
183 | task->tk_calldata = data; | ||
184 | task->tk_action = nfs_async_unlink_init; | ||
185 | task->tk_release = nfs_async_unlink_release; | ||
186 | 184 | ||
187 | spin_lock(&dentry->d_lock); | 185 | spin_lock(&dentry->d_lock); |
188 | dentry->d_flags |= DCACHE_NFSFS_RENAMED; | 186 | dentry->d_flags |= DCACHE_NFSFS_RENAMED; |
189 | spin_unlock(&dentry->d_lock); | 187 | spin_unlock(&dentry->d_lock); |
190 | 188 | ||
191 | rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL); | 189 | rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL); |
192 | status = 0; | 190 | status = 0; |
193 | out: | 191 | out: |
194 | return status; | 192 | return status; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 3107908e5f3f..9449b6835509 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -89,24 +89,38 @@ static mempool_t *nfs_commit_mempool; | |||
89 | 89 | ||
90 | static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); | 90 | static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); |
91 | 91 | ||
92 | static inline struct nfs_write_data *nfs_commit_alloc(void) | 92 | static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount) |
93 | { | 93 | { |
94 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); | 94 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); |
95 | |||
95 | if (p) { | 96 | if (p) { |
96 | memset(p, 0, sizeof(*p)); | 97 | memset(p, 0, sizeof(*p)); |
97 | INIT_LIST_HEAD(&p->pages); | 98 | INIT_LIST_HEAD(&p->pages); |
99 | if (pagecount < NFS_PAGEVEC_SIZE) | ||
100 | p->pagevec = &p->page_array[0]; | ||
101 | else { | ||
102 | size_t size = ++pagecount * sizeof(struct page *); | ||
103 | p->pagevec = kmalloc(size, GFP_NOFS); | ||
104 | if (p->pagevec) { | ||
105 | memset(p->pagevec, 0, size); | ||
106 | } else { | ||
107 | mempool_free(p, nfs_commit_mempool); | ||
108 | p = NULL; | ||
109 | } | ||
110 | } | ||
98 | } | 111 | } |
99 | return p; | 112 | return p; |
100 | } | 113 | } |
101 | 114 | ||
102 | static inline void nfs_commit_free(struct nfs_write_data *p) | 115 | static inline void nfs_commit_free(struct nfs_write_data *p) |
103 | { | 116 | { |
117 | if (p && (p->pagevec != &p->page_array[0])) | ||
118 | kfree(p->pagevec); | ||
104 | mempool_free(p, nfs_commit_mempool); | 119 | mempool_free(p, nfs_commit_mempool); |
105 | } | 120 | } |
106 | 121 | ||
107 | static void nfs_writedata_release(struct rpc_task *task) | 122 | void nfs_writedata_release(void *wdata) |
108 | { | 123 | { |
109 | struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; | ||
110 | nfs_writedata_free(wdata); | 124 | nfs_writedata_free(wdata); |
111 | } | 125 | } |
112 | 126 | ||
@@ -168,7 +182,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
168 | int result, written = 0; | 182 | int result, written = 0; |
169 | struct nfs_write_data *wdata; | 183 | struct nfs_write_data *wdata; |
170 | 184 | ||
171 | wdata = nfs_writedata_alloc(); | 185 | wdata = nfs_writedata_alloc(1); |
172 | if (!wdata) | 186 | if (!wdata) |
173 | return -ENOMEM; | 187 | return -ENOMEM; |
174 | 188 | ||
@@ -232,19 +246,16 @@ static int nfs_writepage_async(struct nfs_open_context *ctx, | |||
232 | unsigned int offset, unsigned int count) | 246 | unsigned int offset, unsigned int count) |
233 | { | 247 | { |
234 | struct nfs_page *req; | 248 | struct nfs_page *req; |
235 | int status; | ||
236 | 249 | ||
237 | req = nfs_update_request(ctx, inode, page, offset, count); | 250 | req = nfs_update_request(ctx, inode, page, offset, count); |
238 | status = (IS_ERR(req)) ? PTR_ERR(req) : 0; | 251 | if (IS_ERR(req)) |
239 | if (status < 0) | 252 | return PTR_ERR(req); |
240 | goto out; | ||
241 | /* Update file length */ | 253 | /* Update file length */ |
242 | nfs_grow_file(page, offset, count); | 254 | nfs_grow_file(page, offset, count); |
243 | /* Set the PG_uptodate flag? */ | 255 | /* Set the PG_uptodate flag? */ |
244 | nfs_mark_uptodate(page, offset, count); | 256 | nfs_mark_uptodate(page, offset, count); |
245 | nfs_unlock_request(req); | 257 | nfs_unlock_request(req); |
246 | out: | 258 | return 0; |
247 | return status; | ||
248 | } | 259 | } |
249 | 260 | ||
250 | static int wb_priority(struct writeback_control *wbc) | 261 | static int wb_priority(struct writeback_control *wbc) |
@@ -304,11 +315,8 @@ do_it: | |||
304 | lock_kernel(); | 315 | lock_kernel(); |
305 | if (!IS_SYNC(inode) && inode_referenced) { | 316 | if (!IS_SYNC(inode) && inode_referenced) { |
306 | err = nfs_writepage_async(ctx, inode, page, 0, offset); | 317 | err = nfs_writepage_async(ctx, inode, page, 0, offset); |
307 | if (err >= 0) { | 318 | if (!wbc->for_writepages) |
308 | err = 0; | 319 | nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); |
309 | if (wbc->for_reclaim) | ||
310 | nfs_flush_inode(inode, 0, 0, FLUSH_STABLE); | ||
311 | } | ||
312 | } else { | 320 | } else { |
313 | err = nfs_writepage_sync(ctx, inode, page, 0, | 321 | err = nfs_writepage_sync(ctx, inode, page, 0, |
314 | offset, priority); | 322 | offset, priority); |
@@ -877,9 +885,6 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
877 | 885 | ||
878 | data->task.tk_priority = flush_task_priority(how); | 886 | data->task.tk_priority = flush_task_priority(how); |
879 | data->task.tk_cookie = (unsigned long)inode; | 887 | data->task.tk_cookie = (unsigned long)inode; |
880 | data->task.tk_calldata = data; | ||
881 | /* Release requests */ | ||
882 | data->task.tk_release = nfs_writedata_release; | ||
883 | 888 | ||
884 | dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 889 | dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
885 | data->task.tk_pid, | 890 | data->task.tk_pid, |
@@ -919,7 +924,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) | |||
919 | 924 | ||
920 | nbytes = req->wb_bytes; | 925 | nbytes = req->wb_bytes; |
921 | for (;;) { | 926 | for (;;) { |
922 | data = nfs_writedata_alloc(); | 927 | data = nfs_writedata_alloc(1); |
923 | if (!data) | 928 | if (!data) |
924 | goto out_bad; | 929 | goto out_bad; |
925 | list_add(&data->pages, &list); | 930 | list_add(&data->pages, &list); |
@@ -983,7 +988,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
983 | if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) | 988 | if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) |
984 | return nfs_flush_multi(head, inode, how); | 989 | return nfs_flush_multi(head, inode, how); |
985 | 990 | ||
986 | data = nfs_writedata_alloc(); | 991 | data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); |
987 | if (!data) | 992 | if (!data) |
988 | goto out_bad; | 993 | goto out_bad; |
989 | 994 | ||
@@ -1137,9 +1142,9 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1137 | /* | 1142 | /* |
1138 | * This function is called when the WRITE call is complete. | 1143 | * This function is called when the WRITE call is complete. |
1139 | */ | 1144 | */ |
1140 | void nfs_writeback_done(struct rpc_task *task) | 1145 | void nfs_writeback_done(struct rpc_task *task, void *calldata) |
1141 | { | 1146 | { |
1142 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 1147 | struct nfs_write_data *data = calldata; |
1143 | struct nfs_writeargs *argp = &data->args; | 1148 | struct nfs_writeargs *argp = &data->args; |
1144 | struct nfs_writeres *resp = &data->res; | 1149 | struct nfs_writeres *resp = &data->res; |
1145 | 1150 | ||
@@ -1206,9 +1211,8 @@ void nfs_writeback_done(struct rpc_task *task) | |||
1206 | 1211 | ||
1207 | 1212 | ||
1208 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1213 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1209 | static void nfs_commit_release(struct rpc_task *task) | 1214 | void nfs_commit_release(void *wdata) |
1210 | { | 1215 | { |
1211 | struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; | ||
1212 | nfs_commit_free(wdata); | 1216 | nfs_commit_free(wdata); |
1213 | } | 1217 | } |
1214 | 1218 | ||
@@ -1244,9 +1248,6 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1244 | 1248 | ||
1245 | data->task.tk_priority = flush_task_priority(how); | 1249 | data->task.tk_priority = flush_task_priority(how); |
1246 | data->task.tk_cookie = (unsigned long)inode; | 1250 | data->task.tk_cookie = (unsigned long)inode; |
1247 | data->task.tk_calldata = data; | ||
1248 | /* Release requests */ | ||
1249 | data->task.tk_release = nfs_commit_release; | ||
1250 | 1251 | ||
1251 | dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); | 1252 | dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); |
1252 | } | 1253 | } |
@@ -1255,12 +1256,12 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1255 | * Commit dirty pages | 1256 | * Commit dirty pages |
1256 | */ | 1257 | */ |
1257 | static int | 1258 | static int |
1258 | nfs_commit_list(struct list_head *head, int how) | 1259 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) |
1259 | { | 1260 | { |
1260 | struct nfs_write_data *data; | 1261 | struct nfs_write_data *data; |
1261 | struct nfs_page *req; | 1262 | struct nfs_page *req; |
1262 | 1263 | ||
1263 | data = nfs_commit_alloc(); | 1264 | data = nfs_commit_alloc(NFS_SERVER(inode)->wpages); |
1264 | 1265 | ||
1265 | if (!data) | 1266 | if (!data) |
1266 | goto out_bad; | 1267 | goto out_bad; |
@@ -1283,10 +1284,9 @@ nfs_commit_list(struct list_head *head, int how) | |||
1283 | /* | 1284 | /* |
1284 | * COMMIT call returned | 1285 | * COMMIT call returned |
1285 | */ | 1286 | */ |
1286 | void | 1287 | void nfs_commit_done(struct rpc_task *task, void *calldata) |
1287 | nfs_commit_done(struct rpc_task *task) | ||
1288 | { | 1288 | { |
1289 | struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; | 1289 | struct nfs_write_data *data = calldata; |
1290 | struct nfs_page *req; | 1290 | struct nfs_page *req; |
1291 | int res = 0; | 1291 | int res = 0; |
1292 | 1292 | ||
@@ -1366,7 +1366,7 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1366 | res = nfs_scan_commit(inode, &head, 0, 0); | 1366 | res = nfs_scan_commit(inode, &head, 0, 0); |
1367 | spin_unlock(&nfsi->req_lock); | 1367 | spin_unlock(&nfsi->req_lock); |
1368 | if (res) { | 1368 | if (res) { |
1369 | error = nfs_commit_list(&head, how); | 1369 | error = nfs_commit_list(inode, &head, how); |
1370 | if (error < 0) | 1370 | if (error < 0) |
1371 | return error; | 1371 | return error; |
1372 | } | 1372 | } |
@@ -1377,22 +1377,23 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1377 | int nfs_sync_inode(struct inode *inode, unsigned long idx_start, | 1377 | int nfs_sync_inode(struct inode *inode, unsigned long idx_start, |
1378 | unsigned int npages, int how) | 1378 | unsigned int npages, int how) |
1379 | { | 1379 | { |
1380 | int error, | 1380 | int nocommit = how & FLUSH_NOCOMMIT; |
1381 | wait; | 1381 | int wait = how & FLUSH_WAIT; |
1382 | int error; | ||
1382 | 1383 | ||
1383 | wait = how & FLUSH_WAIT; | 1384 | how &= ~(FLUSH_WAIT|FLUSH_NOCOMMIT); |
1384 | how &= ~FLUSH_WAIT; | ||
1385 | 1385 | ||
1386 | do { | 1386 | do { |
1387 | error = 0; | 1387 | if (wait) { |
1388 | if (wait) | ||
1389 | error = nfs_wait_on_requests(inode, idx_start, npages); | 1388 | error = nfs_wait_on_requests(inode, idx_start, npages); |
1390 | if (error == 0) | 1389 | if (error != 0) |
1391 | error = nfs_flush_inode(inode, idx_start, npages, how); | 1390 | continue; |
1392 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1391 | } |
1393 | if (error == 0) | 1392 | error = nfs_flush_inode(inode, idx_start, npages, how); |
1393 | if (error != 0) | ||
1394 | continue; | ||
1395 | if (!nocommit) | ||
1394 | error = nfs_commit_inode(inode, how); | 1396 | error = nfs_commit_inode(inode, how); |
1395 | #endif | ||
1396 | } while (error > 0); | 1397 | } while (error > 0); |
1397 | return error; | 1398 | return error; |
1398 | } | 1399 | } |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 583c0710e45e..d828662d737d 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -53,7 +53,7 @@ | |||
53 | #define NFSPROC4_CB_COMPOUND 1 | 53 | #define NFSPROC4_CB_COMPOUND 1 |
54 | 54 | ||
55 | /* declarations */ | 55 | /* declarations */ |
56 | static void nfs4_cb_null(struct rpc_task *task); | 56 | static const struct rpc_call_ops nfs4_cb_null_ops; |
57 | 57 | ||
58 | /* Index of predefined Linux callback client operations */ | 58 | /* Index of predefined Linux callback client operations */ |
59 | 59 | ||
@@ -431,7 +431,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
431 | } | 431 | } |
432 | clnt->cl_intr = 0; | 432 | clnt->cl_intr = 0; |
433 | clnt->cl_softrtry = 1; | 433 | clnt->cl_softrtry = 1; |
434 | clnt->cl_chatty = 1; | ||
435 | 434 | ||
436 | /* Kick rpciod, put the call on the wire. */ | 435 | /* Kick rpciod, put the call on the wire. */ |
437 | 436 | ||
@@ -447,7 +446,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
447 | msg.rpc_cred = nfsd4_lookupcred(clp,0); | 446 | msg.rpc_cred = nfsd4_lookupcred(clp,0); |
448 | if (IS_ERR(msg.rpc_cred)) | 447 | if (IS_ERR(msg.rpc_cred)) |
449 | goto out_rpciod; | 448 | goto out_rpciod; |
450 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL); | 449 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); |
451 | put_rpccred(msg.rpc_cred); | 450 | put_rpccred(msg.rpc_cred); |
452 | 451 | ||
453 | if (status != 0) { | 452 | if (status != 0) { |
@@ -469,7 +468,7 @@ out_err: | |||
469 | } | 468 | } |
470 | 469 | ||
471 | static void | 470 | static void |
472 | nfs4_cb_null(struct rpc_task *task) | 471 | nfs4_cb_null(struct rpc_task *task, void *dummy) |
473 | { | 472 | { |
474 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; | 473 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; |
475 | struct nfs4_callback *cb = &clp->cl_callback; | 474 | struct nfs4_callback *cb = &clp->cl_callback; |
@@ -488,6 +487,10 @@ out: | |||
488 | put_nfs4_client(clp); | 487 | put_nfs4_client(clp); |
489 | } | 488 | } |
490 | 489 | ||
490 | static const struct rpc_call_ops nfs4_cb_null_ops = { | ||
491 | .rpc_call_done = nfs4_cb_null, | ||
492 | }; | ||
493 | |||
491 | /* | 494 | /* |
492 | * called with dp->dl_count inc'ed. | 495 | * called with dp->dl_count inc'ed. |
493 | * nfs4_lock_state() may or may not have been called. | 496 | * nfs4_lock_state() may or may not have been called. |