diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
commit | 563307b2fa15d687abc54bd980b9847ebf0e3231 (patch) | |
tree | 7f16be30217a2e66360ede97aa27d07a4ebd7e55 | |
parent | 10c993a6b5418cb1026775765ba4c70ffb70853d (diff) | |
parent | 233607dbbc823caf685e778cabc49fb7f679900b (diff) |
Merge git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (80 commits)
SUNRPC: Invalidate the RPCSEC_GSS session if the server dropped the request
make nfs_automount_list static
NFS: remove duplicate flags assignment from nfs_validate_mount_data
NFS - fix potential NULL pointer dereference v2
SUNRPC: Don't change the RPCSEC_GSS context on a credential that is in use
SUNRPC: Fix a race in gss_refresh_upcall()
SUNRPC: Don't disconnect more than once if retransmitting NFSv4 requests
SUNRPC: Remove the unused export of xprt_force_disconnect
SUNRPC: remove XS_SENDMSG_RETRY
SUNRPC: Protect creds against early garbage collection
NFSv4: Attempt to use machine credentials in SETCLIENTID calls
NFSv4: Reintroduce machine creds
NFSv4: Don't use cred->cr_ops->cr_name in nfs4_proc_setclientid()
nfs: fix printout of multiword bitfields
nfs: return negative error value from nfs{,4}_stat_to_errno
NLM/lockd: Ensure client locking calls use correct credentials
NFS: Remove the buggy lock-if-signalled case from do_setlk()
NLM/lockd: Fix a race when cancelling a blocking lock
NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call
NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel
...
43 files changed, 1583 insertions, 896 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 56c83f40cdbe..2e43d46f65d6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1664,30 +1664,6 @@ config NFS_V4 | |||
1664 | 1664 | ||
1665 | If unsure, say N. | 1665 | If unsure, say N. |
1666 | 1666 | ||
1667 | config NFS_DIRECTIO | ||
1668 | bool "Allow direct I/O on NFS files" | ||
1669 | depends on NFS_FS | ||
1670 | help | ||
1671 | This option enables applications to perform uncached I/O on files | ||
1672 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT | ||
1673 | is set for a file, its data is not cached in the system's page | ||
1674 | cache. Data is moved to and from user-level application buffers | ||
1675 | directly. Unlike local disk-based file systems, NFS O_DIRECT has | ||
1676 | no alignment restrictions. | ||
1677 | |||
1678 | Unless your program is designed to use O_DIRECT properly, you are | ||
1679 | much better off allowing the NFS client to manage data caching for | ||
1680 | you. Misusing O_DIRECT can cause poor server performance or network | ||
1681 | storms. This kernel build option defaults OFF to avoid exposing | ||
1682 | system administrators unwittingly to a potentially hazardous | ||
1683 | feature. | ||
1684 | |||
1685 | For more details on NFS O_DIRECT, see fs/nfs/direct.c. | ||
1686 | |||
1687 | If unsure, say N. This reduces the size of the NFS client, and | ||
1688 | causes open() to return EINVAL if a file residing in NFS is | ||
1689 | opened with the O_DIRECT flag. | ||
1690 | |||
1691 | config NFSD | 1667 | config NFSD |
1692 | tristate "NFS server support" | 1668 | tristate "NFS server support" |
1693 | depends on INET | 1669 | depends on INET |
@@ -1813,15 +1789,33 @@ config SUNRPC_XPRT_RDMA | |||
1813 | tristate | 1789 | tristate |
1814 | depends on SUNRPC && INFINIBAND && EXPERIMENTAL | 1790 | depends on SUNRPC && INFINIBAND && EXPERIMENTAL |
1815 | default SUNRPC && INFINIBAND | 1791 | default SUNRPC && INFINIBAND |
1792 | help | ||
1793 | This option enables an RPC client transport capability that | ||
1794 | allows the NFS client to mount servers via an RDMA-enabled | ||
1795 | transport. | ||
1796 | |||
1797 | To compile RPC client RDMA transport support as a module, | ||
1798 | choose M here: the module will be called xprtrdma. | ||
1799 | |||
1800 | If unsure, say N. | ||
1816 | 1801 | ||
1817 | config SUNRPC_BIND34 | 1802 | config SUNRPC_BIND34 |
1818 | bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" | 1803 | bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" |
1819 | depends on SUNRPC && EXPERIMENTAL | 1804 | depends on SUNRPC && EXPERIMENTAL |
1805 | default n | ||
1820 | help | 1806 | help |
1821 | Provides kernel support for querying rpcbind servers via versions 3 | 1807 | RPC requests over IPv6 networks require support for larger |
1822 | and 4 of the rpcbind protocol. The kernel automatically falls back | 1808 | addresses when performing an RPC bind. Sun added support for |
1823 | to version 2 if a remote rpcbind service does not support versions | 1809 | IPv6 addressing by creating two new versions of the rpcbind |
1824 | 3 or 4. | 1810 | protocol (RFC 1833). |
1811 | |||
1812 | This option enables support in the kernel RPC client for | ||
1813 | querying rpcbind servers via versions 3 and 4 of the rpcbind | ||
1814 | protocol. The kernel automatically falls back to version 2 | ||
1815 | if a remote rpcbind service does not support versions 3 or 4. | ||
1816 | By themselves, these new versions do not provide support for | ||
1817 | RPC over IPv6, but the new protocol versions are necessary to | ||
1818 | support it. | ||
1825 | 1819 | ||
1826 | If unsure, say N to get traditional behavior (version 2 rpcbind | 1820 | If unsure, say N to get traditional behavior (version 2 rpcbind |
1827 | requests only). | 1821 | requests only). |
@@ -1835,12 +1829,13 @@ config RPCSEC_GSS_KRB5 | |||
1835 | select CRYPTO_DES | 1829 | select CRYPTO_DES |
1836 | select CRYPTO_CBC | 1830 | select CRYPTO_CBC |
1837 | help | 1831 | help |
1838 | Provides for secure RPC calls by means of a gss-api | 1832 | Choose Y here to enable Secure RPC using the Kerberos version 5 |
1839 | mechanism based on Kerberos V5. This is required for | 1833 | GSS-API mechanism (RFC 1964). |
1840 | NFSv4. | ||
1841 | 1834 | ||
1842 | Note: Requires an auxiliary userspace daemon which may be found on | 1835 | Secure RPC calls with Kerberos require an auxiliary user-space |
1843 | http://www.citi.umich.edu/projects/nfsv4/ | 1836 | daemon which may be found in the Linux nfs-utils package |
1837 | available from http://linux-nfs.org/. In addition, user-space | ||
1838 | Kerberos support should be installed. | ||
1844 | 1839 | ||
1845 | If unsure, say N. | 1840 | If unsure, say N. |
1846 | 1841 | ||
@@ -1854,11 +1849,12 @@ config RPCSEC_GSS_SPKM3 | |||
1854 | select CRYPTO_CAST5 | 1849 | select CRYPTO_CAST5 |
1855 | select CRYPTO_CBC | 1850 | select CRYPTO_CBC |
1856 | help | 1851 | help |
1857 | Provides for secure RPC calls by means of a gss-api | 1852 | Choose Y here to enable Secure RPC using the SPKM3 public key |
1858 | mechanism based on the SPKM3 public-key mechanism. | 1853 | GSS-API mechansim (RFC 2025). |
1859 | 1854 | ||
1860 | Note: Requires an auxiliary userspace daemon which may be found on | 1855 | Secure RPC calls with SPKM3 require an auxiliary userspace |
1861 | http://www.citi.umich.edu/projects/nfsv4/ | 1856 | daemon which may be found in the Linux nfs-utils package |
1857 | available from http://linux-nfs.org/. | ||
1862 | 1858 | ||
1863 | If unsure, say N. | 1859 | If unsure, say N. |
1864 | 1860 | ||
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index b6b74a60e1eb..40b16f23e49a 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -155,8 +155,6 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | 155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
156 | { | 156 | { |
157 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
158 | sigset_t oldset; | ||
159 | unsigned long flags; | ||
160 | int status; | 158 | int status; |
161 | 159 | ||
162 | nlm_get_host(host); | 160 | nlm_get_host(host); |
@@ -168,22 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
168 | /* Set up the argument struct */ | 166 | /* Set up the argument struct */ |
169 | nlmclnt_setlockargs(call, fl); | 167 | nlmclnt_setlockargs(call, fl); |
170 | 168 | ||
171 | /* Keep the old signal mask */ | ||
172 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
173 | oldset = current->blocked; | ||
174 | |||
175 | /* If we're cleaning up locks because the process is exiting, | ||
176 | * perform the RPC call asynchronously. */ | ||
177 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) | ||
178 | && fl->fl_type == F_UNLCK | ||
179 | && (current->flags & PF_EXITING)) { | ||
180 | sigfillset(¤t->blocked); /* Mask all signals */ | ||
181 | recalc_sigpending(); | ||
182 | |||
183 | call->a_flags = RPC_TASK_ASYNC; | ||
184 | } | ||
185 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
186 | |||
187 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 169 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
188 | if (fl->fl_type != F_UNLCK) { | 170 | if (fl->fl_type != F_UNLCK) { |
189 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 171 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -198,11 +180,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
198 | fl->fl_ops->fl_release_private(fl); | 180 | fl->fl_ops->fl_release_private(fl); |
199 | fl->fl_ops = NULL; | 181 | fl->fl_ops = NULL; |
200 | 182 | ||
201 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
202 | current->blocked = oldset; | ||
203 | recalc_sigpending(); | ||
204 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
205 | |||
206 | dprintk("lockd: clnt proc returns %d\n", status); | 183 | dprintk("lockd: clnt proc returns %d\n", status); |
207 | return status; | 184 | return status; |
208 | } | 185 | } |
@@ -221,6 +198,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
221 | for(;;) { | 198 | for(;;) { |
222 | call = kzalloc(sizeof(*call), GFP_KERNEL); | 199 | call = kzalloc(sizeof(*call), GFP_KERNEL); |
223 | if (call != NULL) { | 200 | if (call != NULL) { |
201 | atomic_set(&call->a_count, 1); | ||
224 | locks_init_lock(&call->a_args.lock.fl); | 202 | locks_init_lock(&call->a_args.lock.fl); |
225 | locks_init_lock(&call->a_res.lock.fl); | 203 | locks_init_lock(&call->a_res.lock.fl); |
226 | call->a_host = host; | 204 | call->a_host = host; |
@@ -237,6 +215,8 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
237 | 215 | ||
238 | void nlm_release_call(struct nlm_rqst *call) | 216 | void nlm_release_call(struct nlm_rqst *call) |
239 | { | 217 | { |
218 | if (!atomic_dec_and_test(&call->a_count)) | ||
219 | return; | ||
240 | nlm_release_host(call->a_host); | 220 | nlm_release_host(call->a_host); |
241 | nlmclnt_release_lockargs(call); | 221 | nlmclnt_release_lockargs(call); |
242 | kfree(call); | 222 | kfree(call); |
@@ -267,7 +247,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) | |||
267 | * Generic NLM call | 247 | * Generic NLM call |
268 | */ | 248 | */ |
269 | static int | 249 | static int |
270 | nlmclnt_call(struct nlm_rqst *req, u32 proc) | 250 | nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc) |
271 | { | 251 | { |
272 | struct nlm_host *host = req->a_host; | 252 | struct nlm_host *host = req->a_host; |
273 | struct rpc_clnt *clnt; | 253 | struct rpc_clnt *clnt; |
@@ -276,6 +256,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) | |||
276 | struct rpc_message msg = { | 256 | struct rpc_message msg = { |
277 | .rpc_argp = argp, | 257 | .rpc_argp = argp, |
278 | .rpc_resp = resp, | 258 | .rpc_resp = resp, |
259 | .rpc_cred = cred, | ||
279 | }; | 260 | }; |
280 | int status; | 261 | int status; |
281 | 262 | ||
@@ -343,10 +324,16 @@ in_grace_period: | |||
343 | /* | 324 | /* |
344 | * Generic NLM call, async version. | 325 | * Generic NLM call, async version. |
345 | */ | 326 | */ |
346 | static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | 327 | static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
347 | { | 328 | { |
348 | struct nlm_host *host = req->a_host; | 329 | struct nlm_host *host = req->a_host; |
349 | struct rpc_clnt *clnt; | 330 | struct rpc_clnt *clnt; |
331 | struct rpc_task_setup task_setup_data = { | ||
332 | .rpc_message = msg, | ||
333 | .callback_ops = tk_ops, | ||
334 | .callback_data = req, | ||
335 | .flags = RPC_TASK_ASYNC, | ||
336 | }; | ||
350 | 337 | ||
351 | dprintk("lockd: call procedure %d on %s (async)\n", | 338 | dprintk("lockd: call procedure %d on %s (async)\n", |
352 | (int)proc, host->h_name); | 339 | (int)proc, host->h_name); |
@@ -356,21 +343,36 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * | |||
356 | if (clnt == NULL) | 343 | if (clnt == NULL) |
357 | goto out_err; | 344 | goto out_err; |
358 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | 345 | msg->rpc_proc = &clnt->cl_procinfo[proc]; |
346 | task_setup_data.rpc_client = clnt; | ||
359 | 347 | ||
360 | /* bootstrap and kick off the async RPC call */ | 348 | /* bootstrap and kick off the async RPC call */ |
361 | return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); | 349 | return rpc_run_task(&task_setup_data); |
362 | out_err: | 350 | out_err: |
363 | tk_ops->rpc_release(req); | 351 | tk_ops->rpc_release(req); |
364 | return -ENOLCK; | 352 | return ERR_PTR(-ENOLCK); |
365 | } | 353 | } |
366 | 354 | ||
355 | static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | ||
356 | { | ||
357 | struct rpc_task *task; | ||
358 | |||
359 | task = __nlm_async_call(req, proc, msg, tk_ops); | ||
360 | if (IS_ERR(task)) | ||
361 | return PTR_ERR(task); | ||
362 | rpc_put_task(task); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * NLM asynchronous call. | ||
368 | */ | ||
367 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 369 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
368 | { | 370 | { |
369 | struct rpc_message msg = { | 371 | struct rpc_message msg = { |
370 | .rpc_argp = &req->a_args, | 372 | .rpc_argp = &req->a_args, |
371 | .rpc_resp = &req->a_res, | 373 | .rpc_resp = &req->a_res, |
372 | }; | 374 | }; |
373 | return __nlm_async_call(req, proc, &msg, tk_ops); | 375 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
374 | } | 376 | } |
375 | 377 | ||
376 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 378 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
@@ -378,7 +380,33 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t | |||
378 | struct rpc_message msg = { | 380 | struct rpc_message msg = { |
379 | .rpc_argp = &req->a_res, | 381 | .rpc_argp = &req->a_res, |
380 | }; | 382 | }; |
381 | return __nlm_async_call(req, proc, &msg, tk_ops); | 383 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
384 | } | ||
385 | |||
386 | /* | ||
387 | * NLM client asynchronous call. | ||
388 | * | ||
389 | * Note that although the calls are asynchronous, and are therefore | ||
390 | * guaranteed to complete, we still always attempt to wait for | ||
391 | * completion in order to be able to correctly track the lock | ||
392 | * state. | ||
393 | */ | ||
394 | static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | ||
395 | { | ||
396 | struct rpc_message msg = { | ||
397 | .rpc_argp = &req->a_args, | ||
398 | .rpc_resp = &req->a_res, | ||
399 | .rpc_cred = cred, | ||
400 | }; | ||
401 | struct rpc_task *task; | ||
402 | int err; | ||
403 | |||
404 | task = __nlm_async_call(req, proc, &msg, tk_ops); | ||
405 | if (IS_ERR(task)) | ||
406 | return PTR_ERR(task); | ||
407 | err = rpc_wait_for_completion_task(task); | ||
408 | rpc_put_task(task); | ||
409 | return err; | ||
382 | } | 410 | } |
383 | 411 | ||
384 | /* | 412 | /* |
@@ -389,7 +417,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
389 | { | 417 | { |
390 | int status; | 418 | int status; |
391 | 419 | ||
392 | status = nlmclnt_call(req, NLMPROC_TEST); | 420 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST); |
393 | if (status < 0) | 421 | if (status < 0) |
394 | goto out; | 422 | goto out; |
395 | 423 | ||
@@ -480,10 +508,12 @@ static int do_vfs_lock(struct file_lock *fl) | |||
480 | static int | 508 | static int |
481 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | 509 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) |
482 | { | 510 | { |
511 | struct rpc_cred *cred = nfs_file_cred(fl->fl_file); | ||
483 | struct nlm_host *host = req->a_host; | 512 | struct nlm_host *host = req->a_host; |
484 | struct nlm_res *resp = &req->a_res; | 513 | struct nlm_res *resp = &req->a_res; |
485 | struct nlm_wait *block = NULL; | 514 | struct nlm_wait *block = NULL; |
486 | unsigned char fl_flags = fl->fl_flags; | 515 | unsigned char fl_flags = fl->fl_flags; |
516 | unsigned char fl_type; | ||
487 | int status = -ENOLCK; | 517 | int status = -ENOLCK; |
488 | 518 | ||
489 | if (nsm_monitor(host) < 0) { | 519 | if (nsm_monitor(host) < 0) { |
@@ -493,18 +523,22 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
493 | } | 523 | } |
494 | fl->fl_flags |= FL_ACCESS; | 524 | fl->fl_flags |= FL_ACCESS; |
495 | status = do_vfs_lock(fl); | 525 | status = do_vfs_lock(fl); |
526 | fl->fl_flags = fl_flags; | ||
496 | if (status < 0) | 527 | if (status < 0) |
497 | goto out; | 528 | goto out; |
498 | 529 | ||
499 | block = nlmclnt_prepare_block(host, fl); | 530 | block = nlmclnt_prepare_block(host, fl); |
500 | again: | 531 | again: |
532 | /* | ||
533 | * Initialise resp->status to a valid non-zero value, | ||
534 | * since 0 == nlm_lck_granted | ||
535 | */ | ||
536 | resp->status = nlm_lck_blocked; | ||
501 | for(;;) { | 537 | for(;;) { |
502 | /* Reboot protection */ | 538 | /* Reboot protection */ |
503 | fl->fl_u.nfs_fl.state = host->h_state; | 539 | fl->fl_u.nfs_fl.state = host->h_state; |
504 | status = nlmclnt_call(req, NLMPROC_LOCK); | 540 | status = nlmclnt_call(cred, req, NLMPROC_LOCK); |
505 | if (status < 0) | 541 | if (status < 0) |
506 | goto out_unblock; | ||
507 | if (!req->a_args.block) | ||
508 | break; | 542 | break; |
509 | /* Did a reclaimer thread notify us of a server reboot? */ | 543 | /* Did a reclaimer thread notify us of a server reboot? */ |
510 | if (resp->status == nlm_lck_denied_grace_period) | 544 | if (resp->status == nlm_lck_denied_grace_period) |
@@ -513,15 +547,22 @@ again: | |||
513 | break; | 547 | break; |
514 | /* Wait on an NLM blocking lock */ | 548 | /* Wait on an NLM blocking lock */ |
515 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); | 549 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
516 | /* if we were interrupted. Send a CANCEL request to the server | ||
517 | * and exit | ||
518 | */ | ||
519 | if (status < 0) | 550 | if (status < 0) |
520 | goto out_unblock; | 551 | break; |
521 | if (resp->status != nlm_lck_blocked) | 552 | if (resp->status != nlm_lck_blocked) |
522 | break; | 553 | break; |
523 | } | 554 | } |
524 | 555 | ||
556 | /* if we were interrupted while blocking, then cancel the lock request | ||
557 | * and exit | ||
558 | */ | ||
559 | if (resp->status == nlm_lck_blocked) { | ||
560 | if (!req->a_args.block) | ||
561 | goto out_unlock; | ||
562 | if (nlmclnt_cancel(host, req->a_args.block, fl) == 0) | ||
563 | goto out_unblock; | ||
564 | } | ||
565 | |||
525 | if (resp->status == nlm_granted) { | 566 | if (resp->status == nlm_granted) { |
526 | down_read(&host->h_rwsem); | 567 | down_read(&host->h_rwsem); |
527 | /* Check whether or not the server has rebooted */ | 568 | /* Check whether or not the server has rebooted */ |
@@ -530,20 +571,34 @@ again: | |||
530 | goto again; | 571 | goto again; |
531 | } | 572 | } |
532 | /* Ensure the resulting lock will get added to granted list */ | 573 | /* Ensure the resulting lock will get added to granted list */ |
533 | fl->fl_flags = fl_flags | FL_SLEEP; | 574 | fl->fl_flags |= FL_SLEEP; |
534 | if (do_vfs_lock(fl) < 0) | 575 | if (do_vfs_lock(fl) < 0) |
535 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); | 576 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); |
536 | up_read(&host->h_rwsem); | 577 | up_read(&host->h_rwsem); |
578 | fl->fl_flags = fl_flags; | ||
579 | status = 0; | ||
537 | } | 580 | } |
581 | if (status < 0) | ||
582 | goto out_unlock; | ||
538 | status = nlm_stat_to_errno(resp->status); | 583 | status = nlm_stat_to_errno(resp->status); |
539 | out_unblock: | 584 | out_unblock: |
540 | nlmclnt_finish_block(block); | 585 | nlmclnt_finish_block(block); |
541 | /* Cancel the blocked request if it is still pending */ | ||
542 | if (resp->status == nlm_lck_blocked) | ||
543 | nlmclnt_cancel(host, req->a_args.block, fl); | ||
544 | out: | 586 | out: |
545 | nlm_release_call(req); | 587 | nlm_release_call(req); |
588 | return status; | ||
589 | out_unlock: | ||
590 | /* Fatal error: ensure that we remove the lock altogether */ | ||
591 | dprintk("lockd: lock attempt ended in fatal error.\n" | ||
592 | " Attempting to unlock.\n"); | ||
593 | nlmclnt_finish_block(block); | ||
594 | fl_type = fl->fl_type; | ||
595 | fl->fl_type = F_UNLCK; | ||
596 | down_read(&host->h_rwsem); | ||
597 | do_vfs_lock(fl); | ||
598 | up_read(&host->h_rwsem); | ||
599 | fl->fl_type = fl_type; | ||
546 | fl->fl_flags = fl_flags; | 600 | fl->fl_flags = fl_flags; |
601 | nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
547 | return status; | 602 | return status; |
548 | } | 603 | } |
549 | 604 | ||
@@ -567,8 +622,8 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) | |||
567 | nlmclnt_setlockargs(req, fl); | 622 | nlmclnt_setlockargs(req, fl); |
568 | req->a_args.reclaim = 1; | 623 | req->a_args.reclaim = 1; |
569 | 624 | ||
570 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0 | 625 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK); |
571 | && req->a_res.status == nlm_granted) | 626 | if (status >= 0 && req->a_res.status == nlm_granted) |
572 | return 0; | 627 | return 0; |
573 | 628 | ||
574 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " | 629 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " |
@@ -598,7 +653,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
598 | { | 653 | { |
599 | struct nlm_host *host = req->a_host; | 654 | struct nlm_host *host = req->a_host; |
600 | struct nlm_res *resp = &req->a_res; | 655 | struct nlm_res *resp = &req->a_res; |
601 | int status = 0; | 656 | int status; |
657 | unsigned char fl_flags = fl->fl_flags; | ||
602 | 658 | ||
603 | /* | 659 | /* |
604 | * Note: the server is supposed to either grant us the unlock | 660 | * Note: the server is supposed to either grant us the unlock |
@@ -607,16 +663,17 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
607 | */ | 663 | */ |
608 | fl->fl_flags |= FL_EXISTS; | 664 | fl->fl_flags |= FL_EXISTS; |
609 | down_read(&host->h_rwsem); | 665 | down_read(&host->h_rwsem); |
610 | if (do_vfs_lock(fl) == -ENOENT) { | 666 | status = do_vfs_lock(fl); |
611 | up_read(&host->h_rwsem); | 667 | up_read(&host->h_rwsem); |
668 | fl->fl_flags = fl_flags; | ||
669 | if (status == -ENOENT) { | ||
670 | status = 0; | ||
612 | goto out; | 671 | goto out; |
613 | } | 672 | } |
614 | up_read(&host->h_rwsem); | ||
615 | |||
616 | if (req->a_flags & RPC_TASK_ASYNC) | ||
617 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
618 | 673 | ||
619 | status = nlmclnt_call(req, NLMPROC_UNLOCK); | 674 | atomic_inc(&req->a_count); |
675 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | ||
676 | NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
620 | if (status < 0) | 677 | if (status < 0) |
621 | goto out; | 678 | goto out; |
622 | 679 | ||
@@ -671,16 +728,10 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = { | |||
671 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) | 728 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) |
672 | { | 729 | { |
673 | struct nlm_rqst *req; | 730 | struct nlm_rqst *req; |
674 | unsigned long flags; | 731 | int status; |
675 | sigset_t oldset; | ||
676 | int status; | ||
677 | 732 | ||
678 | /* Block all signals while setting up call */ | 733 | dprintk("lockd: blocking lock attempt was interrupted by a signal.\n" |
679 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 734 | " Attempting to cancel lock.\n"); |
680 | oldset = current->blocked; | ||
681 | sigfillset(¤t->blocked); | ||
682 | recalc_sigpending(); | ||
683 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
684 | 735 | ||
685 | req = nlm_alloc_call(nlm_get_host(host)); | 736 | req = nlm_alloc_call(nlm_get_host(host)); |
686 | if (!req) | 737 | if (!req) |
@@ -690,13 +741,12 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
690 | nlmclnt_setlockargs(req, fl); | 741 | nlmclnt_setlockargs(req, fl); |
691 | req->a_args.block = block; | 742 | req->a_args.block = block; |
692 | 743 | ||
693 | status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 744 | atomic_inc(&req->a_count); |
694 | 745 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | |
695 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 746 | NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
696 | current->blocked = oldset; | 747 | if (status == 0 && req->a_res.status == nlm_lck_denied) |
697 | recalc_sigpending(); | 748 | status = -ENOLCK; |
698 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 749 | nlm_release_call(req); |
699 | |||
700 | return status; | 750 | return status; |
701 | } | 751 | } |
702 | 752 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index c7854791898f..a17664c7eacc 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -41,11 +41,12 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, | |||
41 | /* | 41 | /* |
42 | * Common host lookup routine for server & client | 42 | * Common host lookup routine for server & client |
43 | */ | 43 | */ |
44 | static struct nlm_host * | 44 | static struct nlm_host *nlm_lookup_host(int server, |
45 | nlm_lookup_host(int server, const struct sockaddr_in *sin, | 45 | const struct sockaddr_in *sin, |
46 | int proto, int version, const char *hostname, | 46 | int proto, u32 version, |
47 | unsigned int hostname_len, | 47 | const char *hostname, |
48 | const struct sockaddr_in *ssin) | 48 | unsigned int hostname_len, |
49 | const struct sockaddr_in *ssin) | ||
49 | { | 50 | { |
50 | struct hlist_head *chain; | 51 | struct hlist_head *chain; |
51 | struct hlist_node *pos; | 52 | struct hlist_node *pos; |
@@ -54,7 +55,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
54 | int hash; | 55 | int hash; |
55 | 56 | ||
56 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT | 57 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT |
57 | ", p=%d, v=%d, my role=%s, name=%.*s)\n", | 58 | ", p=%d, v=%u, my role=%s, name=%.*s)\n", |
58 | NIPQUAD(ssin->sin_addr.s_addr), | 59 | NIPQUAD(ssin->sin_addr.s_addr), |
59 | NIPQUAD(sin->sin_addr.s_addr), proto, version, | 60 | NIPQUAD(sin->sin_addr.s_addr), proto, version, |
60 | server? "server" : "client", | 61 | server? "server" : "client", |
@@ -172,9 +173,10 @@ nlm_destroy_host(struct nlm_host *host) | |||
172 | /* | 173 | /* |
173 | * Find an NLM server handle in the cache. If there is none, create it. | 174 | * Find an NLM server handle in the cache. If there is none, create it. |
174 | */ | 175 | */ |
175 | struct nlm_host * | 176 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin, |
176 | nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, | 177 | int proto, u32 version, |
177 | const char *hostname, unsigned int hostname_len) | 178 | const char *hostname, |
179 | unsigned int hostname_len) | ||
178 | { | 180 | { |
179 | struct sockaddr_in ssin = {0}; | 181 | struct sockaddr_in ssin = {0}; |
180 | 182 | ||
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 908b23fadd05..e4d563543b11 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #define NLMDBG_FACILITY NLMDBG_MONITOR | 19 | #define NLMDBG_FACILITY NLMDBG_MONITOR |
20 | 20 | ||
21 | #define XDR_ADDRBUF_LEN (20) | ||
22 | |||
21 | static struct rpc_clnt * nsm_create(void); | 23 | static struct rpc_clnt * nsm_create(void); |
22 | 24 | ||
23 | static struct rpc_program nsm_program; | 25 | static struct rpc_program nsm_program; |
@@ -147,28 +149,55 @@ nsm_create(void) | |||
147 | 149 | ||
148 | /* | 150 | /* |
149 | * XDR functions for NSM. | 151 | * XDR functions for NSM. |
152 | * | ||
153 | * See http://www.opengroup.org/ for details on the Network | ||
154 | * Status Monitor wire protocol. | ||
150 | */ | 155 | */ |
151 | 156 | ||
152 | static __be32 * | 157 | static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) |
153 | xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
154 | { | 158 | { |
155 | char buffer[20], *name; | 159 | size_t len = strlen(string); |
156 | 160 | ||
157 | /* | 161 | if (len > SM_MAXSTRLEN) |
158 | * Use the dotted-quad IP address of the remote host as | 162 | len = SM_MAXSTRLEN; |
159 | * identifier. Linux statd always looks up the canonical | 163 | return xdr_encode_opaque(p, string, len); |
160 | * hostname first for whatever remote hostname it receives, | 164 | } |
161 | * so this works alright. | 165 | |
162 | */ | 166 | /* |
163 | if (nsm_use_hostnames) { | 167 | * "mon_name" specifies the host to be monitored. |
164 | name = argp->mon_name; | 168 | * |
165 | } else { | 169 | * Linux uses a text version of the IP address of the remote |
166 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); | 170 | * host as the host identifier (the "mon_name" argument). |
171 | * | ||
172 | * Linux statd always looks up the canonical hostname first for | ||
173 | * whatever remote hostname it receives, so this works alright. | ||
174 | */ | ||
175 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | ||
176 | { | ||
177 | char buffer[XDR_ADDRBUF_LEN + 1]; | ||
178 | char *name = argp->mon_name; | ||
179 | |||
180 | if (!nsm_use_hostnames) { | ||
181 | snprintf(buffer, XDR_ADDRBUF_LEN, | ||
182 | NIPQUAD_FMT, NIPQUAD(argp->addr)); | ||
167 | name = buffer; | 183 | name = buffer; |
168 | } | 184 | } |
169 | if (!(p = xdr_encode_string(p, name)) | 185 | |
170 | || !(p = xdr_encode_string(p, utsname()->nodename))) | 186 | return xdr_encode_nsm_string(p, name); |
187 | } | ||
188 | |||
189 | /* | ||
190 | * The "my_id" argument specifies the hostname and RPC procedure | ||
191 | * to be called when the status manager receives notification | ||
192 | * (via the SM_NOTIFY call) that the state of host "mon_name" | ||
193 | * has changed. | ||
194 | */ | ||
195 | static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) | ||
196 | { | ||
197 | p = xdr_encode_nsm_string(p, utsname()->nodename); | ||
198 | if (!p) | ||
171 | return ERR_PTR(-EIO); | 199 | return ERR_PTR(-EIO); |
200 | |||
172 | *p++ = htonl(argp->prog); | 201 | *p++ = htonl(argp->prog); |
173 | *p++ = htonl(argp->vers); | 202 | *p++ = htonl(argp->vers); |
174 | *p++ = htonl(argp->proc); | 203 | *p++ = htonl(argp->proc); |
@@ -176,18 +205,48 @@ xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
176 | return p; | 205 | return p; |
177 | } | 206 | } |
178 | 207 | ||
179 | static int | 208 | /* |
180 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 209 | * The "mon_id" argument specifies the non-private arguments |
210 | * of an SM_MON or SM_UNMON call. | ||
211 | */ | ||
212 | static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) | ||
181 | { | 213 | { |
182 | p = xdr_encode_common(rqstp, p, argp); | 214 | p = xdr_encode_mon_name(p, argp); |
183 | if (IS_ERR(p)) | 215 | if (!p) |
184 | return PTR_ERR(p); | 216 | return ERR_PTR(-EIO); |
185 | 217 | ||
186 | /* Surprise - there may even be room for an IPv6 address now */ | 218 | return xdr_encode_my_id(p, argp); |
219 | } | ||
220 | |||
221 | /* | ||
222 | * The "priv" argument may contain private information required | ||
223 | * by the SM_MON call. This information will be supplied in the | ||
224 | * SM_NOTIFY call. | ||
225 | * | ||
226 | * Linux provides the raw IP address of the monitored host, | ||
227 | * left in network byte order. | ||
228 | */ | ||
229 | static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) | ||
230 | { | ||
187 | *p++ = argp->addr; | 231 | *p++ = argp->addr; |
188 | *p++ = 0; | 232 | *p++ = 0; |
189 | *p++ = 0; | 233 | *p++ = 0; |
190 | *p++ = 0; | 234 | *p++ = 0; |
235 | |||
236 | return p; | ||
237 | } | ||
238 | |||
239 | static int | ||
240 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
241 | { | ||
242 | p = xdr_encode_mon_id(p, argp); | ||
243 | if (IS_ERR(p)) | ||
244 | return PTR_ERR(p); | ||
245 | |||
246 | p = xdr_encode_priv(p, argp); | ||
247 | if (IS_ERR(p)) | ||
248 | return PTR_ERR(p); | ||
249 | |||
191 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 250 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
192 | return 0; | 251 | return 0; |
193 | } | 252 | } |
@@ -195,7 +254,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
195 | static int | 254 | static int |
196 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 255 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) |
197 | { | 256 | { |
198 | p = xdr_encode_common(rqstp, p, argp); | 257 | p = xdr_encode_mon_id(p, argp); |
199 | if (IS_ERR(p)) | 258 | if (IS_ERR(p)) |
200 | return PTR_ERR(p); | 259 | return PTR_ERR(p); |
201 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 260 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
@@ -220,9 +279,11 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | |||
220 | } | 279 | } |
221 | 280 | ||
222 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) | 281 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
223 | #define SM_my_id_sz (3+1+SM_my_name_sz) | 282 | #define SM_my_id_sz (SM_my_name_sz+3) |
224 | #define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz) | 283 | #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
225 | #define SM_mon_sz (SM_mon_id_sz+4) | 284 | #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) |
285 | #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) | ||
286 | #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) | ||
226 | #define SM_monres_sz 2 | 287 | #define SM_monres_sz 2 |
227 | #define SM_unmonres_sz 1 | 288 | #define SM_unmonres_sz 1 |
228 | 289 | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index cf977bbcf303..2169af4d5455 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -72,7 +72,9 @@ static const unsigned long nlm_timeout_min = 3; | |||
72 | static const unsigned long nlm_timeout_max = 20; | 72 | static const unsigned long nlm_timeout_max = 20; |
73 | static const int nlm_port_min = 0, nlm_port_max = 65535; | 73 | static const int nlm_port_min = 0, nlm_port_max = 65535; |
74 | 74 | ||
75 | #ifdef CONFIG_SYSCTL | ||
75 | static struct ctl_table_header * nlm_sysctl_table; | 76 | static struct ctl_table_header * nlm_sysctl_table; |
77 | #endif | ||
76 | 78 | ||
77 | static unsigned long get_lockd_grace_period(void) | 79 | static unsigned long get_lockd_grace_period(void) |
78 | { | 80 | { |
@@ -349,6 +351,8 @@ out: | |||
349 | } | 351 | } |
350 | EXPORT_SYMBOL(lockd_down); | 352 | EXPORT_SYMBOL(lockd_down); |
351 | 353 | ||
354 | #ifdef CONFIG_SYSCTL | ||
355 | |||
352 | /* | 356 | /* |
353 | * Sysctl parameters (same as module parameters, different interface). | 357 | * Sysctl parameters (same as module parameters, different interface). |
354 | */ | 358 | */ |
@@ -433,6 +437,8 @@ static ctl_table nlm_sysctl_root[] = { | |||
433 | { .ctl_name = 0 } | 437 | { .ctl_name = 0 } |
434 | }; | 438 | }; |
435 | 439 | ||
440 | #endif /* CONFIG_SYSCTL */ | ||
441 | |||
436 | /* | 442 | /* |
437 | * Module (and sysfs) parameters. | 443 | * Module (and sysfs) parameters. |
438 | */ | 444 | */ |
@@ -506,15 +512,21 @@ module_param(nsm_use_hostnames, bool, 0644); | |||
506 | 512 | ||
507 | static int __init init_nlm(void) | 513 | static int __init init_nlm(void) |
508 | { | 514 | { |
515 | #ifdef CONFIG_SYSCTL | ||
509 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); | 516 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); |
510 | return nlm_sysctl_table ? 0 : -ENOMEM; | 517 | return nlm_sysctl_table ? 0 : -ENOMEM; |
518 | #else | ||
519 | return 0; | ||
520 | #endif | ||
511 | } | 521 | } |
512 | 522 | ||
513 | static void __exit exit_nlm(void) | 523 | static void __exit exit_nlm(void) |
514 | { | 524 | { |
515 | /* FIXME: delete all NLM clients */ | 525 | /* FIXME: delete all NLM clients */ |
516 | nlm_shutdown_hosts(); | 526 | nlm_shutdown_hosts(); |
527 | #ifdef CONFIG_SYSCTL | ||
517 | unregister_sysctl_table(nlm_sysctl_table); | 528 | unregister_sysctl_table(nlm_sysctl_table); |
529 | #endif | ||
518 | } | 530 | } |
519 | 531 | ||
520 | module_init(init_nlm); | 532 | module_init(init_nlm); |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index df0f41e09885..ac6170c594a3 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | obj-$(CONFIG_NFS_FS) += nfs.o | 5 | obj-$(CONFIG_NFS_FS) += nfs.o |
6 | 6 | ||
7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ |
8 | pagelist.o proc.o read.o symlink.o unlink.o \ | 8 | direct.o pagelist.o proc.o read.o symlink.o unlink.o \ |
9 | write.o namespace.o mount_clnt.o | 9 | write.o namespace.o mount_clnt.o |
10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
@@ -14,5 +14,4 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |||
14 | delegation.o idmap.o \ | 14 | delegation.o idmap.o \ |
15 | callback.o callback_xdr.o callback_proc.o \ | 15 | callback.o callback_xdr.o callback_proc.o \ |
16 | nfs4namespace.o | 16 | nfs4namespace.o |
17 | nfs-$(CONFIG_NFS_DIRECTIO) += direct.o | ||
18 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 17 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index c5c0175898f6..f2f3b284e6dd 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -112,6 +112,7 @@ struct nfs_client_initdata { | |||
112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) | 112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
113 | { | 113 | { |
114 | struct nfs_client *clp; | 114 | struct nfs_client *clp; |
115 | struct rpc_cred *cred; | ||
115 | 116 | ||
116 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 117 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
117 | goto error_0; | 118 | goto error_0; |
@@ -150,6 +151,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | clp->cl_boot_time = CURRENT_TIME; | 151 | clp->cl_boot_time = CURRENT_TIME; |
151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
152 | #endif | 153 | #endif |
154 | cred = rpc_lookup_machine_cred(); | ||
155 | if (!IS_ERR(cred)) | ||
156 | clp->cl_machine_cred = cred; | ||
153 | 157 | ||
154 | return clp; | 158 | return clp; |
155 | 159 | ||
@@ -170,6 +174,8 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
170 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); | 174 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); |
171 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | 175 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) |
172 | nfs_idmap_delete(clp); | 176 | nfs_idmap_delete(clp); |
177 | |||
178 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
173 | #endif | 179 | #endif |
174 | } | 180 | } |
175 | 181 | ||
@@ -189,6 +195,9 @@ static void nfs_free_client(struct nfs_client *clp) | |||
189 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | 195 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) |
190 | nfs_callback_down(); | 196 | nfs_callback_down(); |
191 | 197 | ||
198 | if (clp->cl_machine_cred != NULL) | ||
199 | put_rpccred(clp->cl_machine_cred); | ||
200 | |||
192 | kfree(clp->cl_hostname); | 201 | kfree(clp->cl_hostname); |
193 | kfree(clp); | 202 | kfree(clp); |
194 | 203 | ||
@@ -680,10 +689,22 @@ static int nfs_init_server(struct nfs_server *server, | |||
680 | if (error < 0) | 689 | if (error < 0) |
681 | goto error; | 690 | goto error; |
682 | 691 | ||
692 | server->port = data->nfs_server.port; | ||
693 | |||
683 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 694 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
684 | if (error < 0) | 695 | if (error < 0) |
685 | goto error; | 696 | goto error; |
686 | 697 | ||
698 | /* Preserve the values of mount_server-related mount options */ | ||
699 | if (data->mount_server.addrlen) { | ||
700 | memcpy(&server->mountd_address, &data->mount_server.address, | ||
701 | data->mount_server.addrlen); | ||
702 | server->mountd_addrlen = data->mount_server.addrlen; | ||
703 | } | ||
704 | server->mountd_version = data->mount_server.version; | ||
705 | server->mountd_port = data->mount_server.port; | ||
706 | server->mountd_protocol = data->mount_server.protocol; | ||
707 | |||
687 | server->namelen = data->namlen; | 708 | server->namelen = data->namlen; |
688 | /* Create a client RPC handle for the NFSv3 ACL management interface */ | 709 | /* Create a client RPC handle for the NFSv3 ACL management interface */ |
689 | nfs_init_server_aclclient(server); | 710 | nfs_init_server_aclclient(server); |
@@ -1062,6 +1083,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1062 | server->acdirmin = data->acdirmin * HZ; | 1083 | server->acdirmin = data->acdirmin * HZ; |
1063 | server->acdirmax = data->acdirmax * HZ; | 1084 | server->acdirmax = data->acdirmax * HZ; |
1064 | 1085 | ||
1086 | server->port = data->nfs_server.port; | ||
1087 | |||
1065 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 1088 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
1066 | 1089 | ||
1067 | error: | 1090 | error: |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d9e30ac2798d..f288b3ecab4a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1967,7 +1967,7 @@ force_lookup: | |||
1967 | if (!NFS_PROTO(inode)->access) | 1967 | if (!NFS_PROTO(inode)->access) |
1968 | goto out_notsup; | 1968 | goto out_notsup; |
1969 | 1969 | ||
1970 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1970 | cred = rpc_lookup_cred(); |
1971 | if (!IS_ERR(cred)) { | 1971 | if (!IS_ERR(cred)) { |
1972 | res = nfs_do_access(inode, cred, mask); | 1972 | res = nfs_do_access(inode, cred, mask); |
1973 | put_rpccred(cred); | 1973 | put_rpccred(cred); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 16844f98f50e..4757a2b326a1 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -229,14 +229,20 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) | |||
229 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) | 229 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) |
230 | { | 230 | { |
231 | struct nfs_read_data *data = calldata; | 231 | struct nfs_read_data *data = calldata; |
232 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
233 | 232 | ||
234 | if (nfs_readpage_result(task, data) != 0) | 233 | nfs_readpage_result(task, data); |
235 | return; | 234 | } |
235 | |||
236 | static void nfs_direct_read_release(void *calldata) | ||
237 | { | ||
238 | |||
239 | struct nfs_read_data *data = calldata; | ||
240 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
241 | int status = data->task.tk_status; | ||
236 | 242 | ||
237 | spin_lock(&dreq->lock); | 243 | spin_lock(&dreq->lock); |
238 | if (unlikely(task->tk_status < 0)) { | 244 | if (unlikely(status < 0)) { |
239 | dreq->error = task->tk_status; | 245 | dreq->error = status; |
240 | spin_unlock(&dreq->lock); | 246 | spin_unlock(&dreq->lock); |
241 | } else { | 247 | } else { |
242 | dreq->count += data->res.count; | 248 | dreq->count += data->res.count; |
@@ -249,11 +255,12 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata) | |||
249 | 255 | ||
250 | if (put_dreq(dreq)) | 256 | if (put_dreq(dreq)) |
251 | nfs_direct_complete(dreq); | 257 | nfs_direct_complete(dreq); |
258 | nfs_readdata_release(calldata); | ||
252 | } | 259 | } |
253 | 260 | ||
254 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
255 | .rpc_call_done = nfs_direct_read_result, | 262 | .rpc_call_done = nfs_direct_read_result, |
256 | .rpc_release = nfs_readdata_release, | 263 | .rpc_release = nfs_direct_read_release, |
257 | }; | 264 | }; |
258 | 265 | ||
259 | /* | 266 | /* |
@@ -280,6 +287,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
280 | .rpc_client = NFS_CLIENT(inode), | 287 | .rpc_client = NFS_CLIENT(inode), |
281 | .rpc_message = &msg, | 288 | .rpc_message = &msg, |
282 | .callback_ops = &nfs_read_direct_ops, | 289 | .callback_ops = &nfs_read_direct_ops, |
290 | .workqueue = nfsiod_workqueue, | ||
283 | .flags = RPC_TASK_ASYNC, | 291 | .flags = RPC_TASK_ASYNC, |
284 | }; | 292 | }; |
285 | unsigned int pgbase; | 293 | unsigned int pgbase; |
@@ -323,7 +331,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
323 | data->inode = inode; | 331 | data->inode = inode; |
324 | data->cred = msg.rpc_cred; | 332 | data->cred = msg.rpc_cred; |
325 | data->args.fh = NFS_FH(inode); | 333 | data->args.fh = NFS_FH(inode); |
326 | data->args.context = ctx; | 334 | data->args.context = get_nfs_open_context(ctx); |
327 | data->args.offset = pos; | 335 | data->args.offset = pos; |
328 | data->args.pgbase = pgbase; | 336 | data->args.pgbase = pgbase; |
329 | data->args.pages = data->pagevec; | 337 | data->args.pages = data->pagevec; |
@@ -339,8 +347,9 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
339 | NFS_PROTO(inode)->read_setup(data, &msg); | 347 | NFS_PROTO(inode)->read_setup(data, &msg); |
340 | 348 | ||
341 | task = rpc_run_task(&task_setup_data); | 349 | task = rpc_run_task(&task_setup_data); |
342 | if (!IS_ERR(task)) | 350 | if (IS_ERR(task)) |
343 | rpc_put_task(task); | 351 | break; |
352 | rpc_put_task(task); | ||
344 | 353 | ||
345 | dprintk("NFS: %5u initiated direct read call " | 354 | dprintk("NFS: %5u initiated direct read call " |
346 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 355 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -446,6 +455,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
446 | struct rpc_task_setup task_setup_data = { | 455 | struct rpc_task_setup task_setup_data = { |
447 | .rpc_client = NFS_CLIENT(inode), | 456 | .rpc_client = NFS_CLIENT(inode), |
448 | .callback_ops = &nfs_write_direct_ops, | 457 | .callback_ops = &nfs_write_direct_ops, |
458 | .workqueue = nfsiod_workqueue, | ||
449 | .flags = RPC_TASK_ASYNC, | 459 | .flags = RPC_TASK_ASYNC, |
450 | }; | 460 | }; |
451 | 461 | ||
@@ -499,27 +509,34 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
499 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) | 509 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
500 | { | 510 | { |
501 | struct nfs_write_data *data = calldata; | 511 | struct nfs_write_data *data = calldata; |
502 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
503 | 512 | ||
504 | /* Call the NFS version-specific code */ | 513 | /* Call the NFS version-specific code */ |
505 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 514 | NFS_PROTO(data->inode)->commit_done(task, data); |
506 | return; | 515 | } |
507 | if (unlikely(task->tk_status < 0)) { | 516 | |
517 | static void nfs_direct_commit_release(void *calldata) | ||
518 | { | ||
519 | struct nfs_write_data *data = calldata; | ||
520 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
521 | int status = data->task.tk_status; | ||
522 | |||
523 | if (status < 0) { | ||
508 | dprintk("NFS: %5u commit failed with error %d.\n", | 524 | dprintk("NFS: %5u commit failed with error %d.\n", |
509 | task->tk_pid, task->tk_status); | 525 | data->task.tk_pid, status); |
510 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 526 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
511 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 527 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { |
512 | dprintk("NFS: %5u commit verify failed\n", task->tk_pid); | 528 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
513 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 529 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
514 | } | 530 | } |
515 | 531 | ||
516 | dprintk("NFS: %5u commit returned %d\n", task->tk_pid, task->tk_status); | 532 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
517 | nfs_direct_write_complete(dreq, data->inode); | 533 | nfs_direct_write_complete(dreq, data->inode); |
534 | nfs_commitdata_release(calldata); | ||
518 | } | 535 | } |
519 | 536 | ||
520 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 537 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
521 | .rpc_call_done = nfs_direct_commit_result, | 538 | .rpc_call_done = nfs_direct_commit_result, |
522 | .rpc_release = nfs_commit_release, | 539 | .rpc_release = nfs_direct_commit_release, |
523 | }; | 540 | }; |
524 | 541 | ||
525 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 542 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
@@ -537,6 +554,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
537 | .rpc_message = &msg, | 554 | .rpc_message = &msg, |
538 | .callback_ops = &nfs_commit_direct_ops, | 555 | .callback_ops = &nfs_commit_direct_ops, |
539 | .callback_data = data, | 556 | .callback_data = data, |
557 | .workqueue = nfsiod_workqueue, | ||
540 | .flags = RPC_TASK_ASYNC, | 558 | .flags = RPC_TASK_ASYNC, |
541 | }; | 559 | }; |
542 | 560 | ||
@@ -546,6 +564,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
546 | data->args.fh = NFS_FH(data->inode); | 564 | data->args.fh = NFS_FH(data->inode); |
547 | data->args.offset = 0; | 565 | data->args.offset = 0; |
548 | data->args.count = 0; | 566 | data->args.count = 0; |
567 | data->args.context = get_nfs_open_context(dreq->ctx); | ||
549 | data->res.count = 0; | 568 | data->res.count = 0; |
550 | data->res.fattr = &data->fattr; | 569 | data->res.fattr = &data->fattr; |
551 | data->res.verf = &data->verf; | 570 | data->res.verf = &data->verf; |
@@ -585,7 +604,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
585 | 604 | ||
586 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) | 605 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) |
587 | { | 606 | { |
588 | dreq->commit_data = nfs_commit_alloc(); | 607 | dreq->commit_data = nfs_commitdata_alloc(); |
589 | if (dreq->commit_data != NULL) | 608 | if (dreq->commit_data != NULL) |
590 | dreq->commit_data->req = (struct nfs_page *) dreq; | 609 | dreq->commit_data->req = (struct nfs_page *) dreq; |
591 | } | 610 | } |
@@ -606,11 +625,20 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
606 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | 625 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
607 | { | 626 | { |
608 | struct nfs_write_data *data = calldata; | 627 | struct nfs_write_data *data = calldata; |
609 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
610 | int status = task->tk_status; | ||
611 | 628 | ||
612 | if (nfs_writeback_done(task, data) != 0) | 629 | if (nfs_writeback_done(task, data) != 0) |
613 | return; | 630 | return; |
631 | } | ||
632 | |||
633 | /* | ||
634 | * NB: Return the value of the first error return code. Subsequent | ||
635 | * errors after the first one are ignored. | ||
636 | */ | ||
637 | static void nfs_direct_write_release(void *calldata) | ||
638 | { | ||
639 | struct nfs_write_data *data = calldata; | ||
640 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
641 | int status = data->task.tk_status; | ||
614 | 642 | ||
615 | spin_lock(&dreq->lock); | 643 | spin_lock(&dreq->lock); |
616 | 644 | ||
@@ -632,23 +660,13 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | |||
632 | break; | 660 | break; |
633 | case NFS_ODIRECT_DO_COMMIT: | 661 | case NFS_ODIRECT_DO_COMMIT: |
634 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { | 662 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { |
635 | dprintk("NFS: %5u write verify failed\n", task->tk_pid); | 663 | dprintk("NFS: %5u write verify failed\n", data->task.tk_pid); |
636 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 664 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
637 | } | 665 | } |
638 | } | 666 | } |
639 | } | 667 | } |
640 | out_unlock: | 668 | out_unlock: |
641 | spin_unlock(&dreq->lock); | 669 | spin_unlock(&dreq->lock); |
642 | } | ||
643 | |||
644 | /* | ||
645 | * NB: Return the value of the first error return code. Subsequent | ||
646 | * errors after the first one are ignored. | ||
647 | */ | ||
648 | static void nfs_direct_write_release(void *calldata) | ||
649 | { | ||
650 | struct nfs_write_data *data = calldata; | ||
651 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
652 | 670 | ||
653 | if (put_dreq(dreq)) | 671 | if (put_dreq(dreq)) |
654 | nfs_direct_write_complete(dreq, data->inode); | 672 | nfs_direct_write_complete(dreq, data->inode); |
@@ -682,6 +700,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
682 | .rpc_client = NFS_CLIENT(inode), | 700 | .rpc_client = NFS_CLIENT(inode), |
683 | .rpc_message = &msg, | 701 | .rpc_message = &msg, |
684 | .callback_ops = &nfs_write_direct_ops, | 702 | .callback_ops = &nfs_write_direct_ops, |
703 | .workqueue = nfsiod_workqueue, | ||
685 | .flags = RPC_TASK_ASYNC, | 704 | .flags = RPC_TASK_ASYNC, |
686 | }; | 705 | }; |
687 | size_t wsize = NFS_SERVER(inode)->wsize; | 706 | size_t wsize = NFS_SERVER(inode)->wsize; |
@@ -728,7 +747,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
728 | data->inode = inode; | 747 | data->inode = inode; |
729 | data->cred = msg.rpc_cred; | 748 | data->cred = msg.rpc_cred; |
730 | data->args.fh = NFS_FH(inode); | 749 | data->args.fh = NFS_FH(inode); |
731 | data->args.context = ctx; | 750 | data->args.context = get_nfs_open_context(ctx); |
732 | data->args.offset = pos; | 751 | data->args.offset = pos; |
733 | data->args.pgbase = pgbase; | 752 | data->args.pgbase = pgbase; |
734 | data->args.pages = data->pagevec; | 753 | data->args.pages = data->pagevec; |
@@ -745,8 +764,9 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
745 | NFS_PROTO(inode)->write_setup(data, &msg); | 764 | NFS_PROTO(inode)->write_setup(data, &msg); |
746 | 765 | ||
747 | task = rpc_run_task(&task_setup_data); | 766 | task = rpc_run_task(&task_setup_data); |
748 | if (!IS_ERR(task)) | 767 | if (IS_ERR(task)) |
749 | rpc_put_task(task); | 768 | break; |
769 | rpc_put_task(task); | ||
750 | 770 | ||
751 | dprintk("NFS: %5u initiated direct write call " | 771 | dprintk("NFS: %5u initiated direct write call " |
752 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 772 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 5d2e9d9a4e28..3536b01164f9 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -238,10 +238,8 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
238 | ssize_t result; | 238 | ssize_t result; |
239 | size_t count = iov_length(iov, nr_segs); | 239 | size_t count = iov_length(iov, nr_segs); |
240 | 240 | ||
241 | #ifdef CONFIG_NFS_DIRECTIO | ||
242 | if (iocb->ki_filp->f_flags & O_DIRECT) | 241 | if (iocb->ki_filp->f_flags & O_DIRECT) |
243 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); | 242 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); |
244 | #endif | ||
245 | 243 | ||
246 | dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", | 244 | dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", |
247 | dentry->d_parent->d_name.name, dentry->d_name.name, | 245 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -387,9 +385,7 @@ const struct address_space_operations nfs_file_aops = { | |||
387 | .write_end = nfs_write_end, | 385 | .write_end = nfs_write_end, |
388 | .invalidatepage = nfs_invalidate_page, | 386 | .invalidatepage = nfs_invalidate_page, |
389 | .releasepage = nfs_release_page, | 387 | .releasepage = nfs_release_page, |
390 | #ifdef CONFIG_NFS_DIRECTIO | ||
391 | .direct_IO = nfs_direct_IO, | 388 | .direct_IO = nfs_direct_IO, |
392 | #endif | ||
393 | .launder_page = nfs_launder_page, | 389 | .launder_page = nfs_launder_page, |
394 | }; | 390 | }; |
395 | 391 | ||
@@ -447,10 +443,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
447 | ssize_t result; | 443 | ssize_t result; |
448 | size_t count = iov_length(iov, nr_segs); | 444 | size_t count = iov_length(iov, nr_segs); |
449 | 445 | ||
450 | #ifdef CONFIG_NFS_DIRECTIO | ||
451 | if (iocb->ki_filp->f_flags & O_DIRECT) | 446 | if (iocb->ki_filp->f_flags & O_DIRECT) |
452 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); | 447 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); |
453 | #endif | ||
454 | 448 | ||
455 | dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", | 449 | dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", |
456 | dentry->d_parent->d_name.name, dentry->d_name.name, | 450 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -576,17 +570,9 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
576 | 570 | ||
577 | lock_kernel(); | 571 | lock_kernel(); |
578 | /* Use local locking if mounted with "-onolock" */ | 572 | /* Use local locking if mounted with "-onolock" */ |
579 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) { | 573 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
580 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 574 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
581 | /* If we were signalled we still need to ensure that | 575 | else |
582 | * we clean up any state on the server. We therefore | ||
583 | * record the lock call as having succeeded in order to | ||
584 | * ensure that locks_remove_posix() cleans it out when | ||
585 | * the process exits. | ||
586 | */ | ||
587 | if (status == -EINTR || status == -ERESTARTSYS) | ||
588 | do_vfs_lock(filp, fl); | ||
589 | } else | ||
590 | status = do_vfs_lock(filp, fl); | 576 | status = do_vfs_lock(filp, fl); |
591 | unlock_kernel(); | 577 | unlock_kernel(); |
592 | if (status < 0) | 578 | if (status < 0) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6f88d7c77ac9..5cb3345eb694 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -523,8 +523,12 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | |||
523 | 523 | ||
524 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) | 524 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) |
525 | { | 525 | { |
526 | struct inode *inode = ctx->path.dentry->d_inode; | 526 | struct inode *inode; |
527 | 527 | ||
528 | if (ctx == NULL) | ||
529 | return; | ||
530 | |||
531 | inode = ctx->path.dentry->d_inode; | ||
528 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 532 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) |
529 | return; | 533 | return; |
530 | list_del(&ctx->list); | 534 | list_del(&ctx->list); |
@@ -610,7 +614,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
610 | struct nfs_open_context *ctx; | 614 | struct nfs_open_context *ctx; |
611 | struct rpc_cred *cred; | 615 | struct rpc_cred *cred; |
612 | 616 | ||
613 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 617 | cred = rpc_lookup_cred(); |
614 | if (IS_ERR(cred)) | 618 | if (IS_ERR(cred)) |
615 | return PTR_ERR(cred); | 619 | return PTR_ERR(cred); |
616 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); | 620 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); |
@@ -1218,6 +1222,36 @@ static void nfs_destroy_inodecache(void) | |||
1218 | kmem_cache_destroy(nfs_inode_cachep); | 1222 | kmem_cache_destroy(nfs_inode_cachep); |
1219 | } | 1223 | } |
1220 | 1224 | ||
1225 | struct workqueue_struct *nfsiod_workqueue; | ||
1226 | |||
1227 | /* | ||
1228 | * start up the nfsiod workqueue | ||
1229 | */ | ||
1230 | static int nfsiod_start(void) | ||
1231 | { | ||
1232 | struct workqueue_struct *wq; | ||
1233 | dprintk("RPC: creating workqueue nfsiod\n"); | ||
1234 | wq = create_singlethread_workqueue("nfsiod"); | ||
1235 | if (wq == NULL) | ||
1236 | return -ENOMEM; | ||
1237 | nfsiod_workqueue = wq; | ||
1238 | return 0; | ||
1239 | } | ||
1240 | |||
1241 | /* | ||
1242 | * Destroy the nfsiod workqueue | ||
1243 | */ | ||
1244 | static void nfsiod_stop(void) | ||
1245 | { | ||
1246 | struct workqueue_struct *wq; | ||
1247 | |||
1248 | wq = nfsiod_workqueue; | ||
1249 | if (wq == NULL) | ||
1250 | return; | ||
1251 | nfsiod_workqueue = NULL; | ||
1252 | destroy_workqueue(wq); | ||
1253 | } | ||
1254 | |||
1221 | /* | 1255 | /* |
1222 | * Initialize NFS | 1256 | * Initialize NFS |
1223 | */ | 1257 | */ |
@@ -1225,6 +1259,10 @@ static int __init init_nfs_fs(void) | |||
1225 | { | 1259 | { |
1226 | int err; | 1260 | int err; |
1227 | 1261 | ||
1262 | err = nfsiod_start(); | ||
1263 | if (err) | ||
1264 | goto out6; | ||
1265 | |||
1228 | err = nfs_fs_proc_init(); | 1266 | err = nfs_fs_proc_init(); |
1229 | if (err) | 1267 | if (err) |
1230 | goto out5; | 1268 | goto out5; |
@@ -1271,6 +1309,8 @@ out3: | |||
1271 | out4: | 1309 | out4: |
1272 | nfs_fs_proc_exit(); | 1310 | nfs_fs_proc_exit(); |
1273 | out5: | 1311 | out5: |
1312 | nfsiod_stop(); | ||
1313 | out6: | ||
1274 | return err; | 1314 | return err; |
1275 | } | 1315 | } |
1276 | 1316 | ||
@@ -1286,6 +1326,7 @@ static void __exit exit_nfs_fs(void) | |||
1286 | #endif | 1326 | #endif |
1287 | unregister_nfs_fs(); | 1327 | unregister_nfs_fs(); |
1288 | nfs_fs_proc_exit(); | 1328 | nfs_fs_proc_exit(); |
1329 | nfsiod_stop(); | ||
1289 | } | 1330 | } |
1290 | 1331 | ||
1291 | /* Not quite true; I just maintain it */ | 1332 | /* Not quite true; I just maintain it */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 931992763e68..04ae867dddba 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -46,9 +46,9 @@ struct nfs_parsed_mount_data { | |||
46 | struct sockaddr_storage address; | 46 | struct sockaddr_storage address; |
47 | size_t addrlen; | 47 | size_t addrlen; |
48 | char *hostname; | 48 | char *hostname; |
49 | unsigned int version; | 49 | u32 version; |
50 | unsigned short port; | 50 | unsigned short port; |
51 | int protocol; | 51 | unsigned short protocol; |
52 | } mount_server; | 52 | } mount_server; |
53 | 53 | ||
54 | struct { | 54 | struct { |
@@ -56,7 +56,8 @@ struct nfs_parsed_mount_data { | |||
56 | size_t addrlen; | 56 | size_t addrlen; |
57 | char *hostname; | 57 | char *hostname; |
58 | char *export_path; | 58 | char *export_path; |
59 | int protocol; | 59 | unsigned short port; |
60 | unsigned short protocol; | ||
60 | } nfs_server; | 61 | } nfs_server; |
61 | 62 | ||
62 | struct security_mnt_opts lsm_opts; | 63 | struct security_mnt_opts lsm_opts; |
@@ -115,13 +116,8 @@ extern void nfs_destroy_readpagecache(void); | |||
115 | extern int __init nfs_init_writepagecache(void); | 116 | extern int __init nfs_init_writepagecache(void); |
116 | extern void nfs_destroy_writepagecache(void); | 117 | extern void nfs_destroy_writepagecache(void); |
117 | 118 | ||
118 | #ifdef CONFIG_NFS_DIRECTIO | ||
119 | extern int __init nfs_init_directcache(void); | 119 | extern int __init nfs_init_directcache(void); |
120 | extern void nfs_destroy_directcache(void); | 120 | extern void nfs_destroy_directcache(void); |
121 | #else | ||
122 | #define nfs_init_directcache() (0) | ||
123 | #define nfs_destroy_directcache() do {} while(0) | ||
124 | #endif | ||
125 | 121 | ||
126 | /* nfs2xdr.c */ | 122 | /* nfs2xdr.c */ |
127 | extern int nfs_stat_to_errno(int); | 123 | extern int nfs_stat_to_errno(int); |
@@ -146,6 +142,7 @@ extern struct rpc_procinfo nfs4_procedures[]; | |||
146 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | 142 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); |
147 | 143 | ||
148 | /* inode.c */ | 144 | /* inode.c */ |
145 | extern struct workqueue_struct *nfsiod_workqueue; | ||
149 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 146 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
150 | extern void nfs_destroy_inode(struct inode *); | 147 | extern void nfs_destroy_inode(struct inode *); |
151 | extern int nfs_write_inode(struct inode *,int); | 148 | extern int nfs_write_inode(struct inode *,int); |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 607f6eb9cdb5..af4d0f1e402c 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | static void nfs_expire_automounts(struct work_struct *work); | 21 | static void nfs_expire_automounts(struct work_struct *work); |
22 | 22 | ||
23 | LIST_HEAD(nfs_automount_list); | 23 | static LIST_HEAD(nfs_automount_list); |
24 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); | 24 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); |
25 | int nfs_mountpoint_expiry_timeout = 500 * HZ; | 25 | int nfs_mountpoint_expiry_timeout = 500 * HZ; |
26 | 26 | ||
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1f7ea675e0c5..28bab67d1519 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -267,7 +267,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
267 | int status; | 267 | int status; |
268 | 268 | ||
269 | if ((status = ntohl(*p++))) | 269 | if ((status = ntohl(*p++))) |
270 | return -nfs_stat_to_errno(status); | 270 | return nfs_stat_to_errno(status); |
271 | p = xdr_decode_fattr(p, res->fattr); | 271 | p = xdr_decode_fattr(p, res->fattr); |
272 | 272 | ||
273 | count = ntohl(*p++); | 273 | count = ntohl(*p++); |
@@ -428,11 +428,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
428 | size_t hdrlen; | 428 | size_t hdrlen; |
429 | unsigned int pglen, recvd; | 429 | unsigned int pglen, recvd; |
430 | u32 len; | 430 | u32 len; |
431 | int status, nr; | 431 | int status, nr = 0; |
432 | __be32 *end, *entry, *kaddr; | 432 | __be32 *end, *entry, *kaddr; |
433 | 433 | ||
434 | if ((status = ntohl(*p++))) | 434 | if ((status = ntohl(*p++))) |
435 | return -nfs_stat_to_errno(status); | 435 | return nfs_stat_to_errno(status); |
436 | 436 | ||
437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
438 | if (iov->iov_len < hdrlen) { | 438 | if (iov->iov_len < hdrlen) { |
@@ -452,7 +452,12 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
452 | kaddr = p = kmap_atomic(*page, KM_USER0); | 452 | kaddr = p = kmap_atomic(*page, KM_USER0); |
453 | end = (__be32 *)((char *)p + pglen); | 453 | end = (__be32 *)((char *)p + pglen); |
454 | entry = p; | 454 | entry = p; |
455 | for (nr = 0; *p++; nr++) { | 455 | |
456 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
457 | if ((entry + 1) > end) | ||
458 | goto short_pkt; | ||
459 | |||
460 | for (; *p++; nr++) { | ||
456 | if (p + 2 > end) | 461 | if (p + 2 > end) |
457 | goto short_pkt; | 462 | goto short_pkt; |
458 | p++; /* fileid */ | 463 | p++; /* fileid */ |
@@ -467,18 +472,32 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
467 | goto short_pkt; | 472 | goto short_pkt; |
468 | entry = p; | 473 | entry = p; |
469 | } | 474 | } |
470 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 475 | |
471 | goto short_pkt; | 476 | /* |
477 | * Apparently some server sends responses that are a valid size, but | ||
478 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
479 | * those, just set the EOF marker. | ||
480 | */ | ||
481 | if (!nr && entry[1] == 0) { | ||
482 | dprintk("NFS: readdir reply truncated!\n"); | ||
483 | entry[1] = 1; | ||
484 | } | ||
472 | out: | 485 | out: |
473 | kunmap_atomic(kaddr, KM_USER0); | 486 | kunmap_atomic(kaddr, KM_USER0); |
474 | return nr; | 487 | return nr; |
475 | short_pkt: | 488 | short_pkt: |
489 | /* | ||
490 | * When we get a short packet there are 2 possibilities. We can | ||
491 | * return an error, or fix up the response to look like a valid | ||
492 | * response and return what we have so far. If there are no | ||
493 | * entries and the packet was short, then return -EIO. If there | ||
494 | * are valid entries in the response, return them and pretend that | ||
495 | * the call was successful, but incomplete. The caller can retry the | ||
496 | * readdir starting at the last cookie. | ||
497 | */ | ||
476 | entry[0] = entry[1] = 0; | 498 | entry[0] = entry[1] = 0; |
477 | /* truncate listing ? */ | 499 | if (!nr) |
478 | if (!nr) { | 500 | nr = -errno_NFSERR_IO; |
479 | dprintk("NFS: readdir reply truncated!\n"); | ||
480 | entry[1] = 1; | ||
481 | } | ||
482 | goto out; | 501 | goto out; |
483 | err_unmap: | 502 | err_unmap: |
484 | nr = -errno_NFSERR_IO; | 503 | nr = -errno_NFSERR_IO; |
@@ -518,7 +537,7 @@ nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
518 | int status; | 537 | int status; |
519 | 538 | ||
520 | if ((status = ntohl(*p++)) != 0) | 539 | if ((status = ntohl(*p++)) != 0) |
521 | status = -nfs_stat_to_errno(status); | 540 | status = nfs_stat_to_errno(status); |
522 | return status; | 541 | return status; |
523 | } | 542 | } |
524 | 543 | ||
@@ -532,7 +551,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
532 | int status; | 551 | int status; |
533 | 552 | ||
534 | if ((status = ntohl(*p++))) | 553 | if ((status = ntohl(*p++))) |
535 | return -nfs_stat_to_errno(status); | 554 | return nfs_stat_to_errno(status); |
536 | xdr_decode_fattr(p, fattr); | 555 | xdr_decode_fattr(p, fattr); |
537 | return 0; | 556 | return 0; |
538 | } | 557 | } |
@@ -547,7 +566,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |||
547 | int status; | 566 | int status; |
548 | 567 | ||
549 | if ((status = ntohl(*p++))) | 568 | if ((status = ntohl(*p++))) |
550 | return -nfs_stat_to_errno(status); | 569 | return nfs_stat_to_errno(status); |
551 | p = xdr_decode_fhandle(p, res->fh); | 570 | p = xdr_decode_fhandle(p, res->fh); |
552 | xdr_decode_fattr(p, res->fattr); | 571 | xdr_decode_fattr(p, res->fattr); |
553 | return 0; | 572 | return 0; |
@@ -585,7 +604,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
585 | int status; | 604 | int status; |
586 | 605 | ||
587 | if ((status = ntohl(*p++))) | 606 | if ((status = ntohl(*p++))) |
588 | return -nfs_stat_to_errno(status); | 607 | return nfs_stat_to_errno(status); |
589 | /* Convert length of symlink */ | 608 | /* Convert length of symlink */ |
590 | len = ntohl(*p++); | 609 | len = ntohl(*p++); |
591 | if (len >= rcvbuf->page_len) { | 610 | if (len >= rcvbuf->page_len) { |
@@ -634,7 +653,7 @@ nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res) | |||
634 | int status; | 653 | int status; |
635 | 654 | ||
636 | if ((status = ntohl(*p++))) | 655 | if ((status = ntohl(*p++))) |
637 | return -nfs_stat_to_errno(status); | 656 | return nfs_stat_to_errno(status); |
638 | 657 | ||
639 | res->tsize = ntohl(*p++); | 658 | res->tsize = ntohl(*p++); |
640 | res->bsize = ntohl(*p++); | 659 | res->bsize = ntohl(*p++); |
@@ -653,39 +672,39 @@ static struct { | |||
653 | int errno; | 672 | int errno; |
654 | } nfs_errtbl[] = { | 673 | } nfs_errtbl[] = { |
655 | { NFS_OK, 0 }, | 674 | { NFS_OK, 0 }, |
656 | { NFSERR_PERM, EPERM }, | 675 | { NFSERR_PERM, -EPERM }, |
657 | { NFSERR_NOENT, ENOENT }, | 676 | { NFSERR_NOENT, -ENOENT }, |
658 | { NFSERR_IO, errno_NFSERR_IO }, | 677 | { NFSERR_IO, -errno_NFSERR_IO}, |
659 | { NFSERR_NXIO, ENXIO }, | 678 | { NFSERR_NXIO, -ENXIO }, |
660 | /* { NFSERR_EAGAIN, EAGAIN }, */ | 679 | /* { NFSERR_EAGAIN, -EAGAIN }, */ |
661 | { NFSERR_ACCES, EACCES }, | 680 | { NFSERR_ACCES, -EACCES }, |
662 | { NFSERR_EXIST, EEXIST }, | 681 | { NFSERR_EXIST, -EEXIST }, |
663 | { NFSERR_XDEV, EXDEV }, | 682 | { NFSERR_XDEV, -EXDEV }, |
664 | { NFSERR_NODEV, ENODEV }, | 683 | { NFSERR_NODEV, -ENODEV }, |
665 | { NFSERR_NOTDIR, ENOTDIR }, | 684 | { NFSERR_NOTDIR, -ENOTDIR }, |
666 | { NFSERR_ISDIR, EISDIR }, | 685 | { NFSERR_ISDIR, -EISDIR }, |
667 | { NFSERR_INVAL, EINVAL }, | 686 | { NFSERR_INVAL, -EINVAL }, |
668 | { NFSERR_FBIG, EFBIG }, | 687 | { NFSERR_FBIG, -EFBIG }, |
669 | { NFSERR_NOSPC, ENOSPC }, | 688 | { NFSERR_NOSPC, -ENOSPC }, |
670 | { NFSERR_ROFS, EROFS }, | 689 | { NFSERR_ROFS, -EROFS }, |
671 | { NFSERR_MLINK, EMLINK }, | 690 | { NFSERR_MLINK, -EMLINK }, |
672 | { NFSERR_NAMETOOLONG, ENAMETOOLONG }, | 691 | { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, |
673 | { NFSERR_NOTEMPTY, ENOTEMPTY }, | 692 | { NFSERR_NOTEMPTY, -ENOTEMPTY }, |
674 | { NFSERR_DQUOT, EDQUOT }, | 693 | { NFSERR_DQUOT, -EDQUOT }, |
675 | { NFSERR_STALE, ESTALE }, | 694 | { NFSERR_STALE, -ESTALE }, |
676 | { NFSERR_REMOTE, EREMOTE }, | 695 | { NFSERR_REMOTE, -EREMOTE }, |
677 | #ifdef EWFLUSH | 696 | #ifdef EWFLUSH |
678 | { NFSERR_WFLUSH, EWFLUSH }, | 697 | { NFSERR_WFLUSH, -EWFLUSH }, |
679 | #endif | 698 | #endif |
680 | { NFSERR_BADHANDLE, EBADHANDLE }, | 699 | { NFSERR_BADHANDLE, -EBADHANDLE }, |
681 | { NFSERR_NOT_SYNC, ENOTSYNC }, | 700 | { NFSERR_NOT_SYNC, -ENOTSYNC }, |
682 | { NFSERR_BAD_COOKIE, EBADCOOKIE }, | 701 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, |
683 | { NFSERR_NOTSUPP, ENOTSUPP }, | 702 | { NFSERR_NOTSUPP, -ENOTSUPP }, |
684 | { NFSERR_TOOSMALL, ETOOSMALL }, | 703 | { NFSERR_TOOSMALL, -ETOOSMALL }, |
685 | { NFSERR_SERVERFAULT, ESERVERFAULT }, | 704 | { NFSERR_SERVERFAULT, -ESERVERFAULT }, |
686 | { NFSERR_BADTYPE, EBADTYPE }, | 705 | { NFSERR_BADTYPE, -EBADTYPE }, |
687 | { NFSERR_JUKEBOX, EJUKEBOX }, | 706 | { NFSERR_JUKEBOX, -EJUKEBOX }, |
688 | { -1, EIO } | 707 | { -1, -EIO } |
689 | }; | 708 | }; |
690 | 709 | ||
691 | /* | 710 | /* |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 3917e2fa4e40..11cdddec1432 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -508,14 +508,14 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
508 | struct page **page; | 508 | struct page **page; |
509 | size_t hdrlen; | 509 | size_t hdrlen; |
510 | u32 len, recvd, pglen; | 510 | u32 len, recvd, pglen; |
511 | int status, nr; | 511 | int status, nr = 0; |
512 | __be32 *entry, *end, *kaddr; | 512 | __be32 *entry, *end, *kaddr; |
513 | 513 | ||
514 | status = ntohl(*p++); | 514 | status = ntohl(*p++); |
515 | /* Decode post_op_attrs */ | 515 | /* Decode post_op_attrs */ |
516 | p = xdr_decode_post_op_attr(p, res->dir_attr); | 516 | p = xdr_decode_post_op_attr(p, res->dir_attr); |
517 | if (status) | 517 | if (status) |
518 | return -nfs_stat_to_errno(status); | 518 | return nfs_stat_to_errno(status); |
519 | /* Decode verifier cookie */ | 519 | /* Decode verifier cookie */ |
520 | if (res->verf) { | 520 | if (res->verf) { |
521 | res->verf[0] = *p++; | 521 | res->verf[0] = *p++; |
@@ -542,7 +542,12 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
542 | kaddr = p = kmap_atomic(*page, KM_USER0); | 542 | kaddr = p = kmap_atomic(*page, KM_USER0); |
543 | end = (__be32 *)((char *)p + pglen); | 543 | end = (__be32 *)((char *)p + pglen); |
544 | entry = p; | 544 | entry = p; |
545 | for (nr = 0; *p++; nr++) { | 545 | |
546 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
547 | if ((entry + 1) > end) | ||
548 | goto short_pkt; | ||
549 | |||
550 | for (; *p++; nr++) { | ||
546 | if (p + 3 > end) | 551 | if (p + 3 > end) |
547 | goto short_pkt; | 552 | goto short_pkt; |
548 | p += 2; /* inode # */ | 553 | p += 2; /* inode # */ |
@@ -581,18 +586,32 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
581 | goto short_pkt; | 586 | goto short_pkt; |
582 | entry = p; | 587 | entry = p; |
583 | } | 588 | } |
584 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 589 | |
585 | goto short_pkt; | 590 | /* |
591 | * Apparently some server sends responses that are a valid size, but | ||
592 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
593 | * those, just set the EOF marker. | ||
594 | */ | ||
595 | if (!nr && entry[1] == 0) { | ||
596 | dprintk("NFS: readdir reply truncated!\n"); | ||
597 | entry[1] = 1; | ||
598 | } | ||
586 | out: | 599 | out: |
587 | kunmap_atomic(kaddr, KM_USER0); | 600 | kunmap_atomic(kaddr, KM_USER0); |
588 | return nr; | 601 | return nr; |
589 | short_pkt: | 602 | short_pkt: |
603 | /* | ||
604 | * When we get a short packet there are 2 possibilities. We can | ||
605 | * return an error, or fix up the response to look like a valid | ||
606 | * response and return what we have so far. If there are no | ||
607 | * entries and the packet was short, then return -EIO. If there | ||
608 | * are valid entries in the response, return them and pretend that | ||
609 | * the call was successful, but incomplete. The caller can retry the | ||
610 | * readdir starting at the last cookie. | ||
611 | */ | ||
590 | entry[0] = entry[1] = 0; | 612 | entry[0] = entry[1] = 0; |
591 | /* truncate listing ? */ | 613 | if (!nr) |
592 | if (!nr) { | 614 | nr = -errno_NFSERR_IO; |
593 | dprintk("NFS: readdir reply truncated!\n"); | ||
594 | entry[1] = 1; | ||
595 | } | ||
596 | goto out; | 615 | goto out; |
597 | err_unmap: | 616 | err_unmap: |
598 | nr = -errno_NFSERR_IO; | 617 | nr = -errno_NFSERR_IO; |
@@ -732,7 +751,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
732 | int status; | 751 | int status; |
733 | 752 | ||
734 | if ((status = ntohl(*p++))) | 753 | if ((status = ntohl(*p++))) |
735 | return -nfs_stat_to_errno(status); | 754 | return nfs_stat_to_errno(status); |
736 | xdr_decode_fattr(p, fattr); | 755 | xdr_decode_fattr(p, fattr); |
737 | return 0; | 756 | return 0; |
738 | } | 757 | } |
@@ -747,7 +766,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
747 | int status; | 766 | int status; |
748 | 767 | ||
749 | if ((status = ntohl(*p++))) | 768 | if ((status = ntohl(*p++))) |
750 | status = -nfs_stat_to_errno(status); | 769 | status = nfs_stat_to_errno(status); |
751 | xdr_decode_wcc_data(p, fattr); | 770 | xdr_decode_wcc_data(p, fattr); |
752 | return status; | 771 | return status; |
753 | } | 772 | } |
@@ -767,7 +786,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) | |||
767 | int status; | 786 | int status; |
768 | 787 | ||
769 | if ((status = ntohl(*p++))) { | 788 | if ((status = ntohl(*p++))) { |
770 | status = -nfs_stat_to_errno(status); | 789 | status = nfs_stat_to_errno(status); |
771 | } else { | 790 | } else { |
772 | if (!(p = xdr_decode_fhandle(p, res->fh))) | 791 | if (!(p = xdr_decode_fhandle(p, res->fh))) |
773 | return -errno_NFSERR_IO; | 792 | return -errno_NFSERR_IO; |
@@ -787,7 +806,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) | |||
787 | 806 | ||
788 | p = xdr_decode_post_op_attr(p, res->fattr); | 807 | p = xdr_decode_post_op_attr(p, res->fattr); |
789 | if (status) | 808 | if (status) |
790 | return -nfs_stat_to_errno(status); | 809 | return nfs_stat_to_errno(status); |
791 | res->access = ntohl(*p++); | 810 | res->access = ntohl(*p++); |
792 | return 0; | 811 | return 0; |
793 | } | 812 | } |
@@ -824,7 +843,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
824 | p = xdr_decode_post_op_attr(p, fattr); | 843 | p = xdr_decode_post_op_attr(p, fattr); |
825 | 844 | ||
826 | if (status != 0) | 845 | if (status != 0) |
827 | return -nfs_stat_to_errno(status); | 846 | return nfs_stat_to_errno(status); |
828 | 847 | ||
829 | /* Convert length of symlink */ | 848 | /* Convert length of symlink */ |
830 | len = ntohl(*p++); | 849 | len = ntohl(*p++); |
@@ -872,7 +891,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
872 | p = xdr_decode_post_op_attr(p, res->fattr); | 891 | p = xdr_decode_post_op_attr(p, res->fattr); |
873 | 892 | ||
874 | if (status != 0) | 893 | if (status != 0) |
875 | return -nfs_stat_to_errno(status); | 894 | return nfs_stat_to_errno(status); |
876 | 895 | ||
877 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant | 896 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant |
878 | * in that it puts the count both in the res struct and in the | 897 | * in that it puts the count both in the res struct and in the |
@@ -922,7 +941,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) | |||
922 | p = xdr_decode_wcc_data(p, res->fattr); | 941 | p = xdr_decode_wcc_data(p, res->fattr); |
923 | 942 | ||
924 | if (status != 0) | 943 | if (status != 0) |
925 | return -nfs_stat_to_errno(status); | 944 | return nfs_stat_to_errno(status); |
926 | 945 | ||
927 | res->count = ntohl(*p++); | 946 | res->count = ntohl(*p++); |
928 | res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); | 947 | res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); |
@@ -953,7 +972,7 @@ nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) | |||
953 | res->fattr->valid = 0; | 972 | res->fattr->valid = 0; |
954 | } | 973 | } |
955 | } else { | 974 | } else { |
956 | status = -nfs_stat_to_errno(status); | 975 | status = nfs_stat_to_errno(status); |
957 | } | 976 | } |
958 | p = xdr_decode_wcc_data(p, res->dir_attr); | 977 | p = xdr_decode_wcc_data(p, res->dir_attr); |
959 | return status; | 978 | return status; |
@@ -968,7 +987,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res) | |||
968 | int status; | 987 | int status; |
969 | 988 | ||
970 | if ((status = ntohl(*p++)) != 0) | 989 | if ((status = ntohl(*p++)) != 0) |
971 | status = -nfs_stat_to_errno(status); | 990 | status = nfs_stat_to_errno(status); |
972 | p = xdr_decode_wcc_data(p, res->fromattr); | 991 | p = xdr_decode_wcc_data(p, res->fromattr); |
973 | p = xdr_decode_wcc_data(p, res->toattr); | 992 | p = xdr_decode_wcc_data(p, res->toattr); |
974 | return status; | 993 | return status; |
@@ -983,7 +1002,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) | |||
983 | int status; | 1002 | int status; |
984 | 1003 | ||
985 | if ((status = ntohl(*p++)) != 0) | 1004 | if ((status = ntohl(*p++)) != 0) |
986 | status = -nfs_stat_to_errno(status); | 1005 | status = nfs_stat_to_errno(status); |
987 | p = xdr_decode_post_op_attr(p, res->fattr); | 1006 | p = xdr_decode_post_op_attr(p, res->fattr); |
988 | p = xdr_decode_wcc_data(p, res->dir_attr); | 1007 | p = xdr_decode_wcc_data(p, res->dir_attr); |
989 | return status; | 1008 | return status; |
@@ -1001,7 +1020,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) | |||
1001 | 1020 | ||
1002 | p = xdr_decode_post_op_attr(p, res->fattr); | 1021 | p = xdr_decode_post_op_attr(p, res->fattr); |
1003 | if (status != 0) | 1022 | if (status != 0) |
1004 | return -nfs_stat_to_errno(status); | 1023 | return nfs_stat_to_errno(status); |
1005 | 1024 | ||
1006 | p = xdr_decode_hyper(p, &res->tbytes); | 1025 | p = xdr_decode_hyper(p, &res->tbytes); |
1007 | p = xdr_decode_hyper(p, &res->fbytes); | 1026 | p = xdr_decode_hyper(p, &res->fbytes); |
@@ -1026,7 +1045,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) | |||
1026 | 1045 | ||
1027 | p = xdr_decode_post_op_attr(p, res->fattr); | 1046 | p = xdr_decode_post_op_attr(p, res->fattr); |
1028 | if (status != 0) | 1047 | if (status != 0) |
1029 | return -nfs_stat_to_errno(status); | 1048 | return nfs_stat_to_errno(status); |
1030 | 1049 | ||
1031 | res->rtmax = ntohl(*p++); | 1050 | res->rtmax = ntohl(*p++); |
1032 | res->rtpref = ntohl(*p++); | 1051 | res->rtpref = ntohl(*p++); |
@@ -1054,7 +1073,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) | |||
1054 | 1073 | ||
1055 | p = xdr_decode_post_op_attr(p, res->fattr); | 1074 | p = xdr_decode_post_op_attr(p, res->fattr); |
1056 | if (status != 0) | 1075 | if (status != 0) |
1057 | return -nfs_stat_to_errno(status); | 1076 | return nfs_stat_to_errno(status); |
1058 | res->max_link = ntohl(*p++); | 1077 | res->max_link = ntohl(*p++); |
1059 | res->max_namelen = ntohl(*p++); | 1078 | res->max_namelen = ntohl(*p++); |
1060 | 1079 | ||
@@ -1073,7 +1092,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) | |||
1073 | status = ntohl(*p++); | 1092 | status = ntohl(*p++); |
1074 | p = xdr_decode_wcc_data(p, res->fattr); | 1093 | p = xdr_decode_wcc_data(p, res->fattr); |
1075 | if (status != 0) | 1094 | if (status != 0) |
1076 | return -nfs_stat_to_errno(status); | 1095 | return nfs_stat_to_errno(status); |
1077 | 1096 | ||
1078 | res->verf->verifier[0] = *p++; | 1097 | res->verf->verifier[0] = *p++; |
1079 | res->verf->verifier[1] = *p++; | 1098 | res->verf->verifier[1] = *p++; |
@@ -1095,7 +1114,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, | |||
1095 | int err, base; | 1114 | int err, base; |
1096 | 1115 | ||
1097 | if (status != 0) | 1116 | if (status != 0) |
1098 | return -nfs_stat_to_errno(status); | 1117 | return nfs_stat_to_errno(status); |
1099 | p = xdr_decode_post_op_attr(p, res->fattr); | 1118 | p = xdr_decode_post_op_attr(p, res->fattr); |
1100 | res->mask = ntohl(*p++); | 1119 | res->mask = ntohl(*p++); |
1101 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | 1120 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) |
@@ -1122,7 +1141,7 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
1122 | int status = ntohl(*p++); | 1141 | int status = ntohl(*p++); |
1123 | 1142 | ||
1124 | if (status) | 1143 | if (status) |
1125 | return -nfs_stat_to_errno(status); | 1144 | return nfs_stat_to_errno(status); |
1126 | xdr_decode_post_op_attr(p, fattr); | 1145 | xdr_decode_post_op_attr(p, fattr); |
1127 | return 0; | 1146 | return 0; |
1128 | } | 1147 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ce07862c2fb..dbc09271af02 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -51,6 +51,7 @@ | |||
51 | 51 | ||
52 | #include "nfs4_fs.h" | 52 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 53 | #include "delegation.h" |
54 | #include "internal.h" | ||
54 | #include "iostat.h" | 55 | #include "iostat.h" |
55 | 56 | ||
56 | #define NFSDBG_FACILITY NFSDBG_PROC | 57 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -239,6 +240,8 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
239 | { | 240 | { |
240 | p->o_res.f_attr = &p->f_attr; | 241 | p->o_res.f_attr = &p->f_attr; |
241 | p->o_res.dir_attr = &p->dir_attr; | 242 | p->o_res.dir_attr = &p->dir_attr; |
243 | p->o_res.seqid = p->o_arg.seqid; | ||
244 | p->c_res.seqid = p->c_arg.seqid; | ||
242 | p->o_res.server = p->o_arg.server; | 245 | p->o_res.server = p->o_arg.server; |
243 | nfs_fattr_init(&p->f_attr); | 246 | nfs_fattr_init(&p->f_attr); |
244 | nfs_fattr_init(&p->dir_attr); | 247 | nfs_fattr_init(&p->dir_attr); |
@@ -729,7 +732,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
729 | renew_lease(data->o_res.server, data->timestamp); | 732 | renew_lease(data->o_res.server, data->timestamp); |
730 | data->rpc_done = 1; | 733 | data->rpc_done = 1; |
731 | } | 734 | } |
732 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
733 | } | 735 | } |
734 | 736 | ||
735 | static void nfs4_open_confirm_release(void *calldata) | 737 | static void nfs4_open_confirm_release(void *calldata) |
@@ -773,6 +775,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
773 | .rpc_message = &msg, | 775 | .rpc_message = &msg, |
774 | .callback_ops = &nfs4_open_confirm_ops, | 776 | .callback_ops = &nfs4_open_confirm_ops, |
775 | .callback_data = data, | 777 | .callback_data = data, |
778 | .workqueue = nfsiod_workqueue, | ||
776 | .flags = RPC_TASK_ASYNC, | 779 | .flags = RPC_TASK_ASYNC, |
777 | }; | 780 | }; |
778 | int status; | 781 | int status; |
@@ -858,7 +861,6 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
858 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) | 861 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) |
859 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 862 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
860 | } | 863 | } |
861 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | ||
862 | data->rpc_done = 1; | 864 | data->rpc_done = 1; |
863 | } | 865 | } |
864 | 866 | ||
@@ -910,6 +912,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
910 | .rpc_message = &msg, | 912 | .rpc_message = &msg, |
911 | .callback_ops = &nfs4_open_ops, | 913 | .callback_ops = &nfs4_open_ops, |
912 | .callback_data = data, | 914 | .callback_data = data, |
915 | .workqueue = nfsiod_workqueue, | ||
913 | .flags = RPC_TASK_ASYNC, | 916 | .flags = RPC_TASK_ASYNC, |
914 | }; | 917 | }; |
915 | int status; | 918 | int status; |
@@ -979,11 +982,8 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
979 | if (IS_ERR(opendata)) | 982 | if (IS_ERR(opendata)) |
980 | return PTR_ERR(opendata); | 983 | return PTR_ERR(opendata); |
981 | ret = nfs4_open_recover(opendata, state); | 984 | ret = nfs4_open_recover(opendata, state); |
982 | if (ret == -ESTALE) { | 985 | if (ret == -ESTALE) |
983 | /* Invalidate the state owner so we don't ever use it again */ | ||
984 | nfs4_drop_state_owner(state->owner); | ||
985 | d_drop(ctx->path.dentry); | 986 | d_drop(ctx->path.dentry); |
986 | } | ||
987 | nfs4_opendata_put(opendata); | 987 | nfs4_opendata_put(opendata); |
988 | return ret; | 988 | return ret; |
989 | } | 989 | } |
@@ -1226,7 +1226,6 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1226 | /* hmm. we are done with the inode, and in the process of freeing | 1226 | /* hmm. we are done with the inode, and in the process of freeing |
1227 | * the state_owner. we keep this around to process errors | 1227 | * the state_owner. we keep this around to process errors |
1228 | */ | 1228 | */ |
1229 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | ||
1230 | switch (task->tk_status) { | 1229 | switch (task->tk_status) { |
1231 | case 0: | 1230 | case 0: |
1232 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1231 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
@@ -1315,6 +1314,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1315 | .rpc_client = server->client, | 1314 | .rpc_client = server->client, |
1316 | .rpc_message = &msg, | 1315 | .rpc_message = &msg, |
1317 | .callback_ops = &nfs4_close_ops, | 1316 | .callback_ops = &nfs4_close_ops, |
1317 | .workqueue = nfsiod_workqueue, | ||
1318 | .flags = RPC_TASK_ASYNC, | 1318 | .flags = RPC_TASK_ASYNC, |
1319 | }; | 1319 | }; |
1320 | int status = -ENOMEM; | 1320 | int status = -ENOMEM; |
@@ -1332,6 +1332,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1332 | goto out_free_calldata; | 1332 | goto out_free_calldata; |
1333 | calldata->arg.bitmask = server->attr_bitmask; | 1333 | calldata->arg.bitmask = server->attr_bitmask; |
1334 | calldata->res.fattr = &calldata->fattr; | 1334 | calldata->res.fattr = &calldata->fattr; |
1335 | calldata->res.seqid = calldata->arg.seqid; | ||
1335 | calldata->res.server = server; | 1336 | calldata->res.server = server; |
1336 | calldata->path.mnt = mntget(path->mnt); | 1337 | calldata->path.mnt = mntget(path->mnt); |
1337 | calldata->path.dentry = dget(path->dentry); | 1338 | calldata->path.dentry = dget(path->dentry); |
@@ -1404,7 +1405,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1404 | BUG_ON(nd->intent.open.flags & O_CREAT); | 1405 | BUG_ON(nd->intent.open.flags & O_CREAT); |
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1408 | cred = rpc_lookup_cred(); |
1408 | if (IS_ERR(cred)) | 1409 | if (IS_ERR(cred)) |
1409 | return (struct dentry *)cred; | 1410 | return (struct dentry *)cred; |
1410 | parent = dentry->d_parent; | 1411 | parent = dentry->d_parent; |
@@ -1439,7 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1439 | struct rpc_cred *cred; | 1440 | struct rpc_cred *cred; |
1440 | struct nfs4_state *state; | 1441 | struct nfs4_state *state; |
1441 | 1442 | ||
1442 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1443 | cred = rpc_lookup_cred(); |
1443 | if (IS_ERR(cred)) | 1444 | if (IS_ERR(cred)) |
1444 | return PTR_ERR(cred); | 1445 | return PTR_ERR(cred); |
1445 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); | 1446 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); |
@@ -1656,7 +1657,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1656 | 1657 | ||
1657 | nfs_fattr_init(fattr); | 1658 | nfs_fattr_init(fattr); |
1658 | 1659 | ||
1659 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1660 | cred = rpc_lookup_cred(); |
1660 | if (IS_ERR(cred)) | 1661 | if (IS_ERR(cred)) |
1661 | return PTR_ERR(cred); | 1662 | return PTR_ERR(cred); |
1662 | 1663 | ||
@@ -1892,7 +1893,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1892 | struct rpc_cred *cred; | 1893 | struct rpc_cred *cred; |
1893 | int status = 0; | 1894 | int status = 0; |
1894 | 1895 | ||
1895 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1896 | cred = rpc_lookup_cred(); |
1896 | if (IS_ERR(cred)) { | 1897 | if (IS_ERR(cred)) { |
1897 | status = PTR_ERR(cred); | 1898 | status = PTR_ERR(cred); |
1898 | goto out; | 1899 | goto out; |
@@ -2761,10 +2762,10 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2761 | case -NFS4ERR_STALE_CLIENTID: | 2762 | case -NFS4ERR_STALE_CLIENTID: |
2762 | case -NFS4ERR_STALE_STATEID: | 2763 | case -NFS4ERR_STALE_STATEID: |
2763 | case -NFS4ERR_EXPIRED: | 2764 | case -NFS4ERR_EXPIRED: |
2764 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); | 2765 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
2765 | nfs4_schedule_state_recovery(clp); | 2766 | nfs4_schedule_state_recovery(clp); |
2766 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) | 2767 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) |
2767 | rpc_wake_up_task(task); | 2768 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2768 | task->tk_status = 0; | 2769 | task->tk_status = 0; |
2769 | return -EAGAIN; | 2770 | return -EAGAIN; |
2770 | case -NFS4ERR_DELAY: | 2771 | case -NFS4ERR_DELAY: |
@@ -2884,7 +2885,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
2884 | RPC_DISPLAY_ADDR), | 2885 | RPC_DISPLAY_ADDR), |
2885 | rpc_peeraddr2str(clp->cl_rpcclient, | 2886 | rpc_peeraddr2str(clp->cl_rpcclient, |
2886 | RPC_DISPLAY_PROTO), | 2887 | RPC_DISPLAY_PROTO), |
2887 | cred->cr_ops->cr_name, | 2888 | clp->cl_rpcclient->cl_auth->au_ops->au_name, |
2888 | clp->cl_id_uniquifier); | 2889 | clp->cl_id_uniquifier); |
2889 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2890 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
2890 | sizeof(setclientid.sc_netid), | 2891 | sizeof(setclientid.sc_netid), |
@@ -3158,6 +3159,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3158 | p->arg.fh = NFS_FH(inode); | 3159 | p->arg.fh = NFS_FH(inode); |
3159 | p->arg.fl = &p->fl; | 3160 | p->arg.fl = &p->fl; |
3160 | p->arg.seqid = seqid; | 3161 | p->arg.seqid = seqid; |
3162 | p->res.seqid = seqid; | ||
3161 | p->arg.stateid = &lsp->ls_stateid; | 3163 | p->arg.stateid = &lsp->ls_stateid; |
3162 | p->lsp = lsp; | 3164 | p->lsp = lsp; |
3163 | atomic_inc(&lsp->ls_count); | 3165 | atomic_inc(&lsp->ls_count); |
@@ -3183,7 +3185,6 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3183 | 3185 | ||
3184 | if (RPC_ASSASSINATED(task)) | 3186 | if (RPC_ASSASSINATED(task)) |
3185 | return; | 3187 | return; |
3186 | nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid); | ||
3187 | switch (task->tk_status) { | 3188 | switch (task->tk_status) { |
3188 | case 0: | 3189 | case 0: |
3189 | memcpy(calldata->lsp->ls_stateid.data, | 3190 | memcpy(calldata->lsp->ls_stateid.data, |
@@ -3235,6 +3236,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3235 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), | 3236 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), |
3236 | .rpc_message = &msg, | 3237 | .rpc_message = &msg, |
3237 | .callback_ops = &nfs4_locku_ops, | 3238 | .callback_ops = &nfs4_locku_ops, |
3239 | .workqueue = nfsiod_workqueue, | ||
3238 | .flags = RPC_TASK_ASYNC, | 3240 | .flags = RPC_TASK_ASYNC, |
3239 | }; | 3241 | }; |
3240 | 3242 | ||
@@ -3261,6 +3263,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3261 | struct nfs4_lock_state *lsp; | 3263 | struct nfs4_lock_state *lsp; |
3262 | struct rpc_task *task; | 3264 | struct rpc_task *task; |
3263 | int status = 0; | 3265 | int status = 0; |
3266 | unsigned char fl_flags = request->fl_flags; | ||
3264 | 3267 | ||
3265 | status = nfs4_set_lock_state(state, request); | 3268 | status = nfs4_set_lock_state(state, request); |
3266 | /* Unlock _before_ we do the RPC call */ | 3269 | /* Unlock _before_ we do the RPC call */ |
@@ -3284,6 +3287,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3284 | status = nfs4_wait_for_completion_rpc_task(task); | 3287 | status = nfs4_wait_for_completion_rpc_task(task); |
3285 | rpc_put_task(task); | 3288 | rpc_put_task(task); |
3286 | out: | 3289 | out: |
3290 | request->fl_flags = fl_flags; | ||
3287 | return status; | 3291 | return status; |
3288 | } | 3292 | } |
3289 | 3293 | ||
@@ -3320,6 +3324,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3320 | p->arg.lock_stateid = &lsp->ls_stateid; | 3324 | p->arg.lock_stateid = &lsp->ls_stateid; |
3321 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3325 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3322 | p->arg.lock_owner.id = lsp->ls_id.id; | 3326 | p->arg.lock_owner.id = lsp->ls_id.id; |
3327 | p->res.lock_seqid = p->arg.lock_seqid; | ||
3323 | p->lsp = lsp; | 3328 | p->lsp = lsp; |
3324 | atomic_inc(&lsp->ls_count); | 3329 | atomic_inc(&lsp->ls_count); |
3325 | p->ctx = get_nfs_open_context(ctx); | 3330 | p->ctx = get_nfs_open_context(ctx); |
@@ -3346,6 +3351,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3346 | return; | 3351 | return; |
3347 | data->arg.open_stateid = &state->stateid; | 3352 | data->arg.open_stateid = &state->stateid; |
3348 | data->arg.new_lock_owner = 1; | 3353 | data->arg.new_lock_owner = 1; |
3354 | data->res.open_seqid = data->arg.open_seqid; | ||
3349 | } else | 3355 | } else |
3350 | data->arg.new_lock_owner = 0; | 3356 | data->arg.new_lock_owner = 0; |
3351 | data->timestamp = jiffies; | 3357 | data->timestamp = jiffies; |
@@ -3363,7 +3369,6 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3363 | if (RPC_ASSASSINATED(task)) | 3369 | if (RPC_ASSASSINATED(task)) |
3364 | goto out; | 3370 | goto out; |
3365 | if (data->arg.new_lock_owner != 0) { | 3371 | if (data->arg.new_lock_owner != 0) { |
3366 | nfs_increment_open_seqid(data->rpc_status, data->arg.open_seqid); | ||
3367 | if (data->rpc_status == 0) | 3372 | if (data->rpc_status == 0) |
3368 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | 3373 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); |
3369 | else | 3374 | else |
@@ -3375,7 +3380,6 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3375 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 3380 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
3376 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); | 3381 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); |
3377 | } | 3382 | } |
3378 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | ||
3379 | out: | 3383 | out: |
3380 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); | 3384 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); |
3381 | } | 3385 | } |
@@ -3419,6 +3423,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3419 | .rpc_client = NFS_CLIENT(state->inode), | 3423 | .rpc_client = NFS_CLIENT(state->inode), |
3420 | .rpc_message = &msg, | 3424 | .rpc_message = &msg, |
3421 | .callback_ops = &nfs4_lock_ops, | 3425 | .callback_ops = &nfs4_lock_ops, |
3426 | .workqueue = nfsiod_workqueue, | ||
3422 | .flags = RPC_TASK_ASYNC, | 3427 | .flags = RPC_TASK_ASYNC, |
3423 | }; | 3428 | }; |
3424 | int ret; | 3429 | int ret; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index b962397004c1..46eb624e4f16 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -71,6 +71,29 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
71 | return status; | 71 | return status; |
72 | } | 72 | } |
73 | 73 | ||
74 | static struct rpc_cred *nfs4_get_machine_cred(struct nfs_client *clp) | ||
75 | { | ||
76 | struct rpc_cred *cred = NULL; | ||
77 | |||
78 | spin_lock(&clp->cl_lock); | ||
79 | if (clp->cl_machine_cred != NULL) | ||
80 | cred = get_rpccred(clp->cl_machine_cred); | ||
81 | spin_unlock(&clp->cl_lock); | ||
82 | return cred; | ||
83 | } | ||
84 | |||
85 | static void nfs4_clear_machine_cred(struct nfs_client *clp) | ||
86 | { | ||
87 | struct rpc_cred *cred; | ||
88 | |||
89 | spin_lock(&clp->cl_lock); | ||
90 | cred = clp->cl_machine_cred; | ||
91 | clp->cl_machine_cred = NULL; | ||
92 | spin_unlock(&clp->cl_lock); | ||
93 | if (cred != NULL) | ||
94 | put_rpccred(cred); | ||
95 | } | ||
96 | |||
74 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 97 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) |
75 | { | 98 | { |
76 | struct nfs4_state_owner *sp; | 99 | struct nfs4_state_owner *sp; |
@@ -91,13 +114,18 @@ static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | |||
91 | { | 114 | { |
92 | struct nfs4_state_owner *sp; | 115 | struct nfs4_state_owner *sp; |
93 | struct rb_node *pos; | 116 | struct rb_node *pos; |
117 | struct rpc_cred *cred; | ||
94 | 118 | ||
119 | cred = nfs4_get_machine_cred(clp); | ||
120 | if (cred != NULL) | ||
121 | goto out; | ||
95 | pos = rb_first(&clp->cl_state_owners); | 122 | pos = rb_first(&clp->cl_state_owners); |
96 | if (pos != NULL) { | 123 | if (pos != NULL) { |
97 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 124 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
98 | return get_rpccred(sp->so_cred); | 125 | cred = get_rpccred(sp->so_cred); |
99 | } | 126 | } |
100 | return NULL; | 127 | out: |
128 | return cred; | ||
101 | } | 129 | } |
102 | 130 | ||
103 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, | 131 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, |
@@ -292,8 +320,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
292 | spin_unlock(&clp->cl_lock); | 320 | spin_unlock(&clp->cl_lock); |
293 | if (sp == new) | 321 | if (sp == new) |
294 | get_rpccred(cred); | 322 | get_rpccred(cred); |
295 | else | 323 | else { |
324 | rpc_destroy_wait_queue(&new->so_sequence.wait); | ||
296 | kfree(new); | 325 | kfree(new); |
326 | } | ||
297 | return sp; | 327 | return sp; |
298 | } | 328 | } |
299 | 329 | ||
@@ -310,6 +340,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) | |||
310 | return; | 340 | return; |
311 | nfs4_remove_state_owner(clp, sp); | 341 | nfs4_remove_state_owner(clp, sp); |
312 | spin_unlock(&clp->cl_lock); | 342 | spin_unlock(&clp->cl_lock); |
343 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | ||
313 | put_rpccred(cred); | 344 | put_rpccred(cred); |
314 | kfree(sp); | 345 | kfree(sp); |
315 | } | 346 | } |
@@ -529,6 +560,7 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |||
529 | spin_lock(&clp->cl_lock); | 560 | spin_lock(&clp->cl_lock); |
530 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | 561 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); |
531 | spin_unlock(&clp->cl_lock); | 562 | spin_unlock(&clp->cl_lock); |
563 | rpc_destroy_wait_queue(&lsp->ls_sequence.wait); | ||
532 | kfree(lsp); | 564 | kfree(lsp); |
533 | } | 565 | } |
534 | 566 | ||
@@ -731,7 +763,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | |||
731 | list_add_tail(&seqid->list, &sequence->list); | 763 | list_add_tail(&seqid->list, &sequence->list); |
732 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) | 764 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) |
733 | goto unlock; | 765 | goto unlock; |
734 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | 766 | rpc_sleep_on(&sequence->wait, task, NULL); |
735 | status = -EAGAIN; | 767 | status = -EAGAIN; |
736 | unlock: | 768 | unlock: |
737 | spin_unlock(&sequence->lock); | 769 | spin_unlock(&sequence->lock); |
@@ -920,10 +952,10 @@ restart_loop: | |||
920 | if (cred != NULL) { | 952 | if (cred != NULL) { |
921 | /* Yes there are: try to renew the old lease */ | 953 | /* Yes there are: try to renew the old lease */ |
922 | status = nfs4_proc_renew(clp, cred); | 954 | status = nfs4_proc_renew(clp, cred); |
955 | put_rpccred(cred); | ||
923 | switch (status) { | 956 | switch (status) { |
924 | case 0: | 957 | case 0: |
925 | case -NFS4ERR_CB_PATH_DOWN: | 958 | case -NFS4ERR_CB_PATH_DOWN: |
926 | put_rpccred(cred); | ||
927 | goto out; | 959 | goto out; |
928 | case -NFS4ERR_STALE_CLIENTID: | 960 | case -NFS4ERR_STALE_CLIENTID: |
929 | case -NFS4ERR_LEASE_MOVED: | 961 | case -NFS4ERR_LEASE_MOVED: |
@@ -932,14 +964,19 @@ restart_loop: | |||
932 | } else { | 964 | } else { |
933 | /* "reboot" to ensure we clear all state on the server */ | 965 | /* "reboot" to ensure we clear all state on the server */ |
934 | clp->cl_boot_time = CURRENT_TIME; | 966 | clp->cl_boot_time = CURRENT_TIME; |
935 | cred = nfs4_get_setclientid_cred(clp); | ||
936 | } | 967 | } |
937 | /* We're going to have to re-establish a clientid */ | 968 | /* We're going to have to re-establish a clientid */ |
938 | nfs4_state_mark_reclaim(clp); | 969 | nfs4_state_mark_reclaim(clp); |
939 | status = -ENOENT; | 970 | status = -ENOENT; |
971 | cred = nfs4_get_setclientid_cred(clp); | ||
940 | if (cred != NULL) { | 972 | if (cred != NULL) { |
941 | status = nfs4_init_client(clp, cred); | 973 | status = nfs4_init_client(clp, cred); |
942 | put_rpccred(cred); | 974 | put_rpccred(cred); |
975 | /* Handle case where the user hasn't set up machine creds */ | ||
976 | if (status == -EACCES && cred == clp->cl_machine_cred) { | ||
977 | nfs4_clear_machine_cred(clp); | ||
978 | goto restart_loop; | ||
979 | } | ||
943 | } | 980 | } |
944 | if (status) | 981 | if (status) |
945 | goto out_error; | 982 | goto out_error; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index db1ed9c46ede..5a2d64927b35 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -110,7 +110,7 @@ static int nfs4_stat_to_errno(int); | |||
110 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 110 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
111 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) | 111 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) |
112 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) | 112 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) |
113 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) | 113 | #define encode_fsinfo_maxsz (encode_getattr_maxsz) |
114 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) | 114 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) |
115 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) | 115 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) |
116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) | 116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) |
@@ -1191,8 +1191,8 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
1192 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1192 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1193 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1193 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1194 | dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", | 1194 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1195 | __FUNCTION__, | 1195 | __func__, |
1196 | (unsigned long long)readdir->cookie, | 1196 | (unsigned long long)readdir->cookie, |
1197 | ((u32 *)readdir->verifier.data)[0], | 1197 | ((u32 *)readdir->verifier.data)[0], |
1198 | ((u32 *)readdir->verifier.data)[1], | 1198 | ((u32 *)readdir->verifier.data)[1], |
@@ -2241,7 +2241,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
2241 | } | 2241 | } |
2242 | READ32(nfserr); | 2242 | READ32(nfserr); |
2243 | if (nfserr != NFS_OK) | 2243 | if (nfserr != NFS_OK) |
2244 | return -nfs4_stat_to_errno(nfserr); | 2244 | return nfs4_stat_to_errno(nfserr); |
2245 | return 0; | 2245 | return 0; |
2246 | } | 2246 | } |
2247 | 2247 | ||
@@ -2291,7 +2291,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3 | |||
2291 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; | 2291 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; |
2292 | } else | 2292 | } else |
2293 | bitmask[0] = bitmask[1] = 0; | 2293 | bitmask[0] = bitmask[1] = 0; |
2294 | dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]); | 2294 | dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]); |
2295 | return 0; | 2295 | return 0; |
2296 | } | 2296 | } |
2297 | 2297 | ||
@@ -3005,6 +3005,8 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | |||
3005 | int status; | 3005 | int status; |
3006 | 3006 | ||
3007 | status = decode_op_hdr(xdr, OP_CLOSE); | 3007 | status = decode_op_hdr(xdr, OP_CLOSE); |
3008 | if (status != -EIO) | ||
3009 | nfs_increment_open_seqid(status, res->seqid); | ||
3008 | if (status) | 3010 | if (status) |
3009 | return status; | 3011 | return status; |
3010 | READ_BUF(NFS4_STATEID_SIZE); | 3012 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3296,11 +3298,17 @@ static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) | |||
3296 | int status; | 3298 | int status; |
3297 | 3299 | ||
3298 | status = decode_op_hdr(xdr, OP_LOCK); | 3300 | status = decode_op_hdr(xdr, OP_LOCK); |
3301 | if (status == -EIO) | ||
3302 | goto out; | ||
3299 | if (status == 0) { | 3303 | if (status == 0) { |
3300 | READ_BUF(NFS4_STATEID_SIZE); | 3304 | READ_BUF(NFS4_STATEID_SIZE); |
3301 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3305 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
3302 | } else if (status == -NFS4ERR_DENIED) | 3306 | } else if (status == -NFS4ERR_DENIED) |
3303 | return decode_lock_denied(xdr, NULL); | 3307 | status = decode_lock_denied(xdr, NULL); |
3308 | if (res->open_seqid != NULL) | ||
3309 | nfs_increment_open_seqid(status, res->open_seqid); | ||
3310 | nfs_increment_lock_seqid(status, res->lock_seqid); | ||
3311 | out: | ||
3304 | return status; | 3312 | return status; |
3305 | } | 3313 | } |
3306 | 3314 | ||
@@ -3319,6 +3327,8 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) | |||
3319 | int status; | 3327 | int status; |
3320 | 3328 | ||
3321 | status = decode_op_hdr(xdr, OP_LOCKU); | 3329 | status = decode_op_hdr(xdr, OP_LOCKU); |
3330 | if (status != -EIO) | ||
3331 | nfs_increment_lock_seqid(status, res->seqid); | ||
3322 | if (status == 0) { | 3332 | if (status == 0) { |
3323 | READ_BUF(NFS4_STATEID_SIZE); | 3333 | READ_BUF(NFS4_STATEID_SIZE); |
3324 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3334 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
@@ -3384,6 +3394,8 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |||
3384 | int status; | 3394 | int status; |
3385 | 3395 | ||
3386 | status = decode_op_hdr(xdr, OP_OPEN); | 3396 | status = decode_op_hdr(xdr, OP_OPEN); |
3397 | if (status != -EIO) | ||
3398 | nfs_increment_open_seqid(status, res->seqid); | ||
3387 | if (status) | 3399 | if (status) |
3388 | return status; | 3400 | return status; |
3389 | READ_BUF(NFS4_STATEID_SIZE); | 3401 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3416,6 +3428,8 @@ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmre | |||
3416 | int status; | 3428 | int status; |
3417 | 3429 | ||
3418 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); | 3430 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); |
3431 | if (status != -EIO) | ||
3432 | nfs_increment_open_seqid(status, res->seqid); | ||
3419 | if (status) | 3433 | if (status) |
3420 | return status; | 3434 | return status; |
3421 | READ_BUF(NFS4_STATEID_SIZE); | 3435 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3429,6 +3443,8 @@ static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *re | |||
3429 | int status; | 3443 | int status; |
3430 | 3444 | ||
3431 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); | 3445 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); |
3446 | if (status != -EIO) | ||
3447 | nfs_increment_open_seqid(status, res->seqid); | ||
3432 | if (status) | 3448 | if (status) |
3433 | return status; | 3449 | return status; |
3434 | READ_BUF(NFS4_STATEID_SIZE); | 3450 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3481,7 +3497,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3481 | size_t hdrlen; | 3497 | size_t hdrlen; |
3482 | u32 recvd, pglen = rcvbuf->page_len; | 3498 | u32 recvd, pglen = rcvbuf->page_len; |
3483 | __be32 *end, *entry, *p, *kaddr; | 3499 | __be32 *end, *entry, *p, *kaddr; |
3484 | unsigned int nr; | 3500 | unsigned int nr = 0; |
3485 | int status; | 3501 | int status; |
3486 | 3502 | ||
3487 | status = decode_op_hdr(xdr, OP_READDIR); | 3503 | status = decode_op_hdr(xdr, OP_READDIR); |
@@ -3489,8 +3505,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3489 | return status; | 3505 | return status; |
3490 | READ_BUF(8); | 3506 | READ_BUF(8); |
3491 | COPYMEM(readdir->verifier.data, 8); | 3507 | COPYMEM(readdir->verifier.data, 8); |
3492 | dprintk("%s: verifier = 0x%x%x\n", | 3508 | dprintk("%s: verifier = %08x:%08x\n", |
3493 | __FUNCTION__, | 3509 | __func__, |
3494 | ((u32 *)readdir->verifier.data)[0], | 3510 | ((u32 *)readdir->verifier.data)[0], |
3495 | ((u32 *)readdir->verifier.data)[1]); | 3511 | ((u32 *)readdir->verifier.data)[1]); |
3496 | 3512 | ||
@@ -3505,7 +3521,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3505 | kaddr = p = kmap_atomic(page, KM_USER0); | 3521 | kaddr = p = kmap_atomic(page, KM_USER0); |
3506 | end = p + ((pglen + readdir->pgbase) >> 2); | 3522 | end = p + ((pglen + readdir->pgbase) >> 2); |
3507 | entry = p; | 3523 | entry = p; |
3508 | for (nr = 0; *p++; nr++) { | 3524 | |
3525 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
3526 | if ((entry + 1) > end) | ||
3527 | goto short_pkt; | ||
3528 | |||
3529 | for (; *p++; nr++) { | ||
3509 | u32 len, attrlen, xlen; | 3530 | u32 len, attrlen, xlen; |
3510 | if (end - p < 3) | 3531 | if (end - p < 3) |
3511 | goto short_pkt; | 3532 | goto short_pkt; |
@@ -3532,20 +3553,32 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3532 | p += attrlen; /* attributes */ | 3553 | p += attrlen; /* attributes */ |
3533 | entry = p; | 3554 | entry = p; |
3534 | } | 3555 | } |
3535 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 3556 | /* |
3536 | goto short_pkt; | 3557 | * Apparently some server sends responses that are a valid size, but |
3558 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
3559 | * those, just set the EOF marker. | ||
3560 | */ | ||
3561 | if (!nr && entry[1] == 0) { | ||
3562 | dprintk("NFS: readdir reply truncated!\n"); | ||
3563 | entry[1] = 1; | ||
3564 | } | ||
3537 | out: | 3565 | out: |
3538 | kunmap_atomic(kaddr, KM_USER0); | 3566 | kunmap_atomic(kaddr, KM_USER0); |
3539 | return 0; | 3567 | return 0; |
3540 | short_pkt: | 3568 | short_pkt: |
3569 | /* | ||
3570 | * When we get a short packet there are 2 possibilities. We can | ||
3571 | * return an error, or fix up the response to look like a valid | ||
3572 | * response and return what we have so far. If there are no | ||
3573 | * entries and the packet was short, then return -EIO. If there | ||
3574 | * are valid entries in the response, return them and pretend that | ||
3575 | * the call was successful, but incomplete. The caller can retry the | ||
3576 | * readdir starting at the last cookie. | ||
3577 | */ | ||
3541 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); | 3578 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); |
3542 | entry[0] = entry[1] = 0; | 3579 | entry[0] = entry[1] = 0; |
3543 | /* truncate listing ? */ | 3580 | if (nr) |
3544 | if (!nr) { | 3581 | goto out; |
3545 | dprintk("NFS: readdir reply truncated!\n"); | ||
3546 | entry[1] = 1; | ||
3547 | } | ||
3548 | goto out; | ||
3549 | err_unmap: | 3582 | err_unmap: |
3550 | kunmap_atomic(kaddr, KM_USER0); | 3583 | kunmap_atomic(kaddr, KM_USER0); |
3551 | return -errno_NFSERR_IO; | 3584 | return -errno_NFSERR_IO; |
@@ -3727,7 +3760,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
3727 | READ_BUF(len); | 3760 | READ_BUF(len); |
3728 | return -NFSERR_CLID_INUSE; | 3761 | return -NFSERR_CLID_INUSE; |
3729 | } else | 3762 | } else |
3730 | return -nfs4_stat_to_errno(nfserr); | 3763 | return nfs4_stat_to_errno(nfserr); |
3731 | 3764 | ||
3732 | return 0; | 3765 | return 0; |
3733 | } | 3766 | } |
@@ -4389,7 +4422,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4389 | if (!status) | 4422 | if (!status) |
4390 | status = decode_fsinfo(&xdr, fsinfo); | 4423 | status = decode_fsinfo(&xdr, fsinfo); |
4391 | if (!status) | 4424 | if (!status) |
4392 | status = -nfs4_stat_to_errno(hdr.status); | 4425 | status = nfs4_stat_to_errno(hdr.status); |
4393 | return status; | 4426 | return status; |
4394 | } | 4427 | } |
4395 | 4428 | ||
@@ -4479,7 +4512,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
4479 | if (!status) | 4512 | if (!status) |
4480 | status = decode_setclientid(&xdr, clp); | 4513 | status = decode_setclientid(&xdr, clp); |
4481 | if (!status) | 4514 | if (!status) |
4482 | status = -nfs4_stat_to_errno(hdr.status); | 4515 | status = nfs4_stat_to_errno(hdr.status); |
4483 | return status; | 4516 | return status; |
4484 | } | 4517 | } |
4485 | 4518 | ||
@@ -4501,7 +4534,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
4501 | if (!status) | 4534 | if (!status) |
4502 | status = decode_fsinfo(&xdr, fsinfo); | 4535 | status = decode_fsinfo(&xdr, fsinfo); |
4503 | if (!status) | 4536 | if (!status) |
4504 | status = -nfs4_stat_to_errno(hdr.status); | 4537 | status = nfs4_stat_to_errno(hdr.status); |
4505 | return status; | 4538 | return status; |
4506 | } | 4539 | } |
4507 | 4540 | ||
@@ -4611,42 +4644,42 @@ static struct { | |||
4611 | int errno; | 4644 | int errno; |
4612 | } nfs_errtbl[] = { | 4645 | } nfs_errtbl[] = { |
4613 | { NFS4_OK, 0 }, | 4646 | { NFS4_OK, 0 }, |
4614 | { NFS4ERR_PERM, EPERM }, | 4647 | { NFS4ERR_PERM, -EPERM }, |
4615 | { NFS4ERR_NOENT, ENOENT }, | 4648 | { NFS4ERR_NOENT, -ENOENT }, |
4616 | { NFS4ERR_IO, errno_NFSERR_IO }, | 4649 | { NFS4ERR_IO, -errno_NFSERR_IO}, |
4617 | { NFS4ERR_NXIO, ENXIO }, | 4650 | { NFS4ERR_NXIO, -ENXIO }, |
4618 | { NFS4ERR_ACCESS, EACCES }, | 4651 | { NFS4ERR_ACCESS, -EACCES }, |
4619 | { NFS4ERR_EXIST, EEXIST }, | 4652 | { NFS4ERR_EXIST, -EEXIST }, |
4620 | { NFS4ERR_XDEV, EXDEV }, | 4653 | { NFS4ERR_XDEV, -EXDEV }, |
4621 | { NFS4ERR_NOTDIR, ENOTDIR }, | 4654 | { NFS4ERR_NOTDIR, -ENOTDIR }, |
4622 | { NFS4ERR_ISDIR, EISDIR }, | 4655 | { NFS4ERR_ISDIR, -EISDIR }, |
4623 | { NFS4ERR_INVAL, EINVAL }, | 4656 | { NFS4ERR_INVAL, -EINVAL }, |
4624 | { NFS4ERR_FBIG, EFBIG }, | 4657 | { NFS4ERR_FBIG, -EFBIG }, |
4625 | { NFS4ERR_NOSPC, ENOSPC }, | 4658 | { NFS4ERR_NOSPC, -ENOSPC }, |
4626 | { NFS4ERR_ROFS, EROFS }, | 4659 | { NFS4ERR_ROFS, -EROFS }, |
4627 | { NFS4ERR_MLINK, EMLINK }, | 4660 | { NFS4ERR_MLINK, -EMLINK }, |
4628 | { NFS4ERR_NAMETOOLONG, ENAMETOOLONG }, | 4661 | { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG }, |
4629 | { NFS4ERR_NOTEMPTY, ENOTEMPTY }, | 4662 | { NFS4ERR_NOTEMPTY, -ENOTEMPTY }, |
4630 | { NFS4ERR_DQUOT, EDQUOT }, | 4663 | { NFS4ERR_DQUOT, -EDQUOT }, |
4631 | { NFS4ERR_STALE, ESTALE }, | 4664 | { NFS4ERR_STALE, -ESTALE }, |
4632 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | 4665 | { NFS4ERR_BADHANDLE, -EBADHANDLE }, |
4633 | { NFS4ERR_BADOWNER, EINVAL }, | 4666 | { NFS4ERR_BADOWNER, -EINVAL }, |
4634 | { NFS4ERR_BADNAME, EINVAL }, | 4667 | { NFS4ERR_BADNAME, -EINVAL }, |
4635 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | 4668 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, |
4636 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | 4669 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, |
4637 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | 4670 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, |
4638 | { NFS4ERR_SERVERFAULT, ESERVERFAULT }, | 4671 | { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, |
4639 | { NFS4ERR_BADTYPE, EBADTYPE }, | 4672 | { NFS4ERR_BADTYPE, -EBADTYPE }, |
4640 | { NFS4ERR_LOCKED, EAGAIN }, | 4673 | { NFS4ERR_LOCKED, -EAGAIN }, |
4641 | { NFS4ERR_RESOURCE, EREMOTEIO }, | 4674 | { NFS4ERR_RESOURCE, -EREMOTEIO }, |
4642 | { NFS4ERR_SYMLINK, ELOOP }, | 4675 | { NFS4ERR_SYMLINK, -ELOOP }, |
4643 | { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, | 4676 | { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, |
4644 | { NFS4ERR_DEADLOCK, EDEADLK }, | 4677 | { NFS4ERR_DEADLOCK, -EDEADLK }, |
4645 | { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs | 4678 | { NFS4ERR_WRONGSEC, -EPERM }, /* FIXME: this needs |
4646 | * to be handled by a | 4679 | * to be handled by a |
4647 | * middle-layer. | 4680 | * middle-layer. |
4648 | */ | 4681 | */ |
4649 | { -1, EIO } | 4682 | { -1, -EIO } |
4650 | }; | 4683 | }; |
4651 | 4684 | ||
4652 | /* | 4685 | /* |
@@ -4663,14 +4696,14 @@ nfs4_stat_to_errno(int stat) | |||
4663 | } | 4696 | } |
4664 | if (stat <= 10000 || stat > 10100) { | 4697 | if (stat <= 10000 || stat > 10100) { |
4665 | /* The server is looney tunes. */ | 4698 | /* The server is looney tunes. */ |
4666 | return ESERVERFAULT; | 4699 | return -ESERVERFAULT; |
4667 | } | 4700 | } |
4668 | /* If we cannot translate the error, the recovery routines should | 4701 | /* If we cannot translate the error, the recovery routines should |
4669 | * handle it. | 4702 | * handle it. |
4670 | * Note: remaining NFSv4 error codes have values > 10000, so should | 4703 | * Note: remaining NFSv4 error codes have values > 10000, so should |
4671 | * not conflict with native Linux error codes. | 4704 | * not conflict with native Linux error codes. |
4672 | */ | 4705 | */ |
4673 | return stat; | 4706 | return -stat; |
4674 | } | 4707 | } |
4675 | 4708 | ||
4676 | #define PROC(proc, argtype, restype) \ | 4709 | #define PROC(proc, argtype, restype) \ |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 5a70be589bbe..16f57e0af999 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -58,22 +58,19 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
58 | return p; | 58 | return p; |
59 | } | 59 | } |
60 | 60 | ||
61 | static void nfs_readdata_rcu_free(struct rcu_head *head) | 61 | static void nfs_readdata_free(struct nfs_read_data *p) |
62 | { | 62 | { |
63 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | ||
64 | if (p && (p->pagevec != &p->page_array[0])) | 63 | if (p && (p->pagevec != &p->page_array[0])) |
65 | kfree(p->pagevec); | 64 | kfree(p->pagevec); |
66 | mempool_free(p, nfs_rdata_mempool); | 65 | mempool_free(p, nfs_rdata_mempool); |
67 | } | 66 | } |
68 | 67 | ||
69 | static void nfs_readdata_free(struct nfs_read_data *rdata) | ||
70 | { | ||
71 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); | ||
72 | } | ||
73 | |||
74 | void nfs_readdata_release(void *data) | 68 | void nfs_readdata_release(void *data) |
75 | { | 69 | { |
76 | nfs_readdata_free(data); | 70 | struct nfs_read_data *rdata = data; |
71 | |||
72 | put_nfs_open_context(rdata->args.context); | ||
73 | nfs_readdata_free(rdata); | ||
77 | } | 74 | } |
78 | 75 | ||
79 | static | 76 | static |
@@ -156,7 +153,7 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
156 | /* | 153 | /* |
157 | * Set up the NFS read request struct | 154 | * Set up the NFS read request struct |
158 | */ | 155 | */ |
159 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | 156 | static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
160 | const struct rpc_call_ops *call_ops, | 157 | const struct rpc_call_ops *call_ops, |
161 | unsigned int count, unsigned int offset) | 158 | unsigned int count, unsigned int offset) |
162 | { | 159 | { |
@@ -174,6 +171,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
174 | .rpc_message = &msg, | 171 | .rpc_message = &msg, |
175 | .callback_ops = call_ops, | 172 | .callback_ops = call_ops, |
176 | .callback_data = data, | 173 | .callback_data = data, |
174 | .workqueue = nfsiod_workqueue, | ||
177 | .flags = RPC_TASK_ASYNC | swap_flags, | 175 | .flags = RPC_TASK_ASYNC | swap_flags, |
178 | }; | 176 | }; |
179 | 177 | ||
@@ -186,7 +184,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
186 | data->args.pgbase = req->wb_pgbase + offset; | 184 | data->args.pgbase = req->wb_pgbase + offset; |
187 | data->args.pages = data->pagevec; | 185 | data->args.pages = data->pagevec; |
188 | data->args.count = count; | 186 | data->args.count = count; |
189 | data->args.context = req->wb_context; | 187 | data->args.context = get_nfs_open_context(req->wb_context); |
190 | 188 | ||
191 | data->res.fattr = &data->fattr; | 189 | data->res.fattr = &data->fattr; |
192 | data->res.count = count; | 190 | data->res.count = count; |
@@ -204,8 +202,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
204 | (unsigned long long)data->args.offset); | 202 | (unsigned long long)data->args.offset); |
205 | 203 | ||
206 | task = rpc_run_task(&task_setup_data); | 204 | task = rpc_run_task(&task_setup_data); |
207 | if (!IS_ERR(task)) | 205 | if (IS_ERR(task)) |
208 | rpc_put_task(task); | 206 | return PTR_ERR(task); |
207 | rpc_put_task(task); | ||
208 | return 0; | ||
209 | } | 209 | } |
210 | 210 | ||
211 | static void | 211 | static void |
@@ -242,6 +242,7 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
242 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; | 242 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; |
243 | unsigned int offset; | 243 | unsigned int offset; |
244 | int requests = 0; | 244 | int requests = 0; |
245 | int ret = 0; | ||
245 | LIST_HEAD(list); | 246 | LIST_HEAD(list); |
246 | 247 | ||
247 | nfs_list_remove_request(req); | 248 | nfs_list_remove_request(req); |
@@ -253,7 +254,6 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
253 | data = nfs_readdata_alloc(1); | 254 | data = nfs_readdata_alloc(1); |
254 | if (!data) | 255 | if (!data) |
255 | goto out_bad; | 256 | goto out_bad; |
256 | INIT_LIST_HEAD(&data->pages); | ||
257 | list_add(&data->pages, &list); | 257 | list_add(&data->pages, &list); |
258 | requests++; | 258 | requests++; |
259 | nbytes -= len; | 259 | nbytes -= len; |
@@ -264,6 +264,8 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
264 | offset = 0; | 264 | offset = 0; |
265 | nbytes = count; | 265 | nbytes = count; |
266 | do { | 266 | do { |
267 | int ret2; | ||
268 | |||
267 | data = list_entry(list.next, struct nfs_read_data, pages); | 269 | data = list_entry(list.next, struct nfs_read_data, pages); |
268 | list_del_init(&data->pages); | 270 | list_del_init(&data->pages); |
269 | 271 | ||
@@ -271,13 +273,15 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
271 | 273 | ||
272 | if (nbytes < rsize) | 274 | if (nbytes < rsize) |
273 | rsize = nbytes; | 275 | rsize = nbytes; |
274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 276 | ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
275 | rsize, offset); | 277 | rsize, offset); |
278 | if (ret == 0) | ||
279 | ret = ret2; | ||
276 | offset += rsize; | 280 | offset += rsize; |
277 | nbytes -= rsize; | 281 | nbytes -= rsize; |
278 | } while (nbytes != 0); | 282 | } while (nbytes != 0); |
279 | 283 | ||
280 | return 0; | 284 | return ret; |
281 | 285 | ||
282 | out_bad: | 286 | out_bad: |
283 | while (!list_empty(&list)) { | 287 | while (!list_empty(&list)) { |
@@ -295,12 +299,12 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
295 | struct nfs_page *req; | 299 | struct nfs_page *req; |
296 | struct page **pages; | 300 | struct page **pages; |
297 | struct nfs_read_data *data; | 301 | struct nfs_read_data *data; |
302 | int ret = -ENOMEM; | ||
298 | 303 | ||
299 | data = nfs_readdata_alloc(npages); | 304 | data = nfs_readdata_alloc(npages); |
300 | if (!data) | 305 | if (!data) |
301 | goto out_bad; | 306 | goto out_bad; |
302 | 307 | ||
303 | INIT_LIST_HEAD(&data->pages); | ||
304 | pages = data->pagevec; | 308 | pages = data->pagevec; |
305 | while (!list_empty(head)) { | 309 | while (!list_empty(head)) { |
306 | req = nfs_list_entry(head->next); | 310 | req = nfs_list_entry(head->next); |
@@ -311,11 +315,10 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
311 | } | 315 | } |
312 | req = nfs_list_entry(data->pages.next); | 316 | req = nfs_list_entry(data->pages.next); |
313 | 317 | ||
314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 318 | return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
315 | return 0; | ||
316 | out_bad: | 319 | out_bad: |
317 | nfs_async_read_error(head); | 320 | nfs_async_read_error(head); |
318 | return -ENOMEM; | 321 | return ret; |
319 | } | 322 | } |
320 | 323 | ||
321 | /* | 324 | /* |
@@ -342,26 +345,25 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
342 | return 0; | 345 | return 0; |
343 | } | 346 | } |
344 | 347 | ||
345 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | 348 | static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) |
346 | { | 349 | { |
347 | struct nfs_readargs *argp = &data->args; | 350 | struct nfs_readargs *argp = &data->args; |
348 | struct nfs_readres *resp = &data->res; | 351 | struct nfs_readres *resp = &data->res; |
349 | 352 | ||
350 | if (resp->eof || resp->count == argp->count) | 353 | if (resp->eof || resp->count == argp->count) |
351 | return 0; | 354 | return; |
352 | 355 | ||
353 | /* This is a short read! */ | 356 | /* This is a short read! */ |
354 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 357 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
355 | /* Has the server at least made some progress? */ | 358 | /* Has the server at least made some progress? */ |
356 | if (resp->count == 0) | 359 | if (resp->count == 0) |
357 | return 0; | 360 | return; |
358 | 361 | ||
359 | /* Yes, so retry the read at the end of the data */ | 362 | /* Yes, so retry the read at the end of the data */ |
360 | argp->offset += resp->count; | 363 | argp->offset += resp->count; |
361 | argp->pgbase += resp->count; | 364 | argp->pgbase += resp->count; |
362 | argp->count -= resp->count; | 365 | argp->count -= resp->count; |
363 | rpc_restart_call(task); | 366 | rpc_restart_call(task); |
364 | return -EAGAIN; | ||
365 | } | 367 | } |
366 | 368 | ||
367 | /* | 369 | /* |
@@ -370,29 +372,37 @@ static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | |||
370 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | 372 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
371 | { | 373 | { |
372 | struct nfs_read_data *data = calldata; | 374 | struct nfs_read_data *data = calldata; |
373 | struct nfs_page *req = data->req; | ||
374 | struct page *page = req->wb_page; | ||
375 | 375 | ||
376 | if (nfs_readpage_result(task, data) != 0) | 376 | if (nfs_readpage_result(task, data) != 0) |
377 | return; | 377 | return; |
378 | if (task->tk_status < 0) | ||
379 | return; | ||
378 | 380 | ||
379 | if (likely(task->tk_status >= 0)) { | 381 | nfs_readpage_truncate_uninitialised_page(data); |
380 | nfs_readpage_truncate_uninitialised_page(data); | 382 | nfs_readpage_retry(task, data); |
381 | if (nfs_readpage_retry(task, data) != 0) | 383 | } |
382 | return; | 384 | |
383 | } | 385 | static void nfs_readpage_release_partial(void *calldata) |
384 | if (unlikely(task->tk_status < 0)) | 386 | { |
387 | struct nfs_read_data *data = calldata; | ||
388 | struct nfs_page *req = data->req; | ||
389 | struct page *page = req->wb_page; | ||
390 | int status = data->task.tk_status; | ||
391 | |||
392 | if (status < 0) | ||
385 | SetPageError(page); | 393 | SetPageError(page); |
394 | |||
386 | if (atomic_dec_and_test(&req->wb_complete)) { | 395 | if (atomic_dec_and_test(&req->wb_complete)) { |
387 | if (!PageError(page)) | 396 | if (!PageError(page)) |
388 | SetPageUptodate(page); | 397 | SetPageUptodate(page); |
389 | nfs_readpage_release(req); | 398 | nfs_readpage_release(req); |
390 | } | 399 | } |
400 | nfs_readdata_release(calldata); | ||
391 | } | 401 | } |
392 | 402 | ||
393 | static const struct rpc_call_ops nfs_read_partial_ops = { | 403 | static const struct rpc_call_ops nfs_read_partial_ops = { |
394 | .rpc_call_done = nfs_readpage_result_partial, | 404 | .rpc_call_done = nfs_readpage_result_partial, |
395 | .rpc_release = nfs_readdata_release, | 405 | .rpc_release = nfs_readpage_release_partial, |
396 | }; | 406 | }; |
397 | 407 | ||
398 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | 408 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) |
@@ -427,29 +437,35 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) | |||
427 | 437 | ||
428 | if (nfs_readpage_result(task, data) != 0) | 438 | if (nfs_readpage_result(task, data) != 0) |
429 | return; | 439 | return; |
440 | if (task->tk_status < 0) | ||
441 | return; | ||
430 | /* | 442 | /* |
431 | * Note: nfs_readpage_retry may change the values of | 443 | * Note: nfs_readpage_retry may change the values of |
432 | * data->args. In the multi-page case, we therefore need | 444 | * data->args. In the multi-page case, we therefore need |
433 | * to ensure that we call nfs_readpage_set_pages_uptodate() | 445 | * to ensure that we call nfs_readpage_set_pages_uptodate() |
434 | * first. | 446 | * first. |
435 | */ | 447 | */ |
436 | if (likely(task->tk_status >= 0)) { | 448 | nfs_readpage_truncate_uninitialised_page(data); |
437 | nfs_readpage_truncate_uninitialised_page(data); | 449 | nfs_readpage_set_pages_uptodate(data); |
438 | nfs_readpage_set_pages_uptodate(data); | 450 | nfs_readpage_retry(task, data); |
439 | if (nfs_readpage_retry(task, data) != 0) | 451 | } |
440 | return; | 452 | |
441 | } | 453 | static void nfs_readpage_release_full(void *calldata) |
454 | { | ||
455 | struct nfs_read_data *data = calldata; | ||
456 | |||
442 | while (!list_empty(&data->pages)) { | 457 | while (!list_empty(&data->pages)) { |
443 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 458 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
444 | 459 | ||
445 | nfs_list_remove_request(req); | 460 | nfs_list_remove_request(req); |
446 | nfs_readpage_release(req); | 461 | nfs_readpage_release(req); |
447 | } | 462 | } |
463 | nfs_readdata_release(calldata); | ||
448 | } | 464 | } |
449 | 465 | ||
450 | static const struct rpc_call_ops nfs_read_full_ops = { | 466 | static const struct rpc_call_ops nfs_read_full_ops = { |
451 | .rpc_call_done = nfs_readpage_result_full, | 467 | .rpc_call_done = nfs_readpage_result_full, |
452 | .rpc_release = nfs_readdata_release, | 468 | .rpc_release = nfs_readpage_release_full, |
453 | }; | 469 | }; |
454 | 470 | ||
455 | /* | 471 | /* |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f9219024f31a..20a1cb1810fe 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -441,10 +441,52 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
441 | return sec_flavours[i].str; | 441 | return sec_flavours[i].str; |
442 | } | 442 | } |
443 | 443 | ||
444 | static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | ||
445 | int showdefaults) | ||
446 | { | ||
447 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; | ||
448 | |||
449 | switch (sap->sa_family) { | ||
450 | case AF_INET: { | ||
451 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
452 | seq_printf(m, ",mountaddr=" NIPQUAD_FMT, | ||
453 | NIPQUAD(sin->sin_addr.s_addr)); | ||
454 | break; | ||
455 | } | ||
456 | case AF_INET6: { | ||
457 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
458 | seq_printf(m, ",mountaddr=" NIP6_FMT, | ||
459 | NIP6(sin6->sin6_addr)); | ||
460 | break; | ||
461 | } | ||
462 | default: | ||
463 | if (showdefaults) | ||
464 | seq_printf(m, ",mountaddr=unspecified"); | ||
465 | } | ||
466 | |||
467 | if (nfss->mountd_version || showdefaults) | ||
468 | seq_printf(m, ",mountvers=%u", nfss->mountd_version); | ||
469 | if (nfss->mountd_port || showdefaults) | ||
470 | seq_printf(m, ",mountport=%u", nfss->mountd_port); | ||
471 | |||
472 | switch (nfss->mountd_protocol) { | ||
473 | case IPPROTO_UDP: | ||
474 | seq_printf(m, ",mountproto=udp"); | ||
475 | break; | ||
476 | case IPPROTO_TCP: | ||
477 | seq_printf(m, ",mountproto=tcp"); | ||
478 | break; | ||
479 | default: | ||
480 | if (showdefaults) | ||
481 | seq_printf(m, ",mountproto=auto"); | ||
482 | } | ||
483 | } | ||
484 | |||
444 | /* | 485 | /* |
445 | * Describe the mount options in force on this server representation | 486 | * Describe the mount options in force on this server representation |
446 | */ | 487 | */ |
447 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) | 488 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, |
489 | int showdefaults) | ||
448 | { | 490 | { |
449 | static const struct proc_nfs_info { | 491 | static const struct proc_nfs_info { |
450 | int flag; | 492 | int flag; |
@@ -452,6 +494,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
452 | const char *nostr; | 494 | const char *nostr; |
453 | } nfs_info[] = { | 495 | } nfs_info[] = { |
454 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 496 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
497 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
498 | { NFS_MOUNT_POSIX, ",posix", "" }, | ||
455 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 499 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
456 | { NFS_MOUNT_NOAC, ",noac", "" }, | 500 | { NFS_MOUNT_NOAC, ",noac", "" }, |
457 | { NFS_MOUNT_NONLM, ",nolock", "" }, | 501 | { NFS_MOUNT_NONLM, ",nolock", "" }, |
@@ -462,18 +506,22 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
462 | }; | 506 | }; |
463 | const struct proc_nfs_info *nfs_infop; | 507 | const struct proc_nfs_info *nfs_infop; |
464 | struct nfs_client *clp = nfss->nfs_client; | 508 | struct nfs_client *clp = nfss->nfs_client; |
465 | 509 | u32 version = clp->rpc_ops->version; | |
466 | seq_printf(m, ",vers=%d", clp->rpc_ops->version); | 510 | |
467 | seq_printf(m, ",rsize=%d", nfss->rsize); | 511 | seq_printf(m, ",vers=%u", version); |
468 | seq_printf(m, ",wsize=%d", nfss->wsize); | 512 | seq_printf(m, ",rsize=%u", nfss->rsize); |
513 | seq_printf(m, ",wsize=%u", nfss->wsize); | ||
514 | if (nfss->bsize != 0) | ||
515 | seq_printf(m, ",bsize=%u", nfss->bsize); | ||
516 | seq_printf(m, ",namlen=%u", nfss->namelen); | ||
469 | if (nfss->acregmin != 3*HZ || showdefaults) | 517 | if (nfss->acregmin != 3*HZ || showdefaults) |
470 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); | 518 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); |
471 | if (nfss->acregmax != 60*HZ || showdefaults) | 519 | if (nfss->acregmax != 60*HZ || showdefaults) |
472 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); | 520 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); |
473 | if (nfss->acdirmin != 30*HZ || showdefaults) | 521 | if (nfss->acdirmin != 30*HZ || showdefaults) |
474 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); | 522 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); |
475 | if (nfss->acdirmax != 60*HZ || showdefaults) | 523 | if (nfss->acdirmax != 60*HZ || showdefaults) |
476 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); | 524 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); |
477 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 525 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
478 | if (nfss->flags & nfs_infop->flag) | 526 | if (nfss->flags & nfs_infop->flag) |
479 | seq_puts(m, nfs_infop->str); | 527 | seq_puts(m, nfs_infop->str); |
@@ -482,9 +530,24 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
482 | } | 530 | } |
483 | seq_printf(m, ",proto=%s", | 531 | seq_printf(m, ",proto=%s", |
484 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 532 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); |
533 | if (version == 4) { | ||
534 | if (nfss->port != NFS_PORT) | ||
535 | seq_printf(m, ",port=%u", nfss->port); | ||
536 | } else | ||
537 | if (nfss->port) | ||
538 | seq_printf(m, ",port=%u", nfss->port); | ||
539 | |||
485 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); | 540 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); |
486 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); | 541 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); |
487 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 542 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
543 | |||
544 | if (version != 4) | ||
545 | nfs_show_mountd_options(m, nfss, showdefaults); | ||
546 | |||
547 | #ifdef CONFIG_NFS_V4 | ||
548 | if (clp->rpc_ops->version == 4) | ||
549 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
550 | #endif | ||
488 | } | 551 | } |
489 | 552 | ||
490 | /* | 553 | /* |
@@ -529,10 +592,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
529 | 592 | ||
530 | seq_printf(m, "\n\tcaps:\t"); | 593 | seq_printf(m, "\n\tcaps:\t"); |
531 | seq_printf(m, "caps=0x%x", nfss->caps); | 594 | seq_printf(m, "caps=0x%x", nfss->caps); |
532 | seq_printf(m, ",wtmult=%d", nfss->wtmult); | 595 | seq_printf(m, ",wtmult=%u", nfss->wtmult); |
533 | seq_printf(m, ",dtsize=%d", nfss->dtsize); | 596 | seq_printf(m, ",dtsize=%u", nfss->dtsize); |
534 | seq_printf(m, ",bsize=%d", nfss->bsize); | 597 | seq_printf(m, ",bsize=%u", nfss->bsize); |
535 | seq_printf(m, ",namelen=%d", nfss->namelen); | 598 | seq_printf(m, ",namlen=%u", nfss->namelen); |
536 | 599 | ||
537 | #ifdef CONFIG_NFS_V4 | 600 | #ifdef CONFIG_NFS_V4 |
538 | if (nfss->nfs_client->rpc_ops->version == 4) { | 601 | if (nfss->nfs_client->rpc_ops->version == 4) { |
@@ -546,9 +609,9 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
546 | /* | 609 | /* |
547 | * Display security flavor in effect for this mount | 610 | * Display security flavor in effect for this mount |
548 | */ | 611 | */ |
549 | seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor); | 612 | seq_printf(m, "\n\tsec:\tflavor=%u", auth->au_ops->au_flavor); |
550 | if (auth->au_flavor) | 613 | if (auth->au_flavor) |
551 | seq_printf(m, ",pseudoflavor=%d", auth->au_flavor); | 614 | seq_printf(m, ",pseudoflavor=%u", auth->au_flavor); |
552 | 615 | ||
553 | /* | 616 | /* |
554 | * Display superblock I/O counters | 617 | * Display superblock I/O counters |
@@ -683,7 +746,6 @@ static int nfs_parse_mount_options(char *raw, | |||
683 | struct nfs_parsed_mount_data *mnt) | 746 | struct nfs_parsed_mount_data *mnt) |
684 | { | 747 | { |
685 | char *p, *string, *secdata; | 748 | char *p, *string, *secdata; |
686 | unsigned short port = 0; | ||
687 | int rc; | 749 | int rc; |
688 | 750 | ||
689 | if (!raw) { | 751 | if (!raw) { |
@@ -798,7 +860,7 @@ static int nfs_parse_mount_options(char *raw, | |||
798 | return 0; | 860 | return 0; |
799 | if (option < 0 || option > 65535) | 861 | if (option < 0 || option > 65535) |
800 | return 0; | 862 | return 0; |
801 | port = option; | 863 | mnt->nfs_server.port = option; |
802 | break; | 864 | break; |
803 | case Opt_rsize: | 865 | case Opt_rsize: |
804 | if (match_int(args, &mnt->rsize)) | 866 | if (match_int(args, &mnt->rsize)) |
@@ -1048,7 +1110,8 @@ static int nfs_parse_mount_options(char *raw, | |||
1048 | } | 1110 | } |
1049 | } | 1111 | } |
1050 | 1112 | ||
1051 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port); | 1113 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, |
1114 | mnt->nfs_server.port); | ||
1052 | 1115 | ||
1053 | return 1; | 1116 | return 1; |
1054 | 1117 | ||
@@ -1169,7 +1232,9 @@ static int nfs_validate_mount_data(void *options, | |||
1169 | args->acregmax = 60; | 1232 | args->acregmax = 60; |
1170 | args->acdirmin = 30; | 1233 | args->acdirmin = 30; |
1171 | args->acdirmax = 60; | 1234 | args->acdirmax = 60; |
1235 | args->mount_server.port = 0; /* autobind unless user sets port */ | ||
1172 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1236 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; |
1237 | args->nfs_server.port = 0; /* autobind unless user sets port */ | ||
1173 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1238 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1174 | 1239 | ||
1175 | switch (data->version) { | 1240 | switch (data->version) { |
@@ -1208,7 +1273,6 @@ static int nfs_validate_mount_data(void *options, | |||
1208 | args->flags = data->flags; | 1273 | args->flags = data->flags; |
1209 | args->rsize = data->rsize; | 1274 | args->rsize = data->rsize; |
1210 | args->wsize = data->wsize; | 1275 | args->wsize = data->wsize; |
1211 | args->flags = data->flags; | ||
1212 | args->timeo = data->timeo; | 1276 | args->timeo = data->timeo; |
1213 | args->retrans = data->retrans; | 1277 | args->retrans = data->retrans; |
1214 | args->acregmin = data->acregmin; | 1278 | args->acregmin = data->acregmin; |
@@ -1230,6 +1294,8 @@ static int nfs_validate_mount_data(void *options, | |||
1230 | args->namlen = data->namlen; | 1294 | args->namlen = data->namlen; |
1231 | args->bsize = data->bsize; | 1295 | args->bsize = data->bsize; |
1232 | args->auth_flavors[0] = data->pseudoflavor; | 1296 | args->auth_flavors[0] = data->pseudoflavor; |
1297 | if (!args->nfs_server.hostname) | ||
1298 | goto out_nomem; | ||
1233 | 1299 | ||
1234 | /* | 1300 | /* |
1235 | * The legacy version 6 binary mount data from userspace has a | 1301 | * The legacy version 6 binary mount data from userspace has a |
@@ -1276,6 +1342,8 @@ static int nfs_validate_mount_data(void *options, | |||
1276 | len = c - dev_name; | 1342 | len = c - dev_name; |
1277 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1343 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1278 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | 1344 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1345 | if (!args->nfs_server.hostname) | ||
1346 | goto out_nomem; | ||
1279 | 1347 | ||
1280 | c++; | 1348 | c++; |
1281 | if (strlen(c) > NFS_MAXPATHLEN) | 1349 | if (strlen(c) > NFS_MAXPATHLEN) |
@@ -1319,6 +1387,10 @@ out_v3_not_compiled: | |||
1319 | return -EPROTONOSUPPORT; | 1387 | return -EPROTONOSUPPORT; |
1320 | #endif /* !CONFIG_NFS_V3 */ | 1388 | #endif /* !CONFIG_NFS_V3 */ |
1321 | 1389 | ||
1390 | out_nomem: | ||
1391 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | ||
1392 | return -ENOMEM; | ||
1393 | |||
1322 | out_no_address: | 1394 | out_no_address: |
1323 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | 1395 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); |
1324 | return -EINVAL; | 1396 | return -EINVAL; |
@@ -1706,28 +1778,6 @@ static void nfs4_fill_super(struct super_block *sb) | |||
1706 | } | 1778 | } |
1707 | 1779 | ||
1708 | /* | 1780 | /* |
1709 | * If the user didn't specify a port, set the port number to | ||
1710 | * the NFS version 4 default port. | ||
1711 | */ | ||
1712 | static void nfs4_default_port(struct sockaddr *sap) | ||
1713 | { | ||
1714 | switch (sap->sa_family) { | ||
1715 | case AF_INET: { | ||
1716 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
1717 | if (ap->sin_port == 0) | ||
1718 | ap->sin_port = htons(NFS_PORT); | ||
1719 | break; | ||
1720 | } | ||
1721 | case AF_INET6: { | ||
1722 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
1723 | if (ap->sin6_port == 0) | ||
1724 | ap->sin6_port = htons(NFS_PORT); | ||
1725 | break; | ||
1726 | } | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | /* | ||
1731 | * Validate NFSv4 mount options | 1781 | * Validate NFSv4 mount options |
1732 | */ | 1782 | */ |
1733 | static int nfs4_validate_mount_data(void *options, | 1783 | static int nfs4_validate_mount_data(void *options, |
@@ -1751,6 +1801,7 @@ static int nfs4_validate_mount_data(void *options, | |||
1751 | args->acregmax = 60; | 1801 | args->acregmax = 60; |
1752 | args->acdirmin = 30; | 1802 | args->acdirmin = 30; |
1753 | args->acdirmax = 60; | 1803 | args->acdirmax = 60; |
1804 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | ||
1754 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1805 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1755 | 1806 | ||
1756 | switch (data->version) { | 1807 | switch (data->version) { |
@@ -1767,9 +1818,6 @@ static int nfs4_validate_mount_data(void *options, | |||
1767 | &args->nfs_server.address)) | 1818 | &args->nfs_server.address)) |
1768 | goto out_no_address; | 1819 | goto out_no_address; |
1769 | 1820 | ||
1770 | nfs4_default_port((struct sockaddr *) | ||
1771 | &args->nfs_server.address); | ||
1772 | |||
1773 | switch (data->auth_flavourlen) { | 1821 | switch (data->auth_flavourlen) { |
1774 | case 0: | 1822 | case 0: |
1775 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1823 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1827,9 +1875,6 @@ static int nfs4_validate_mount_data(void *options, | |||
1827 | &args->nfs_server.address)) | 1875 | &args->nfs_server.address)) |
1828 | return -EINVAL; | 1876 | return -EINVAL; |
1829 | 1877 | ||
1830 | nfs4_default_port((struct sockaddr *) | ||
1831 | &args->nfs_server.address); | ||
1832 | |||
1833 | switch (args->auth_flavor_len) { | 1878 | switch (args->auth_flavor_len) { |
1834 | case 0: | 1879 | case 0: |
1835 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1880 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1852,12 +1897,16 @@ static int nfs4_validate_mount_data(void *options, | |||
1852 | return -ENAMETOOLONG; | 1897 | return -ENAMETOOLONG; |
1853 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1898 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1854 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | 1899 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1900 | if (!args->nfs_server.hostname) | ||
1901 | goto out_nomem; | ||
1855 | 1902 | ||
1856 | c++; /* step over the ':' */ | 1903 | c++; /* step over the ':' */ |
1857 | len = strlen(c); | 1904 | len = strlen(c); |
1858 | if (len > NFS4_MAXPATHLEN) | 1905 | if (len > NFS4_MAXPATHLEN) |
1859 | return -ENAMETOOLONG; | 1906 | return -ENAMETOOLONG; |
1860 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); | 1907 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); |
1908 | if (!args->nfs_server.export_path) | ||
1909 | goto out_nomem; | ||
1861 | 1910 | ||
1862 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); | 1911 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); |
1863 | 1912 | ||
@@ -1879,6 +1928,10 @@ out_inval_auth: | |||
1879 | data->auth_flavourlen); | 1928 | data->auth_flavourlen); |
1880 | return -EINVAL; | 1929 | return -EINVAL; |
1881 | 1930 | ||
1931 | out_nomem: | ||
1932 | dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n"); | ||
1933 | return -ENOMEM; | ||
1934 | |||
1882 | out_no_address: | 1935 | out_no_address: |
1883 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 1936 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
1884 | return -EINVAL; | 1937 | return -EINVAL; |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 757415363422..3adf8b266461 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -234,7 +234,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
234 | if (data == NULL) | 234 | if (data == NULL) |
235 | goto out; | 235 | goto out; |
236 | 236 | ||
237 | data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 237 | data->cred = rpc_lookup_cred(); |
238 | if (IS_ERR(data->cred)) { | 238 | if (IS_ERR(data->cred)) { |
239 | status = PTR_ERR(data->cred); | 239 | status = PTR_ERR(data->cred); |
240 | goto out_free; | 240 | goto out_free; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bed63416a55b..1ade11d1ba07 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -48,7 +48,7 @@ static struct kmem_cache *nfs_wdata_cachep; | |||
48 | static mempool_t *nfs_wdata_mempool; | 48 | static mempool_t *nfs_wdata_mempool; |
49 | static mempool_t *nfs_commit_mempool; | 49 | static mempool_t *nfs_commit_mempool; |
50 | 50 | ||
51 | struct nfs_write_data *nfs_commit_alloc(void) | 51 | struct nfs_write_data *nfs_commitdata_alloc(void) |
52 | { | 52 | { |
53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); | 53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); |
54 | 54 | ||
@@ -59,19 +59,13 @@ struct nfs_write_data *nfs_commit_alloc(void) | |||
59 | return p; | 59 | return p; |
60 | } | 60 | } |
61 | 61 | ||
62 | static void nfs_commit_rcu_free(struct rcu_head *head) | 62 | void nfs_commit_free(struct nfs_write_data *p) |
63 | { | 63 | { |
64 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
65 | if (p && (p->pagevec != &p->page_array[0])) | 64 | if (p && (p->pagevec != &p->page_array[0])) |
66 | kfree(p->pagevec); | 65 | kfree(p->pagevec); |
67 | mempool_free(p, nfs_commit_mempool); | 66 | mempool_free(p, nfs_commit_mempool); |
68 | } | 67 | } |
69 | 68 | ||
70 | void nfs_commit_free(struct nfs_write_data *wdata) | ||
71 | { | ||
72 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | ||
73 | } | ||
74 | |||
75 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 69 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
76 | { | 70 | { |
77 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); | 71 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
@@ -93,21 +87,18 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
93 | return p; | 87 | return p; |
94 | } | 88 | } |
95 | 89 | ||
96 | static void nfs_writedata_rcu_free(struct rcu_head *head) | 90 | static void nfs_writedata_free(struct nfs_write_data *p) |
97 | { | 91 | { |
98 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
99 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
100 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
101 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
102 | } | 95 | } |
103 | 96 | ||
104 | static void nfs_writedata_free(struct nfs_write_data *wdata) | 97 | void nfs_writedata_release(void *data) |
105 | { | 98 | { |
106 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | 99 | struct nfs_write_data *wdata = data; |
107 | } | ||
108 | 100 | ||
109 | void nfs_writedata_release(void *wdata) | 101 | put_nfs_open_context(wdata->args.context); |
110 | { | ||
111 | nfs_writedata_free(wdata); | 102 | nfs_writedata_free(wdata); |
112 | } | 103 | } |
113 | 104 | ||
@@ -291,8 +282,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
291 | spin_unlock(&inode->i_lock); | 282 | spin_unlock(&inode->i_lock); |
292 | if (!nfs_pageio_add_request(pgio, req)) { | 283 | if (!nfs_pageio_add_request(pgio, req)) { |
293 | nfs_redirty_request(req); | 284 | nfs_redirty_request(req); |
294 | nfs_end_page_writeback(page); | ||
295 | nfs_clear_page_tag_locked(req); | ||
296 | return pgio->pg_error; | 285 | return pgio->pg_error; |
297 | } | 286 | } |
298 | return 0; | 287 | return 0; |
@@ -366,15 +355,13 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
366 | /* | 355 | /* |
367 | * Insert a write request into an inode | 356 | * Insert a write request into an inode |
368 | */ | 357 | */ |
369 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | 358 | static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) |
370 | { | 359 | { |
371 | struct nfs_inode *nfsi = NFS_I(inode); | 360 | struct nfs_inode *nfsi = NFS_I(inode); |
372 | int error; | 361 | int error; |
373 | 362 | ||
374 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 363 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
375 | BUG_ON(error == -EEXIST); | 364 | BUG_ON(error); |
376 | if (error) | ||
377 | return error; | ||
378 | if (!nfsi->npages) { | 365 | if (!nfsi->npages) { |
379 | igrab(inode); | 366 | igrab(inode); |
380 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 367 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
@@ -384,8 +371,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
384 | set_page_private(req->wb_page, (unsigned long)req); | 371 | set_page_private(req->wb_page, (unsigned long)req); |
385 | nfsi->npages++; | 372 | nfsi->npages++; |
386 | kref_get(&req->wb_kref); | 373 | kref_get(&req->wb_kref); |
387 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 374 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, |
388 | return 0; | 375 | NFS_PAGE_TAG_LOCKED); |
389 | } | 376 | } |
390 | 377 | ||
391 | /* | 378 | /* |
@@ -413,7 +400,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
413 | } | 400 | } |
414 | 401 | ||
415 | static void | 402 | static void |
416 | nfs_redirty_request(struct nfs_page *req) | 403 | nfs_mark_request_dirty(struct nfs_page *req) |
417 | { | 404 | { |
418 | __set_page_dirty_nobuffers(req->wb_page); | 405 | __set_page_dirty_nobuffers(req->wb_page); |
419 | } | 406 | } |
@@ -467,7 +454,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
467 | return 1; | 454 | return 1; |
468 | } | 455 | } |
469 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 456 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
470 | nfs_redirty_request(req); | 457 | nfs_mark_request_dirty(req); |
471 | return 1; | 458 | return 1; |
472 | } | 459 | } |
473 | return 0; | 460 | return 0; |
@@ -597,6 +584,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
597 | /* Loop over all inode entries and see if we find | 584 | /* Loop over all inode entries and see if we find |
598 | * A request for the page we wish to update | 585 | * A request for the page we wish to update |
599 | */ | 586 | */ |
587 | if (new) { | ||
588 | if (radix_tree_preload(GFP_NOFS)) { | ||
589 | nfs_release_request(new); | ||
590 | return ERR_PTR(-ENOMEM); | ||
591 | } | ||
592 | } | ||
593 | |||
600 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
601 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
602 | if (req) { | 596 | if (req) { |
@@ -607,28 +601,27 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
607 | error = nfs_wait_on_request(req); | 601 | error = nfs_wait_on_request(req); |
608 | nfs_release_request(req); | 602 | nfs_release_request(req); |
609 | if (error < 0) { | 603 | if (error < 0) { |
610 | if (new) | 604 | if (new) { |
605 | radix_tree_preload_end(); | ||
611 | nfs_release_request(new); | 606 | nfs_release_request(new); |
607 | } | ||
612 | return ERR_PTR(error); | 608 | return ERR_PTR(error); |
613 | } | 609 | } |
614 | continue; | 610 | continue; |
615 | } | 611 | } |
616 | spin_unlock(&inode->i_lock); | 612 | spin_unlock(&inode->i_lock); |
617 | if (new) | 613 | if (new) { |
614 | radix_tree_preload_end(); | ||
618 | nfs_release_request(new); | 615 | nfs_release_request(new); |
616 | } | ||
619 | break; | 617 | break; |
620 | } | 618 | } |
621 | 619 | ||
622 | if (new) { | 620 | if (new) { |
623 | int error; | ||
624 | nfs_lock_request_dontget(new); | 621 | nfs_lock_request_dontget(new); |
625 | error = nfs_inode_add_request(inode, new); | 622 | nfs_inode_add_request(inode, new); |
626 | if (error) { | ||
627 | spin_unlock(&inode->i_lock); | ||
628 | nfs_unlock_request(new); | ||
629 | return ERR_PTR(error); | ||
630 | } | ||
631 | spin_unlock(&inode->i_lock); | 623 | spin_unlock(&inode->i_lock); |
624 | radix_tree_preload_end(); | ||
632 | req = new; | 625 | req = new; |
633 | goto zero_page; | 626 | goto zero_page; |
634 | } | 627 | } |
@@ -785,7 +778,7 @@ static int flush_task_priority(int how) | |||
785 | /* | 778 | /* |
786 | * Set up the argument/result storage required for the RPC call. | 779 | * Set up the argument/result storage required for the RPC call. |
787 | */ | 780 | */ |
788 | static void nfs_write_rpcsetup(struct nfs_page *req, | 781 | static int nfs_write_rpcsetup(struct nfs_page *req, |
789 | struct nfs_write_data *data, | 782 | struct nfs_write_data *data, |
790 | const struct rpc_call_ops *call_ops, | 783 | const struct rpc_call_ops *call_ops, |
791 | unsigned int count, unsigned int offset, | 784 | unsigned int count, unsigned int offset, |
@@ -806,6 +799,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
806 | .rpc_message = &msg, | 799 | .rpc_message = &msg, |
807 | .callback_ops = call_ops, | 800 | .callback_ops = call_ops, |
808 | .callback_data = data, | 801 | .callback_data = data, |
802 | .workqueue = nfsiod_workqueue, | ||
809 | .flags = flags, | 803 | .flags = flags, |
810 | .priority = priority, | 804 | .priority = priority, |
811 | }; | 805 | }; |
@@ -822,7 +816,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
822 | data->args.pgbase = req->wb_pgbase + offset; | 816 | data->args.pgbase = req->wb_pgbase + offset; |
823 | data->args.pages = data->pagevec; | 817 | data->args.pages = data->pagevec; |
824 | data->args.count = count; | 818 | data->args.count = count; |
825 | data->args.context = req->wb_context; | 819 | data->args.context = get_nfs_open_context(req->wb_context); |
826 | data->args.stable = NFS_UNSTABLE; | 820 | data->args.stable = NFS_UNSTABLE; |
827 | if (how & FLUSH_STABLE) { | 821 | if (how & FLUSH_STABLE) { |
828 | data->args.stable = NFS_DATA_SYNC; | 822 | data->args.stable = NFS_DATA_SYNC; |
@@ -847,8 +841,21 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
847 | (unsigned long long)data->args.offset); | 841 | (unsigned long long)data->args.offset); |
848 | 842 | ||
849 | task = rpc_run_task(&task_setup_data); | 843 | task = rpc_run_task(&task_setup_data); |
850 | if (!IS_ERR(task)) | 844 | if (IS_ERR(task)) |
851 | rpc_put_task(task); | 845 | return PTR_ERR(task); |
846 | rpc_put_task(task); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | ||
851 | * call this on each, which will prepare them to be retried on next | ||
852 | * writeback using standard nfs. | ||
853 | */ | ||
854 | static void nfs_redirty_request(struct nfs_page *req) | ||
855 | { | ||
856 | nfs_mark_request_dirty(req); | ||
857 | nfs_end_page_writeback(req->wb_page); | ||
858 | nfs_clear_page_tag_locked(req); | ||
852 | } | 859 | } |
853 | 860 | ||
854 | /* | 861 | /* |
@@ -863,6 +870,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
863 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; | 870 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; |
864 | unsigned int offset; | 871 | unsigned int offset; |
865 | int requests = 0; | 872 | int requests = 0; |
873 | int ret = 0; | ||
866 | LIST_HEAD(list); | 874 | LIST_HEAD(list); |
867 | 875 | ||
868 | nfs_list_remove_request(req); | 876 | nfs_list_remove_request(req); |
@@ -884,6 +892,8 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
884 | offset = 0; | 892 | offset = 0; |
885 | nbytes = count; | 893 | nbytes = count; |
886 | do { | 894 | do { |
895 | int ret2; | ||
896 | |||
887 | data = list_entry(list.next, struct nfs_write_data, pages); | 897 | data = list_entry(list.next, struct nfs_write_data, pages); |
888 | list_del_init(&data->pages); | 898 | list_del_init(&data->pages); |
889 | 899 | ||
@@ -891,13 +901,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
891 | 901 | ||
892 | if (nbytes < wsize) | 902 | if (nbytes < wsize) |
893 | wsize = nbytes; | 903 | wsize = nbytes; |
894 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 904 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
895 | wsize, offset, how); | 905 | wsize, offset, how); |
906 | if (ret == 0) | ||
907 | ret = ret2; | ||
896 | offset += wsize; | 908 | offset += wsize; |
897 | nbytes -= wsize; | 909 | nbytes -= wsize; |
898 | } while (nbytes != 0); | 910 | } while (nbytes != 0); |
899 | 911 | ||
900 | return 0; | 912 | return ret; |
901 | 913 | ||
902 | out_bad: | 914 | out_bad: |
903 | while (!list_empty(&list)) { | 915 | while (!list_empty(&list)) { |
@@ -906,8 +918,6 @@ out_bad: | |||
906 | nfs_writedata_release(data); | 918 | nfs_writedata_release(data); |
907 | } | 919 | } |
908 | nfs_redirty_request(req); | 920 | nfs_redirty_request(req); |
909 | nfs_end_page_writeback(req->wb_page); | ||
910 | nfs_clear_page_tag_locked(req); | ||
911 | return -ENOMEM; | 921 | return -ENOMEM; |
912 | } | 922 | } |
913 | 923 | ||
@@ -940,16 +950,12 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
940 | req = nfs_list_entry(data->pages.next); | 950 | req = nfs_list_entry(data->pages.next); |
941 | 951 | ||
942 | /* Set up the argument struct */ | 952 | /* Set up the argument struct */ |
943 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 953 | return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
944 | |||
945 | return 0; | ||
946 | out_bad: | 954 | out_bad: |
947 | while (!list_empty(head)) { | 955 | while (!list_empty(head)) { |
948 | req = nfs_list_entry(head->next); | 956 | req = nfs_list_entry(head->next); |
949 | nfs_list_remove_request(req); | 957 | nfs_list_remove_request(req); |
950 | nfs_redirty_request(req); | 958 | nfs_redirty_request(req); |
951 | nfs_end_page_writeback(req->wb_page); | ||
952 | nfs_clear_page_tag_locked(req); | ||
953 | } | 959 | } |
954 | return -ENOMEM; | 960 | return -ENOMEM; |
955 | } | 961 | } |
@@ -972,7 +978,6 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
972 | { | 978 | { |
973 | struct nfs_write_data *data = calldata; | 979 | struct nfs_write_data *data = calldata; |
974 | struct nfs_page *req = data->req; | 980 | struct nfs_page *req = data->req; |
975 | struct page *page = req->wb_page; | ||
976 | 981 | ||
977 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 982 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
978 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 983 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -980,13 +985,20 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
980 | req->wb_bytes, | 985 | req->wb_bytes, |
981 | (long long)req_offset(req)); | 986 | (long long)req_offset(req)); |
982 | 987 | ||
983 | if (nfs_writeback_done(task, data) != 0) | 988 | nfs_writeback_done(task, data); |
984 | return; | 989 | } |
985 | 990 | ||
986 | if (task->tk_status < 0) { | 991 | static void nfs_writeback_release_partial(void *calldata) |
992 | { | ||
993 | struct nfs_write_data *data = calldata; | ||
994 | struct nfs_page *req = data->req; | ||
995 | struct page *page = req->wb_page; | ||
996 | int status = data->task.tk_status; | ||
997 | |||
998 | if (status < 0) { | ||
987 | nfs_set_pageerror(page); | 999 | nfs_set_pageerror(page); |
988 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1000 | nfs_context_set_write_error(req->wb_context, status); |
989 | dprintk(", error = %d\n", task->tk_status); | 1001 | dprintk(", error = %d\n", status); |
990 | goto out; | 1002 | goto out; |
991 | } | 1003 | } |
992 | 1004 | ||
@@ -1011,11 +1023,12 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
1011 | out: | 1023 | out: |
1012 | if (atomic_dec_and_test(&req->wb_complete)) | 1024 | if (atomic_dec_and_test(&req->wb_complete)) |
1013 | nfs_writepage_release(req); | 1025 | nfs_writepage_release(req); |
1026 | nfs_writedata_release(calldata); | ||
1014 | } | 1027 | } |
1015 | 1028 | ||
1016 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1029 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1017 | .rpc_call_done = nfs_writeback_done_partial, | 1030 | .rpc_call_done = nfs_writeback_done_partial, |
1018 | .rpc_release = nfs_writedata_release, | 1031 | .rpc_release = nfs_writeback_release_partial, |
1019 | }; | 1032 | }; |
1020 | 1033 | ||
1021 | /* | 1034 | /* |
@@ -1028,17 +1041,21 @@ static const struct rpc_call_ops nfs_write_partial_ops = { | |||
1028 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | 1041 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1029 | { | 1042 | { |
1030 | struct nfs_write_data *data = calldata; | 1043 | struct nfs_write_data *data = calldata; |
1031 | struct nfs_page *req; | ||
1032 | struct page *page; | ||
1033 | 1044 | ||
1034 | if (nfs_writeback_done(task, data) != 0) | 1045 | nfs_writeback_done(task, data); |
1035 | return; | 1046 | } |
1047 | |||
1048 | static void nfs_writeback_release_full(void *calldata) | ||
1049 | { | ||
1050 | struct nfs_write_data *data = calldata; | ||
1051 | int status = data->task.tk_status; | ||
1036 | 1052 | ||
1037 | /* Update attributes as result of writeback. */ | 1053 | /* Update attributes as result of writeback. */ |
1038 | while (!list_empty(&data->pages)) { | 1054 | while (!list_empty(&data->pages)) { |
1039 | req = nfs_list_entry(data->pages.next); | 1055 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
1056 | struct page *page = req->wb_page; | ||
1057 | |||
1040 | nfs_list_remove_request(req); | 1058 | nfs_list_remove_request(req); |
1041 | page = req->wb_page; | ||
1042 | 1059 | ||
1043 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 1060 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
1044 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 1061 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -1046,10 +1063,10 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1046 | req->wb_bytes, | 1063 | req->wb_bytes, |
1047 | (long long)req_offset(req)); | 1064 | (long long)req_offset(req)); |
1048 | 1065 | ||
1049 | if (task->tk_status < 0) { | 1066 | if (status < 0) { |
1050 | nfs_set_pageerror(page); | 1067 | nfs_set_pageerror(page); |
1051 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1068 | nfs_context_set_write_error(req->wb_context, status); |
1052 | dprintk(", error = %d\n", task->tk_status); | 1069 | dprintk(", error = %d\n", status); |
1053 | goto remove_request; | 1070 | goto remove_request; |
1054 | } | 1071 | } |
1055 | 1072 | ||
@@ -1069,11 +1086,12 @@ remove_request: | |||
1069 | next: | 1086 | next: |
1070 | nfs_clear_page_tag_locked(req); | 1087 | nfs_clear_page_tag_locked(req); |
1071 | } | 1088 | } |
1089 | nfs_writedata_release(calldata); | ||
1072 | } | 1090 | } |
1073 | 1091 | ||
1074 | static const struct rpc_call_ops nfs_write_full_ops = { | 1092 | static const struct rpc_call_ops nfs_write_full_ops = { |
1075 | .rpc_call_done = nfs_writeback_done_full, | 1093 | .rpc_call_done = nfs_writeback_done_full, |
1076 | .rpc_release = nfs_writedata_release, | 1094 | .rpc_release = nfs_writeback_release_full, |
1077 | }; | 1095 | }; |
1078 | 1096 | ||
1079 | 1097 | ||
@@ -1159,15 +1177,18 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1159 | 1177 | ||
1160 | 1178 | ||
1161 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1179 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1162 | void nfs_commit_release(void *wdata) | 1180 | void nfs_commitdata_release(void *data) |
1163 | { | 1181 | { |
1182 | struct nfs_write_data *wdata = data; | ||
1183 | |||
1184 | put_nfs_open_context(wdata->args.context); | ||
1164 | nfs_commit_free(wdata); | 1185 | nfs_commit_free(wdata); |
1165 | } | 1186 | } |
1166 | 1187 | ||
1167 | /* | 1188 | /* |
1168 | * Set up the argument/result storage required for the RPC call. | 1189 | * Set up the argument/result storage required for the RPC call. |
1169 | */ | 1190 | */ |
1170 | static void nfs_commit_rpcsetup(struct list_head *head, | 1191 | static int nfs_commit_rpcsetup(struct list_head *head, |
1171 | struct nfs_write_data *data, | 1192 | struct nfs_write_data *data, |
1172 | int how) | 1193 | int how) |
1173 | { | 1194 | { |
@@ -1187,6 +1208,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1187 | .rpc_message = &msg, | 1208 | .rpc_message = &msg, |
1188 | .callback_ops = &nfs_commit_ops, | 1209 | .callback_ops = &nfs_commit_ops, |
1189 | .callback_data = data, | 1210 | .callback_data = data, |
1211 | .workqueue = nfsiod_workqueue, | ||
1190 | .flags = flags, | 1212 | .flags = flags, |
1191 | .priority = priority, | 1213 | .priority = priority, |
1192 | }; | 1214 | }; |
@@ -1203,6 +1225,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1203 | /* Note: we always request a commit of the entire inode */ | 1225 | /* Note: we always request a commit of the entire inode */ |
1204 | data->args.offset = 0; | 1226 | data->args.offset = 0; |
1205 | data->args.count = 0; | 1227 | data->args.count = 0; |
1228 | data->args.context = get_nfs_open_context(first->wb_context); | ||
1206 | data->res.count = 0; | 1229 | data->res.count = 0; |
1207 | data->res.fattr = &data->fattr; | 1230 | data->res.fattr = &data->fattr; |
1208 | data->res.verf = &data->verf; | 1231 | data->res.verf = &data->verf; |
@@ -1214,8 +1237,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1214 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1237 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1215 | 1238 | ||
1216 | task = rpc_run_task(&task_setup_data); | 1239 | task = rpc_run_task(&task_setup_data); |
1217 | if (!IS_ERR(task)) | 1240 | if (IS_ERR(task)) |
1218 | rpc_put_task(task); | 1241 | return PTR_ERR(task); |
1242 | rpc_put_task(task); | ||
1243 | return 0; | ||
1219 | } | 1244 | } |
1220 | 1245 | ||
1221 | /* | 1246 | /* |
@@ -1227,15 +1252,13 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1227 | struct nfs_write_data *data; | 1252 | struct nfs_write_data *data; |
1228 | struct nfs_page *req; | 1253 | struct nfs_page *req; |
1229 | 1254 | ||
1230 | data = nfs_commit_alloc(); | 1255 | data = nfs_commitdata_alloc(); |
1231 | 1256 | ||
1232 | if (!data) | 1257 | if (!data) |
1233 | goto out_bad; | 1258 | goto out_bad; |
1234 | 1259 | ||
1235 | /* Set up the argument struct */ | 1260 | /* Set up the argument struct */ |
1236 | nfs_commit_rpcsetup(head, data, how); | 1261 | return nfs_commit_rpcsetup(head, data, how); |
1237 | |||
1238 | return 0; | ||
1239 | out_bad: | 1262 | out_bad: |
1240 | while (!list_empty(head)) { | 1263 | while (!list_empty(head)) { |
1241 | req = nfs_list_entry(head->next); | 1264 | req = nfs_list_entry(head->next); |
@@ -1255,7 +1278,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1255 | static void nfs_commit_done(struct rpc_task *task, void *calldata) | 1278 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1256 | { | 1279 | { |
1257 | struct nfs_write_data *data = calldata; | 1280 | struct nfs_write_data *data = calldata; |
1258 | struct nfs_page *req; | ||
1259 | 1281 | ||
1260 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", | 1282 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1261 | task->tk_pid, task->tk_status); | 1283 | task->tk_pid, task->tk_status); |
@@ -1263,6 +1285,13 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1263 | /* Call the NFS version-specific code */ | 1285 | /* Call the NFS version-specific code */ |
1264 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 1286 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) |
1265 | return; | 1287 | return; |
1288 | } | ||
1289 | |||
1290 | static void nfs_commit_release(void *calldata) | ||
1291 | { | ||
1292 | struct nfs_write_data *data = calldata; | ||
1293 | struct nfs_page *req; | ||
1294 | int status = data->task.tk_status; | ||
1266 | 1295 | ||
1267 | while (!list_empty(&data->pages)) { | 1296 | while (!list_empty(&data->pages)) { |
1268 | req = nfs_list_entry(data->pages.next); | 1297 | req = nfs_list_entry(data->pages.next); |
@@ -1277,10 +1306,10 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1277 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | 1306 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
1278 | req->wb_bytes, | 1307 | req->wb_bytes, |
1279 | (long long)req_offset(req)); | 1308 | (long long)req_offset(req)); |
1280 | if (task->tk_status < 0) { | 1309 | if (status < 0) { |
1281 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1310 | nfs_context_set_write_error(req->wb_context, status); |
1282 | nfs_inode_remove_request(req); | 1311 | nfs_inode_remove_request(req); |
1283 | dprintk(", error = %d\n", task->tk_status); | 1312 | dprintk(", error = %d\n", status); |
1284 | goto next; | 1313 | goto next; |
1285 | } | 1314 | } |
1286 | 1315 | ||
@@ -1297,10 +1326,11 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1297 | } | 1326 | } |
1298 | /* We have a mismatch. Write the page again */ | 1327 | /* We have a mismatch. Write the page again */ |
1299 | dprintk(" mismatch\n"); | 1328 | dprintk(" mismatch\n"); |
1300 | nfs_redirty_request(req); | 1329 | nfs_mark_request_dirty(req); |
1301 | next: | 1330 | next: |
1302 | nfs_clear_page_tag_locked(req); | 1331 | nfs_clear_page_tag_locked(req); |
1303 | } | 1332 | } |
1333 | nfs_commitdata_release(calldata); | ||
1304 | } | 1334 | } |
1305 | 1335 | ||
1306 | static const struct rpc_call_ops nfs_commit_ops = { | 1336 | static const struct rpc_call_ops nfs_commit_ops = { |
@@ -1487,18 +1517,19 @@ static int nfs_wb_page_priority(struct inode *inode, struct page *page, | |||
1487 | }; | 1517 | }; |
1488 | int ret; | 1518 | int ret; |
1489 | 1519 | ||
1490 | BUG_ON(!PageLocked(page)); | 1520 | do { |
1491 | if (clear_page_dirty_for_io(page)) { | 1521 | if (clear_page_dirty_for_io(page)) { |
1492 | ret = nfs_writepage_locked(page, &wbc); | 1522 | ret = nfs_writepage_locked(page, &wbc); |
1523 | if (ret < 0) | ||
1524 | goto out_error; | ||
1525 | } else if (!PagePrivate(page)) | ||
1526 | break; | ||
1527 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1493 | if (ret < 0) | 1528 | if (ret < 0) |
1494 | goto out; | 1529 | goto out_error; |
1495 | } | 1530 | } while (PagePrivate(page)); |
1496 | if (!PagePrivate(page)) | 1531 | return 0; |
1497 | return 0; | 1532 | out_error: |
1498 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1499 | if (ret >= 0) | ||
1500 | return 0; | ||
1501 | out: | ||
1502 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | 1533 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
1503 | return ret; | 1534 | return ret; |
1504 | } | 1535 | } |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 4babb2a129ac..94649a8da014 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -91,6 +91,7 @@ struct nlm_wait; | |||
91 | */ | 91 | */ |
92 | #define NLMCLNT_OHSIZE ((__NEW_UTS_LEN) + 10u) | 92 | #define NLMCLNT_OHSIZE ((__NEW_UTS_LEN) + 10u) |
93 | struct nlm_rqst { | 93 | struct nlm_rqst { |
94 | atomic_t a_count; | ||
94 | unsigned int a_flags; /* initial RPC task flags */ | 95 | unsigned int a_flags; /* initial RPC task flags */ |
95 | struct nlm_host * a_host; /* host handle */ | 96 | struct nlm_host * a_host; /* host handle */ |
96 | struct nlm_args a_args; /* arguments */ | 97 | struct nlm_args a_args; /* arguments */ |
@@ -173,8 +174,10 @@ void nlmclnt_next_cookie(struct nlm_cookie *); | |||
173 | /* | 174 | /* |
174 | * Host cache | 175 | * Host cache |
175 | */ | 176 | */ |
176 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *, int, int, | 177 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin, |
177 | const char *, unsigned int); | 178 | int proto, u32 version, |
179 | const char *hostname, | ||
180 | unsigned int hostname_len); | ||
178 | struct nlm_host *nlmsvc_lookup_host(struct svc_rqst *, const char *, | 181 | struct nlm_host *nlmsvc_lookup_host(struct svc_rqst *, const char *, |
179 | unsigned int); | 182 | unsigned int); |
180 | struct rpc_clnt * nlm_bind_host(struct nlm_host *); | 183 | struct rpc_clnt * nlm_bind_host(struct nlm_host *); |
@@ -217,8 +220,7 @@ void nlmsvc_mark_resources(void); | |||
217 | void nlmsvc_free_host_resources(struct nlm_host *); | 220 | void nlmsvc_free_host_resources(struct nlm_host *); |
218 | void nlmsvc_invalidate_all(void); | 221 | void nlmsvc_invalidate_all(void); |
219 | 222 | ||
220 | static __inline__ struct inode * | 223 | static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) |
221 | nlmsvc_file_inode(struct nlm_file *file) | ||
222 | { | 224 | { |
223 | return file->f_file->f_path.dentry->d_inode; | 225 | return file->f_file->f_path.dentry->d_inode; |
224 | } | 226 | } |
@@ -226,8 +228,8 @@ nlmsvc_file_inode(struct nlm_file *file) | |||
226 | /* | 228 | /* |
227 | * Compare two host addresses (needs modifying for ipv6) | 229 | * Compare two host addresses (needs modifying for ipv6) |
228 | */ | 230 | */ |
229 | static __inline__ int | 231 | static inline int nlm_cmp_addr(const struct sockaddr_in *sin1, |
230 | nlm_cmp_addr(const struct sockaddr_in *sin1, const struct sockaddr_in *sin2) | 232 | const struct sockaddr_in *sin2) |
231 | { | 233 | { |
232 | return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; | 234 | return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; |
233 | } | 235 | } |
@@ -236,8 +238,8 @@ nlm_cmp_addr(const struct sockaddr_in *sin1, const struct sockaddr_in *sin2) | |||
236 | * Compare two NLM locks. | 238 | * Compare two NLM locks. |
237 | * When the second lock is of type F_UNLCK, this acts like a wildcard. | 239 | * When the second lock is of type F_UNLCK, this acts like a wildcard. |
238 | */ | 240 | */ |
239 | static __inline__ int | 241 | static inline int nlm_compare_locks(const struct file_lock *fl1, |
240 | nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2) | 242 | const struct file_lock *fl2) |
241 | { | 243 | { |
242 | return fl1->fl_pid == fl2->fl_pid | 244 | return fl1->fl_pid == fl2->fl_pid |
243 | && fl1->fl_owner == fl2->fl_owner | 245 | && fl1->fl_owner == fl2->fl_owner |
diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h index 22a645828f26..5a5448bdb17d 100644 --- a/include/linux/lockd/sm_inter.h +++ b/include/linux/lockd/sm_inter.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #define SM_NOTIFY 6 | 19 | #define SM_NOTIFY 6 |
20 | 20 | ||
21 | #define SM_MAXSTRLEN 1024 | 21 | #define SM_MAXSTRLEN 1024 |
22 | #define SM_PRIV_SIZE 16 | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * Arguments for all calls to statd | 25 | * Arguments for all calls to statd |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f4a0e4c218df..27d6a8d98cef 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -430,7 +430,6 @@ extern void nfs_unregister_sysctl(void); | |||
430 | /* | 430 | /* |
431 | * linux/fs/nfs/namespace.c | 431 | * linux/fs/nfs/namespace.c |
432 | */ | 432 | */ |
433 | extern struct list_head nfs_automount_list; | ||
434 | extern const struct inode_operations nfs_mountpoint_inode_operations; | 433 | extern const struct inode_operations nfs_mountpoint_inode_operations; |
435 | extern const struct inode_operations nfs_referral_inode_operations; | 434 | extern const struct inode_operations nfs_referral_inode_operations; |
436 | extern int nfs_mountpoint_expiry_timeout; | 435 | extern int nfs_mountpoint_expiry_timeout; |
@@ -466,9 +465,9 @@ extern int nfs_wb_page(struct inode *inode, struct page* page); | |||
466 | extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); | 465 | extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); |
467 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 466 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
468 | extern int nfs_commit_inode(struct inode *, int); | 467 | extern int nfs_commit_inode(struct inode *, int); |
469 | extern struct nfs_write_data *nfs_commit_alloc(void); | 468 | extern struct nfs_write_data *nfs_commitdata_alloc(void); |
470 | extern void nfs_commit_free(struct nfs_write_data *wdata); | 469 | extern void nfs_commit_free(struct nfs_write_data *wdata); |
471 | extern void nfs_commit_release(void *wdata); | 470 | extern void nfs_commitdata_release(void *wdata); |
472 | #else | 471 | #else |
473 | static inline int | 472 | static inline int |
474 | nfs_commit_inode(struct inode *inode, int how) | 473 | nfs_commit_inode(struct inode *inode, int how) |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 3423c6761bf7..c9beacd16c00 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -32,6 +32,8 @@ struct nfs_client { | |||
32 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ | 32 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ |
33 | int cl_proto; /* Network transport protocol */ | 33 | int cl_proto; /* Network transport protocol */ |
34 | 34 | ||
35 | struct rpc_cred *cl_machine_cred; | ||
36 | |||
35 | #ifdef CONFIG_NFS_V4 | 37 | #ifdef CONFIG_NFS_V4 |
36 | u64 cl_clientid; /* constant */ | 38 | u64 cl_clientid; /* constant */ |
37 | nfs4_verifier cl_confirm; | 39 | nfs4_verifier cl_confirm; |
@@ -93,6 +95,7 @@ struct nfs_server { | |||
93 | unsigned int wpages; /* write size (in pages) */ | 95 | unsigned int wpages; /* write size (in pages) */ |
94 | unsigned int wtmult; /* server disk block size */ | 96 | unsigned int wtmult; /* server disk block size */ |
95 | unsigned int dtsize; /* readdir size */ | 97 | unsigned int dtsize; /* readdir size */ |
98 | unsigned short port; /* "port=" setting */ | ||
96 | unsigned int bsize; /* server block size */ | 99 | unsigned int bsize; /* server block size */ |
97 | unsigned int acregmin; /* attr cache timeouts */ | 100 | unsigned int acregmin; /* attr cache timeouts */ |
98 | unsigned int acregmax; | 101 | unsigned int acregmax; |
@@ -117,6 +120,13 @@ struct nfs_server { | |||
117 | 120 | ||
118 | atomic_t active; /* Keep trace of any activity to this server */ | 121 | atomic_t active; /* Keep trace of any activity to this server */ |
119 | wait_queue_head_t active_wq; /* Wait for any activity to stop */ | 122 | wait_queue_head_t active_wq; /* Wait for any activity to stop */ |
123 | |||
124 | /* mountd-related mount options */ | ||
125 | struct sockaddr_storage mountd_address; | ||
126 | size_t mountd_addrlen; | ||
127 | u32 mountd_version; | ||
128 | unsigned short mountd_port; | ||
129 | unsigned short mountd_protocol; | ||
120 | }; | 130 | }; |
121 | 131 | ||
122 | /* Server capabilities */ | 132 | /* Server capabilities */ |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index f301d0b8babc..24263bb8e0be 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -140,6 +140,7 @@ struct nfs_openres { | |||
140 | __u32 rflags; | 140 | __u32 rflags; |
141 | struct nfs_fattr * f_attr; | 141 | struct nfs_fattr * f_attr; |
142 | struct nfs_fattr * dir_attr; | 142 | struct nfs_fattr * dir_attr; |
143 | struct nfs_seqid * seqid; | ||
143 | const struct nfs_server *server; | 144 | const struct nfs_server *server; |
144 | int delegation_type; | 145 | int delegation_type; |
145 | nfs4_stateid delegation; | 146 | nfs4_stateid delegation; |
@@ -159,6 +160,7 @@ struct nfs_open_confirmargs { | |||
159 | 160 | ||
160 | struct nfs_open_confirmres { | 161 | struct nfs_open_confirmres { |
161 | nfs4_stateid stateid; | 162 | nfs4_stateid stateid; |
163 | struct nfs_seqid * seqid; | ||
162 | }; | 164 | }; |
163 | 165 | ||
164 | /* | 166 | /* |
@@ -175,6 +177,7 @@ struct nfs_closeargs { | |||
175 | struct nfs_closeres { | 177 | struct nfs_closeres { |
176 | nfs4_stateid stateid; | 178 | nfs4_stateid stateid; |
177 | struct nfs_fattr * fattr; | 179 | struct nfs_fattr * fattr; |
180 | struct nfs_seqid * seqid; | ||
178 | const struct nfs_server *server; | 181 | const struct nfs_server *server; |
179 | }; | 182 | }; |
180 | /* | 183 | /* |
@@ -199,7 +202,9 @@ struct nfs_lock_args { | |||
199 | }; | 202 | }; |
200 | 203 | ||
201 | struct nfs_lock_res { | 204 | struct nfs_lock_res { |
202 | nfs4_stateid stateid; | 205 | nfs4_stateid stateid; |
206 | struct nfs_seqid * lock_seqid; | ||
207 | struct nfs_seqid * open_seqid; | ||
203 | }; | 208 | }; |
204 | 209 | ||
205 | struct nfs_locku_args { | 210 | struct nfs_locku_args { |
@@ -210,7 +215,8 @@ struct nfs_locku_args { | |||
210 | }; | 215 | }; |
211 | 216 | ||
212 | struct nfs_locku_res { | 217 | struct nfs_locku_res { |
213 | nfs4_stateid stateid; | 218 | nfs4_stateid stateid; |
219 | struct nfs_seqid * seqid; | ||
214 | }; | 220 | }; |
215 | 221 | ||
216 | struct nfs_lockt_args { | 222 | struct nfs_lockt_args { |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 7a69ca3bebaf..3f632182d8eb 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -26,6 +26,7 @@ struct auth_cred { | |||
26 | uid_t uid; | 26 | uid_t uid; |
27 | gid_t gid; | 27 | gid_t gid; |
28 | struct group_info *group_info; | 28 | struct group_info *group_info; |
29 | unsigned char machine_cred : 1; | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | /* | 32 | /* |
@@ -59,8 +60,8 @@ struct rpc_cred { | |||
59 | /* | 60 | /* |
60 | * Client authentication handle | 61 | * Client authentication handle |
61 | */ | 62 | */ |
62 | #define RPC_CREDCACHE_NR 8 | 63 | #define RPC_CREDCACHE_HASHBITS 4 |
63 | #define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1) | 64 | #define RPC_CREDCACHE_NR (1 << RPC_CREDCACHE_HASHBITS) |
64 | struct rpc_cred_cache { | 65 | struct rpc_cred_cache { |
65 | struct hlist_head hashtable[RPC_CREDCACHE_NR]; | 66 | struct hlist_head hashtable[RPC_CREDCACHE_NR]; |
66 | spinlock_t lock; | 67 | spinlock_t lock; |
@@ -89,7 +90,6 @@ struct rpc_auth { | |||
89 | 90 | ||
90 | /* Flags for rpcauth_lookupcred() */ | 91 | /* Flags for rpcauth_lookupcred() */ |
91 | #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ | 92 | #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ |
92 | #define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */ | ||
93 | 93 | ||
94 | /* | 94 | /* |
95 | * Client authentication ops | 95 | * Client authentication ops |
@@ -97,9 +97,7 @@ struct rpc_auth { | |||
97 | struct rpc_authops { | 97 | struct rpc_authops { |
98 | struct module *owner; | 98 | struct module *owner; |
99 | rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ | 99 | rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ |
100 | #ifdef RPC_DEBUG | ||
101 | char * au_name; | 100 | char * au_name; |
102 | #endif | ||
103 | struct rpc_auth * (*create)(struct rpc_clnt *, rpc_authflavor_t); | 101 | struct rpc_auth * (*create)(struct rpc_clnt *, rpc_authflavor_t); |
104 | void (*destroy)(struct rpc_auth *); | 102 | void (*destroy)(struct rpc_auth *); |
105 | 103 | ||
@@ -113,6 +111,7 @@ struct rpc_credops { | |||
113 | void (*crdestroy)(struct rpc_cred *); | 111 | void (*crdestroy)(struct rpc_cred *); |
114 | 112 | ||
115 | int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); | 113 | int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); |
114 | void (*crbind)(struct rpc_task *, struct rpc_cred *); | ||
116 | __be32 * (*crmarshal)(struct rpc_task *, __be32 *); | 115 | __be32 * (*crmarshal)(struct rpc_task *, __be32 *); |
117 | int (*crrefresh)(struct rpc_task *); | 116 | int (*crrefresh)(struct rpc_task *); |
118 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); | 117 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); |
@@ -126,9 +125,13 @@ extern const struct rpc_authops authunix_ops; | |||
126 | extern const struct rpc_authops authnull_ops; | 125 | extern const struct rpc_authops authnull_ops; |
127 | 126 | ||
128 | void __init rpc_init_authunix(void); | 127 | void __init rpc_init_authunix(void); |
128 | void __init rpc_init_generic_auth(void); | ||
129 | void __init rpcauth_init_module(void); | 129 | void __init rpcauth_init_module(void); |
130 | void __exit rpcauth_remove_module(void); | 130 | void __exit rpcauth_remove_module(void); |
131 | void __exit rpc_destroy_generic_auth(void); | ||
131 | 132 | ||
133 | struct rpc_cred * rpc_lookup_cred(void); | ||
134 | struct rpc_cred * rpc_lookup_machine_cred(void); | ||
132 | int rpcauth_register(const struct rpc_authops *); | 135 | int rpcauth_register(const struct rpc_authops *); |
133 | int rpcauth_unregister(const struct rpc_authops *); | 136 | int rpcauth_unregister(const struct rpc_authops *); |
134 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); | 137 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); |
@@ -136,8 +139,8 @@ void rpcauth_release(struct rpc_auth *); | |||
136 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | 139 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); |
137 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | 140 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); |
138 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); | 141 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); |
139 | struct rpc_cred * rpcauth_bindcred(struct rpc_task *); | 142 | void rpcauth_bindcred(struct rpc_task *, struct rpc_cred *, int); |
140 | void rpcauth_holdcred(struct rpc_task *); | 143 | void rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *); |
141 | void put_rpccred(struct rpc_cred *); | 144 | void put_rpccred(struct rpc_cred *); |
142 | void rpcauth_unbindcred(struct rpc_task *); | 145 | void rpcauth_unbindcred(struct rpc_task *); |
143 | __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); | 146 | __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); |
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index 67658e17a375..fec6899bf355 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h | |||
@@ -84,6 +84,7 @@ struct gss_cred { | |||
84 | enum rpc_gss_svc gc_service; | 84 | enum rpc_gss_svc gc_service; |
85 | struct gss_cl_ctx *gc_ctx; | 85 | struct gss_cl_ctx *gc_ctx; |
86 | struct gss_upcall_msg *gc_upcall; | 86 | struct gss_upcall_msg *gc_upcall; |
87 | unsigned char gc_machine_cred : 1; | ||
87 | }; | 88 | }; |
88 | 89 | ||
89 | #endif /* __KERNEL__ */ | 90 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 129a86e25d29..6fff7f82ef12 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -127,11 +127,12 @@ int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int); | |||
127 | void rpcb_getport_async(struct rpc_task *); | 127 | void rpcb_getport_async(struct rpc_task *); |
128 | 128 | ||
129 | void rpc_call_start(struct rpc_task *); | 129 | void rpc_call_start(struct rpc_task *); |
130 | int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, | 130 | int rpc_call_async(struct rpc_clnt *clnt, |
131 | int flags, const struct rpc_call_ops *tk_ops, | 131 | const struct rpc_message *msg, int flags, |
132 | const struct rpc_call_ops *tk_ops, | ||
132 | void *calldata); | 133 | void *calldata); |
133 | int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, | 134 | int rpc_call_sync(struct rpc_clnt *clnt, |
134 | int flags); | 135 | const struct rpc_message *msg, int flags); |
135 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, | 136 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, |
136 | int flags); | 137 | int flags); |
137 | void rpc_restart_call(struct rpc_task *); | 138 | void rpc_restart_call(struct rpc_task *); |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index f689f02e6793..d1a5c8c1a0f1 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -11,7 +11,6 @@ | |||
11 | 11 | ||
12 | #include <linux/timer.h> | 12 | #include <linux/timer.h> |
13 | #include <linux/sunrpc/types.h> | 13 | #include <linux/sunrpc/types.h> |
14 | #include <linux/rcupdate.h> | ||
15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
16 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
17 | #include <linux/workqueue.h> | 16 | #include <linux/workqueue.h> |
@@ -33,7 +32,8 @@ struct rpc_wait_queue; | |||
33 | struct rpc_wait { | 32 | struct rpc_wait { |
34 | struct list_head list; /* wait queue links */ | 33 | struct list_head list; /* wait queue links */ |
35 | struct list_head links; /* Links to related tasks */ | 34 | struct list_head links; /* Links to related tasks */ |
36 | struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */ | 35 | struct list_head timer_list; /* Timer list */ |
36 | unsigned long expires; | ||
37 | }; | 37 | }; |
38 | 38 | ||
39 | /* | 39 | /* |
@@ -57,33 +57,25 @@ struct rpc_task { | |||
57 | __u8 tk_cred_retry; | 57 | __u8 tk_cred_retry; |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * timeout_fn to be executed by timer bottom half | ||
61 | * callback to be executed after waking up | 60 | * callback to be executed after waking up |
62 | * action next procedure for async tasks | 61 | * action next procedure for async tasks |
63 | * tk_ops caller callbacks | 62 | * tk_ops caller callbacks |
64 | */ | 63 | */ |
65 | void (*tk_timeout_fn)(struct rpc_task *); | ||
66 | void (*tk_callback)(struct rpc_task *); | 64 | void (*tk_callback)(struct rpc_task *); |
67 | void (*tk_action)(struct rpc_task *); | 65 | void (*tk_action)(struct rpc_task *); |
68 | const struct rpc_call_ops *tk_ops; | 66 | const struct rpc_call_ops *tk_ops; |
69 | void * tk_calldata; | 67 | void * tk_calldata; |
70 | 68 | ||
71 | /* | ||
72 | * tk_timer is used for async processing by the RPC scheduling | ||
73 | * primitives. You should not access this directly unless | ||
74 | * you have a pathological interest in kernel oopses. | ||
75 | */ | ||
76 | struct timer_list tk_timer; /* kernel timer */ | ||
77 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ | 69 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ |
78 | unsigned short tk_flags; /* misc flags */ | 70 | unsigned short tk_flags; /* misc flags */ |
79 | unsigned long tk_runstate; /* Task run status */ | 71 | unsigned long tk_runstate; /* Task run status */ |
80 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could | 72 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could |
81 | * be any workqueue | 73 | * be any workqueue |
82 | */ | 74 | */ |
75 | struct rpc_wait_queue *tk_waitqueue; /* RPC wait queue we're on */ | ||
83 | union { | 76 | union { |
84 | struct work_struct tk_work; /* Async task work queue */ | 77 | struct work_struct tk_work; /* Async task work queue */ |
85 | struct rpc_wait tk_wait; /* RPC wait */ | 78 | struct rpc_wait tk_wait; /* RPC wait */ |
86 | struct rcu_head tk_rcu; /* for task deletion */ | ||
87 | } u; | 79 | } u; |
88 | 80 | ||
89 | unsigned short tk_timeouts; /* maj timeouts */ | 81 | unsigned short tk_timeouts; /* maj timeouts */ |
@@ -123,6 +115,7 @@ struct rpc_task_setup { | |||
123 | const struct rpc_message *rpc_message; | 115 | const struct rpc_message *rpc_message; |
124 | const struct rpc_call_ops *callback_ops; | 116 | const struct rpc_call_ops *callback_ops; |
125 | void *callback_data; | 117 | void *callback_data; |
118 | struct workqueue_struct *workqueue; | ||
126 | unsigned short flags; | 119 | unsigned short flags; |
127 | signed char priority; | 120 | signed char priority; |
128 | }; | 121 | }; |
@@ -147,9 +140,7 @@ struct rpc_task_setup { | |||
147 | 140 | ||
148 | #define RPC_TASK_RUNNING 0 | 141 | #define RPC_TASK_RUNNING 0 |
149 | #define RPC_TASK_QUEUED 1 | 142 | #define RPC_TASK_QUEUED 1 |
150 | #define RPC_TASK_WAKEUP 2 | 143 | #define RPC_TASK_ACTIVE 2 |
151 | #define RPC_TASK_HAS_TIMER 3 | ||
152 | #define RPC_TASK_ACTIVE 4 | ||
153 | 144 | ||
154 | #define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) | 145 | #define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) |
155 | #define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) | 146 | #define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) |
@@ -171,15 +162,6 @@ struct rpc_task_setup { | |||
171 | smp_mb__after_clear_bit(); \ | 162 | smp_mb__after_clear_bit(); \ |
172 | } while (0) | 163 | } while (0) |
173 | 164 | ||
174 | #define rpc_start_wakeup(t) \ | ||
175 | (test_and_set_bit(RPC_TASK_WAKEUP, &(t)->tk_runstate) == 0) | ||
176 | #define rpc_finish_wakeup(t) \ | ||
177 | do { \ | ||
178 | smp_mb__before_clear_bit(); \ | ||
179 | clear_bit(RPC_TASK_WAKEUP, &(t)->tk_runstate); \ | ||
180 | smp_mb__after_clear_bit(); \ | ||
181 | } while (0) | ||
182 | |||
183 | #define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate) | 165 | #define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate) |
184 | 166 | ||
185 | /* | 167 | /* |
@@ -192,6 +174,12 @@ struct rpc_task_setup { | |||
192 | #define RPC_PRIORITY_HIGH (1) | 174 | #define RPC_PRIORITY_HIGH (1) |
193 | #define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) | 175 | #define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) |
194 | 176 | ||
177 | struct rpc_timer { | ||
178 | struct timer_list timer; | ||
179 | struct list_head list; | ||
180 | unsigned long expires; | ||
181 | }; | ||
182 | |||
195 | /* | 183 | /* |
196 | * RPC synchronization objects | 184 | * RPC synchronization objects |
197 | */ | 185 | */ |
@@ -204,6 +192,7 @@ struct rpc_wait_queue { | |||
204 | unsigned char count; /* # task groups remaining serviced so far */ | 192 | unsigned char count; /* # task groups remaining serviced so far */ |
205 | unsigned char nr; /* # tasks remaining for cookie */ | 193 | unsigned char nr; /* # tasks remaining for cookie */ |
206 | unsigned short qlen; /* total # tasks waiting in queue */ | 194 | unsigned short qlen; /* total # tasks waiting in queue */ |
195 | struct rpc_timer timer_list; | ||
207 | #ifdef RPC_DEBUG | 196 | #ifdef RPC_DEBUG |
208 | const char * name; | 197 | const char * name; |
209 | #endif | 198 | #endif |
@@ -229,9 +218,11 @@ void rpc_killall_tasks(struct rpc_clnt *); | |||
229 | void rpc_execute(struct rpc_task *); | 218 | void rpc_execute(struct rpc_task *); |
230 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); | 219 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); |
231 | void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); | 220 | void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); |
221 | void rpc_destroy_wait_queue(struct rpc_wait_queue *); | ||
232 | void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, | 222 | void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, |
233 | rpc_action action, rpc_action timer); | 223 | rpc_action action); |
234 | void rpc_wake_up_task(struct rpc_task *); | 224 | void rpc_wake_up_queued_task(struct rpc_wait_queue *, |
225 | struct rpc_task *); | ||
235 | void rpc_wake_up(struct rpc_wait_queue *); | 226 | void rpc_wake_up(struct rpc_wait_queue *); |
236 | struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); | 227 | struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); |
237 | void rpc_wake_up_status(struct rpc_wait_queue *, int); | 228 | void rpc_wake_up_status(struct rpc_wait_queue *, int); |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b3ff9a815e6f..4d80a118d538 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -86,6 +86,10 @@ struct rpc_rqst { | |||
86 | unsigned long rq_majortimeo; /* major timeout alarm */ | 86 | unsigned long rq_majortimeo; /* major timeout alarm */ |
87 | unsigned long rq_timeout; /* Current timeout value */ | 87 | unsigned long rq_timeout; /* Current timeout value */ |
88 | unsigned int rq_retries; /* # of retries */ | 88 | unsigned int rq_retries; /* # of retries */ |
89 | unsigned int rq_connect_cookie; | ||
90 | /* A cookie used to track the | ||
91 | state of the transport | ||
92 | connection */ | ||
89 | 93 | ||
90 | /* | 94 | /* |
91 | * Partial send handling | 95 | * Partial send handling |
@@ -152,6 +156,9 @@ struct rpc_xprt { | |||
152 | unsigned long connect_timeout, | 156 | unsigned long connect_timeout, |
153 | bind_timeout, | 157 | bind_timeout, |
154 | reestablish_timeout; | 158 | reestablish_timeout; |
159 | unsigned int connect_cookie; /* A cookie that gets bumped | ||
160 | every time the transport | ||
161 | is reconnected */ | ||
155 | 162 | ||
156 | /* | 163 | /* |
157 | * Disconnection of idle transports | 164 | * Disconnection of idle transports |
@@ -232,7 +239,7 @@ int xprt_unregister_transport(struct xprt_class *type); | |||
232 | void xprt_set_retrans_timeout_def(struct rpc_task *task); | 239 | void xprt_set_retrans_timeout_def(struct rpc_task *task); |
233 | void xprt_set_retrans_timeout_rtt(struct rpc_task *task); | 240 | void xprt_set_retrans_timeout_rtt(struct rpc_task *task); |
234 | void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); | 241 | void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); |
235 | void xprt_wait_for_buffer_space(struct rpc_task *task); | 242 | void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action); |
236 | void xprt_write_space(struct rpc_xprt *xprt); | 243 | void xprt_write_space(struct rpc_xprt *xprt); |
237 | void xprt_update_rtt(struct rpc_task *task); | 244 | void xprt_update_rtt(struct rpc_task *task); |
238 | void xprt_adjust_cwnd(struct rpc_task *task, int result); | 245 | void xprt_adjust_cwnd(struct rpc_task *task, int result); |
@@ -241,6 +248,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied); | |||
241 | void xprt_release_rqst_cong(struct rpc_task *task); | 248 | void xprt_release_rqst_cong(struct rpc_task *task); |
242 | void xprt_disconnect_done(struct rpc_xprt *xprt); | 249 | void xprt_disconnect_done(struct rpc_xprt *xprt); |
243 | void xprt_force_disconnect(struct rpc_xprt *xprt); | 250 | void xprt_force_disconnect(struct rpc_xprt *xprt); |
251 | void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); | ||
244 | 252 | ||
245 | /* | 253 | /* |
246 | * Reserved bit positions in xprt->state | 254 | * Reserved bit positions in xprt->state |
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 92e1dbe50947..5369aa369b35 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile | |||
@@ -8,7 +8,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_gss/ | |||
8 | obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/ | 8 | obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/ |
9 | 9 | ||
10 | sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ | 10 | sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ |
11 | auth.o auth_null.o auth_unix.o \ | 11 | auth.o auth_null.o auth_unix.o auth_generic.o \ |
12 | svc.o svcsock.o svcauth.o svcauth_unix.o \ | 12 | svc.o svcsock.o svcauth.o svcauth_unix.o \ |
13 | rpcb_clnt.o timer.o xdr.o \ | 13 | rpcb_clnt.o timer.o xdr.o \ |
14 | sunrpc_syms.o cache.o rpc_pipe.o \ | 14 | sunrpc_syms.o cache.o rpc_pipe.o \ |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index eca941ce298b..6bfea9ed6869 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/hash.h> | ||
14 | #include <linux/sunrpc/clnt.h> | 15 | #include <linux/sunrpc/clnt.h> |
15 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
16 | 17 | ||
@@ -219,6 +220,9 @@ rpcauth_destroy_credcache(struct rpc_auth *auth) | |||
219 | } | 220 | } |
220 | EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache); | 221 | EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache); |
221 | 222 | ||
223 | |||
224 | #define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ) | ||
225 | |||
222 | /* | 226 | /* |
223 | * Remove stale credentials. Avoid sleeping inside the loop. | 227 | * Remove stale credentials. Avoid sleeping inside the loop. |
224 | */ | 228 | */ |
@@ -227,6 +231,7 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
227 | { | 231 | { |
228 | spinlock_t *cache_lock; | 232 | spinlock_t *cache_lock; |
229 | struct rpc_cred *cred; | 233 | struct rpc_cred *cred; |
234 | unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM; | ||
230 | 235 | ||
231 | while (!list_empty(&cred_unused)) { | 236 | while (!list_empty(&cred_unused)) { |
232 | cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); | 237 | cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); |
@@ -234,6 +239,10 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
234 | number_cred_unused--; | 239 | number_cred_unused--; |
235 | if (atomic_read(&cred->cr_count) != 0) | 240 | if (atomic_read(&cred->cr_count) != 0) |
236 | continue; | 241 | continue; |
242 | /* Enforce a 5 second garbage collection moratorium */ | ||
243 | if (time_in_range(cred->cr_expire, expired, jiffies) && | ||
244 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) | ||
245 | continue; | ||
237 | cache_lock = &cred->cr_auth->au_credcache->lock; | 246 | cache_lock = &cred->cr_auth->au_credcache->lock; |
238 | spin_lock(cache_lock); | 247 | spin_lock(cache_lock); |
239 | if (atomic_read(&cred->cr_count) == 0) { | 248 | if (atomic_read(&cred->cr_count) == 0) { |
@@ -280,10 +289,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
280 | struct hlist_node *pos; | 289 | struct hlist_node *pos; |
281 | struct rpc_cred *cred = NULL, | 290 | struct rpc_cred *cred = NULL, |
282 | *entry, *new; | 291 | *entry, *new; |
283 | int nr = 0; | 292 | unsigned int nr; |
284 | 293 | ||
285 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) | 294 | nr = hash_long(acred->uid, RPC_CREDCACHE_HASHBITS); |
286 | nr = acred->uid & RPC_CREDCACHE_MASK; | ||
287 | 295 | ||
288 | rcu_read_lock(); | 296 | rcu_read_lock(); |
289 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { | 297 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { |
@@ -356,7 +364,6 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |||
356 | put_group_info(acred.group_info); | 364 | put_group_info(acred.group_info); |
357 | return ret; | 365 | return ret; |
358 | } | 366 | } |
359 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); | ||
360 | 367 | ||
361 | void | 368 | void |
362 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | 369 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, |
@@ -375,41 +382,58 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | |||
375 | } | 382 | } |
376 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); | 383 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); |
377 | 384 | ||
378 | struct rpc_cred * | 385 | void |
379 | rpcauth_bindcred(struct rpc_task *task) | 386 | rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) |
387 | { | ||
388 | task->tk_msg.rpc_cred = get_rpccred(cred); | ||
389 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, | ||
390 | cred->cr_auth->au_ops->au_name, cred); | ||
391 | } | ||
392 | EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred); | ||
393 | |||
394 | static void | ||
395 | rpcauth_bind_root_cred(struct rpc_task *task) | ||
380 | { | 396 | { |
381 | struct rpc_auth *auth = task->tk_client->cl_auth; | 397 | struct rpc_auth *auth = task->tk_client->cl_auth; |
382 | struct auth_cred acred = { | 398 | struct auth_cred acred = { |
383 | .uid = current->fsuid, | 399 | .uid = 0, |
384 | .gid = current->fsgid, | 400 | .gid = 0, |
385 | .group_info = current->group_info, | ||
386 | }; | 401 | }; |
387 | struct rpc_cred *ret; | 402 | struct rpc_cred *ret; |
388 | int flags = 0; | ||
389 | 403 | ||
390 | dprintk("RPC: %5u looking up %s cred\n", | 404 | dprintk("RPC: %5u looking up %s cred\n", |
391 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); | 405 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); |
392 | get_group_info(acred.group_info); | 406 | ret = auth->au_ops->lookup_cred(auth, &acred, 0); |
393 | if (task->tk_flags & RPC_TASK_ROOTCREDS) | 407 | if (!IS_ERR(ret)) |
394 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; | 408 | task->tk_msg.rpc_cred = ret; |
395 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 409 | else |
410 | task->tk_status = PTR_ERR(ret); | ||
411 | } | ||
412 | |||
413 | static void | ||
414 | rpcauth_bind_new_cred(struct rpc_task *task) | ||
415 | { | ||
416 | struct rpc_auth *auth = task->tk_client->cl_auth; | ||
417 | struct rpc_cred *ret; | ||
418 | |||
419 | dprintk("RPC: %5u looking up %s cred\n", | ||
420 | task->tk_pid, auth->au_ops->au_name); | ||
421 | ret = rpcauth_lookupcred(auth, 0); | ||
396 | if (!IS_ERR(ret)) | 422 | if (!IS_ERR(ret)) |
397 | task->tk_msg.rpc_cred = ret; | 423 | task->tk_msg.rpc_cred = ret; |
398 | else | 424 | else |
399 | task->tk_status = PTR_ERR(ret); | 425 | task->tk_status = PTR_ERR(ret); |
400 | put_group_info(acred.group_info); | ||
401 | return ret; | ||
402 | } | 426 | } |
403 | 427 | ||
404 | void | 428 | void |
405 | rpcauth_holdcred(struct rpc_task *task) | 429 | rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags) |
406 | { | 430 | { |
407 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 431 | if (cred != NULL) |
408 | if (cred != NULL) { | 432 | cred->cr_ops->crbind(task, cred); |
409 | get_rpccred(cred); | 433 | else if (flags & RPC_TASK_ROOTCREDS) |
410 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, | 434 | rpcauth_bind_root_cred(task); |
411 | cred->cr_auth->au_ops->au_name, cred); | 435 | else |
412 | } | 436 | rpcauth_bind_new_cred(task); |
413 | } | 437 | } |
414 | 438 | ||
415 | void | 439 | void |
@@ -550,6 +574,7 @@ static struct shrinker rpc_cred_shrinker = { | |||
550 | void __init rpcauth_init_module(void) | 574 | void __init rpcauth_init_module(void) |
551 | { | 575 | { |
552 | rpc_init_authunix(); | 576 | rpc_init_authunix(); |
577 | rpc_init_generic_auth(); | ||
553 | register_shrinker(&rpc_cred_shrinker); | 578 | register_shrinker(&rpc_cred_shrinker); |
554 | } | 579 | } |
555 | 580 | ||
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c new file mode 100644 index 000000000000..d927d9f57412 --- /dev/null +++ b/net/sunrpc/auth_generic.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Generic RPC credential | ||
3 | * | ||
4 | * Copyright (C) 2008, Trond Myklebust <Trond.Myklebust@netapp.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/err.h> | ||
8 | #include <linux/types.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/sunrpc/auth.h> | ||
12 | #include <linux/sunrpc/clnt.h> | ||
13 | #include <linux/sunrpc/debug.h> | ||
14 | #include <linux/sunrpc/sched.h> | ||
15 | |||
16 | #ifdef RPC_DEBUG | ||
17 | # define RPCDBG_FACILITY RPCDBG_AUTH | ||
18 | #endif | ||
19 | |||
20 | #define RPC_ANONYMOUS_USERID ((uid_t)-2) | ||
21 | #define RPC_ANONYMOUS_GROUPID ((gid_t)-2) | ||
22 | |||
23 | struct generic_cred { | ||
24 | struct rpc_cred gc_base; | ||
25 | struct auth_cred acred; | ||
26 | }; | ||
27 | |||
28 | static struct rpc_auth generic_auth; | ||
29 | static struct rpc_cred_cache generic_cred_cache; | ||
30 | static const struct rpc_credops generic_credops; | ||
31 | |||
32 | /* | ||
33 | * Public call interface | ||
34 | */ | ||
35 | struct rpc_cred *rpc_lookup_cred(void) | ||
36 | { | ||
37 | return rpcauth_lookupcred(&generic_auth, 0); | ||
38 | } | ||
39 | EXPORT_SYMBOL_GPL(rpc_lookup_cred); | ||
40 | |||
41 | /* | ||
42 | * Public call interface for looking up machine creds. | ||
43 | */ | ||
44 | struct rpc_cred *rpc_lookup_machine_cred(void) | ||
45 | { | ||
46 | struct auth_cred acred = { | ||
47 | .uid = RPC_ANONYMOUS_USERID, | ||
48 | .gid = RPC_ANONYMOUS_GROUPID, | ||
49 | .machine_cred = 1, | ||
50 | }; | ||
51 | |||
52 | dprintk("RPC: looking up machine cred\n"); | ||
53 | return generic_auth.au_ops->lookup_cred(&generic_auth, &acred, 0); | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); | ||
56 | |||
57 | static void | ||
58 | generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) | ||
59 | { | ||
60 | struct rpc_auth *auth = task->tk_client->cl_auth; | ||
61 | struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; | ||
62 | struct rpc_cred *ret; | ||
63 | |||
64 | ret = auth->au_ops->lookup_cred(auth, acred, 0); | ||
65 | if (!IS_ERR(ret)) | ||
66 | task->tk_msg.rpc_cred = ret; | ||
67 | else | ||
68 | task->tk_status = PTR_ERR(ret); | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Lookup generic creds for current process | ||
73 | */ | ||
74 | static struct rpc_cred * | ||
75 | generic_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | ||
76 | { | ||
77 | return rpcauth_lookup_credcache(&generic_auth, acred, flags); | ||
78 | } | ||
79 | |||
80 | static struct rpc_cred * | ||
81 | generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | ||
82 | { | ||
83 | struct generic_cred *gcred; | ||
84 | |||
85 | gcred = kmalloc(sizeof(*gcred), GFP_KERNEL); | ||
86 | if (gcred == NULL) | ||
87 | return ERR_PTR(-ENOMEM); | ||
88 | |||
89 | rpcauth_init_cred(&gcred->gc_base, acred, &generic_auth, &generic_credops); | ||
90 | gcred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; | ||
91 | |||
92 | gcred->acred.uid = acred->uid; | ||
93 | gcred->acred.gid = acred->gid; | ||
94 | gcred->acred.group_info = acred->group_info; | ||
95 | if (gcred->acred.group_info != NULL) | ||
96 | get_group_info(gcred->acred.group_info); | ||
97 | gcred->acred.machine_cred = acred->machine_cred; | ||
98 | |||
99 | dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", | ||
100 | gcred->acred.machine_cred ? "machine" : "generic", | ||
101 | gcred, acred->uid, acred->gid); | ||
102 | return &gcred->gc_base; | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | generic_free_cred(struct rpc_cred *cred) | ||
107 | { | ||
108 | struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); | ||
109 | |||
110 | dprintk("RPC: generic_free_cred %p\n", gcred); | ||
111 | if (gcred->acred.group_info != NULL) | ||
112 | put_group_info(gcred->acred.group_info); | ||
113 | kfree(gcred); | ||
114 | } | ||
115 | |||
116 | static void | ||
117 | generic_free_cred_callback(struct rcu_head *head) | ||
118 | { | ||
119 | struct rpc_cred *cred = container_of(head, struct rpc_cred, cr_rcu); | ||
120 | generic_free_cred(cred); | ||
121 | } | ||
122 | |||
123 | static void | ||
124 | generic_destroy_cred(struct rpc_cred *cred) | ||
125 | { | ||
126 | call_rcu(&cred->cr_rcu, generic_free_cred_callback); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Match credentials against current process creds. | ||
131 | */ | ||
132 | static int | ||
133 | generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) | ||
134 | { | ||
135 | struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); | ||
136 | |||
137 | if (gcred->acred.uid != acred->uid || | ||
138 | gcred->acred.gid != acred->gid || | ||
139 | gcred->acred.group_info != acred->group_info || | ||
140 | gcred->acred.machine_cred != acred->machine_cred) | ||
141 | return 0; | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | void __init rpc_init_generic_auth(void) | ||
146 | { | ||
147 | spin_lock_init(&generic_cred_cache.lock); | ||
148 | } | ||
149 | |||
150 | void __exit rpc_destroy_generic_auth(void) | ||
151 | { | ||
152 | rpcauth_clear_credcache(&generic_cred_cache); | ||
153 | } | ||
154 | |||
155 | static struct rpc_cred_cache generic_cred_cache = { | ||
156 | {{ NULL, },}, | ||
157 | }; | ||
158 | |||
159 | static const struct rpc_authops generic_auth_ops = { | ||
160 | .owner = THIS_MODULE, | ||
161 | .au_name = "Generic", | ||
162 | .lookup_cred = generic_lookup_cred, | ||
163 | .crcreate = generic_create_cred, | ||
164 | }; | ||
165 | |||
166 | static struct rpc_auth generic_auth = { | ||
167 | .au_ops = &generic_auth_ops, | ||
168 | .au_count = ATOMIC_INIT(0), | ||
169 | .au_credcache = &generic_cred_cache, | ||
170 | }; | ||
171 | |||
172 | static const struct rpc_credops generic_credops = { | ||
173 | .cr_name = "Generic cred", | ||
174 | .crdestroy = generic_destroy_cred, | ||
175 | .crbind = generic_bind_cred, | ||
176 | .crmatch = generic_match, | ||
177 | }; | ||
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5828e5c060ca..cc12d5f5d5da 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -114,27 +114,14 @@ static void | |||
114 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | 114 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) |
115 | { | 115 | { |
116 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 116 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
117 | struct gss_cl_ctx *old; | ||
118 | 117 | ||
119 | old = gss_cred->gc_ctx; | 118 | if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) |
119 | return; | ||
120 | gss_get_ctx(ctx); | ||
120 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); | 121 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); |
121 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 122 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
123 | smp_mb__before_clear_bit(); | ||
122 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); | 124 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); |
123 | if (old) | ||
124 | gss_put_ctx(old); | ||
125 | } | ||
126 | |||
127 | static int | ||
128 | gss_cred_is_uptodate_ctx(struct rpc_cred *cred) | ||
129 | { | ||
130 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
131 | int res = 0; | ||
132 | |||
133 | rcu_read_lock(); | ||
134 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx) | ||
135 | res = 1; | ||
136 | rcu_read_unlock(); | ||
137 | return res; | ||
138 | } | 125 | } |
139 | 126 | ||
140 | static const void * | 127 | static const void * |
@@ -266,6 +253,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) | |||
266 | BUG_ON(!list_empty(&gss_msg->list)); | 253 | BUG_ON(!list_empty(&gss_msg->list)); |
267 | if (gss_msg->ctx != NULL) | 254 | if (gss_msg->ctx != NULL) |
268 | gss_put_ctx(gss_msg->ctx); | 255 | gss_put_ctx(gss_msg->ctx); |
256 | rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue); | ||
269 | kfree(gss_msg); | 257 | kfree(gss_msg); |
270 | } | 258 | } |
271 | 259 | ||
@@ -339,7 +327,7 @@ gss_upcall_callback(struct rpc_task *task) | |||
339 | 327 | ||
340 | spin_lock(&inode->i_lock); | 328 | spin_lock(&inode->i_lock); |
341 | if (gss_msg->ctx) | 329 | if (gss_msg->ctx) |
342 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); | 330 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); |
343 | else | 331 | else |
344 | task->tk_status = gss_msg->msg.errno; | 332 | task->tk_status = gss_msg->msg.errno; |
345 | gss_cred->gc_upcall = NULL; | 333 | gss_cred->gc_upcall = NULL; |
@@ -370,9 +358,16 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) | |||
370 | static struct gss_upcall_msg * | 358 | static struct gss_upcall_msg * |
371 | gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) | 359 | gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) |
372 | { | 360 | { |
361 | struct gss_cred *gss_cred = container_of(cred, | ||
362 | struct gss_cred, gc_base); | ||
373 | struct gss_upcall_msg *gss_new, *gss_msg; | 363 | struct gss_upcall_msg *gss_new, *gss_msg; |
364 | uid_t uid = cred->cr_uid; | ||
374 | 365 | ||
375 | gss_new = gss_alloc_msg(gss_auth, cred->cr_uid); | 366 | /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */ |
367 | if (gss_cred->gc_machine_cred != 0) | ||
368 | uid = 0; | ||
369 | |||
370 | gss_new = gss_alloc_msg(gss_auth, uid); | ||
376 | if (gss_new == NULL) | 371 | if (gss_new == NULL) |
377 | return ERR_PTR(-ENOMEM); | 372 | return ERR_PTR(-ENOMEM); |
378 | gss_msg = gss_add_msg(gss_auth, gss_new); | 373 | gss_msg = gss_add_msg(gss_auth, gss_new); |
@@ -408,13 +403,17 @@ gss_refresh_upcall(struct rpc_task *task) | |||
408 | } | 403 | } |
409 | spin_lock(&inode->i_lock); | 404 | spin_lock(&inode->i_lock); |
410 | if (gss_cred->gc_upcall != NULL) | 405 | if (gss_cred->gc_upcall != NULL) |
411 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); | 406 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); |
412 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { | 407 | else if (gss_msg->ctx != NULL) { |
408 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); | ||
409 | gss_cred->gc_upcall = NULL; | ||
410 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | ||
411 | } else if (gss_msg->msg.errno >= 0) { | ||
413 | task->tk_timeout = 0; | 412 | task->tk_timeout = 0; |
414 | gss_cred->gc_upcall = gss_msg; | 413 | gss_cred->gc_upcall = gss_msg; |
415 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ | 414 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ |
416 | atomic_inc(&gss_msg->count); | 415 | atomic_inc(&gss_msg->count); |
417 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); | 416 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback); |
418 | } else | 417 | } else |
419 | err = gss_msg->msg.errno; | 418 | err = gss_msg->msg.errno; |
420 | spin_unlock(&inode->i_lock); | 419 | spin_unlock(&inode->i_lock); |
@@ -454,7 +453,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
454 | schedule(); | 453 | schedule(); |
455 | } | 454 | } |
456 | if (gss_msg->ctx) | 455 | if (gss_msg->ctx) |
457 | gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); | 456 | gss_cred_set_ctx(cred, gss_msg->ctx); |
458 | else | 457 | else |
459 | err = gss_msg->msg.errno; | 458 | err = gss_msg->msg.errno; |
460 | spin_unlock(&inode->i_lock); | 459 | spin_unlock(&inode->i_lock); |
@@ -709,7 +708,7 @@ gss_destroying_context(struct rpc_cred *cred) | |||
709 | struct rpc_task *task; | 708 | struct rpc_task *task; |
710 | 709 | ||
711 | if (gss_cred->gc_ctx == NULL || | 710 | if (gss_cred->gc_ctx == NULL || |
712 | gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY) | 711 | test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) |
713 | return 0; | 712 | return 0; |
714 | 713 | ||
715 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | 714 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; |
@@ -719,7 +718,7 @@ gss_destroying_context(struct rpc_cred *cred) | |||
719 | * by the RPC call or by the put_rpccred() below */ | 718 | * by the RPC call or by the put_rpccred() below */ |
720 | get_rpccred(cred); | 719 | get_rpccred(cred); |
721 | 720 | ||
722 | task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC); | 721 | task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT); |
723 | if (!IS_ERR(task)) | 722 | if (!IS_ERR(task)) |
724 | rpc_put_task(task); | 723 | rpc_put_task(task); |
725 | 724 | ||
@@ -817,6 +816,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |||
817 | */ | 816 | */ |
818 | cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; | 817 | cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; |
819 | cred->gc_service = gss_auth->service; | 818 | cred->gc_service = gss_auth->service; |
819 | cred->gc_machine_cred = acred->machine_cred; | ||
820 | kref_get(&gss_auth->kref); | 820 | kref_get(&gss_auth->kref); |
821 | return &cred->gc_base; | 821 | return &cred->gc_base; |
822 | 822 | ||
@@ -843,17 +843,16 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | |||
843 | { | 843 | { |
844 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 844 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
845 | 845 | ||
846 | /* | 846 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) |
847 | * If the searchflags have set RPCAUTH_LOOKUP_NEW, then | ||
848 | * we don't really care if the credential has expired or not, | ||
849 | * since the caller should be prepared to reinitialise it. | ||
850 | */ | ||
851 | if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) | ||
852 | goto out; | 847 | goto out; |
853 | /* Don't match with creds that have expired. */ | 848 | /* Don't match with creds that have expired. */ |
854 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | 849 | if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) |
850 | return 0; | ||
851 | if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) | ||
855 | return 0; | 852 | return 0; |
856 | out: | 853 | out: |
854 | if (acred->machine_cred != gss_cred->gc_machine_cred) | ||
855 | return 0; | ||
857 | return (rc->cr_uid == acred->uid); | 856 | return (rc->cr_uid == acred->uid); |
858 | } | 857 | } |
859 | 858 | ||
@@ -917,16 +916,48 @@ out_put_ctx: | |||
917 | return NULL; | 916 | return NULL; |
918 | } | 917 | } |
919 | 918 | ||
919 | static int gss_renew_cred(struct rpc_task *task) | ||
920 | { | ||
921 | struct rpc_cred *oldcred = task->tk_msg.rpc_cred; | ||
922 | struct gss_cred *gss_cred = container_of(oldcred, | ||
923 | struct gss_cred, | ||
924 | gc_base); | ||
925 | struct rpc_auth *auth = oldcred->cr_auth; | ||
926 | struct auth_cred acred = { | ||
927 | .uid = oldcred->cr_uid, | ||
928 | .machine_cred = gss_cred->gc_machine_cred, | ||
929 | }; | ||
930 | struct rpc_cred *new; | ||
931 | |||
932 | new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW); | ||
933 | if (IS_ERR(new)) | ||
934 | return PTR_ERR(new); | ||
935 | task->tk_msg.rpc_cred = new; | ||
936 | put_rpccred(oldcred); | ||
937 | return 0; | ||
938 | } | ||
939 | |||
920 | /* | 940 | /* |
921 | * Refresh credentials. XXX - finish | 941 | * Refresh credentials. XXX - finish |
922 | */ | 942 | */ |
923 | static int | 943 | static int |
924 | gss_refresh(struct rpc_task *task) | 944 | gss_refresh(struct rpc_task *task) |
925 | { | 945 | { |
946 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | ||
947 | int ret = 0; | ||
948 | |||
949 | if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && | ||
950 | !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) { | ||
951 | ret = gss_renew_cred(task); | ||
952 | if (ret < 0) | ||
953 | goto out; | ||
954 | cred = task->tk_msg.rpc_cred; | ||
955 | } | ||
926 | 956 | ||
927 | if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred)) | 957 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) |
928 | return gss_refresh_upcall(task); | 958 | ret = gss_refresh_upcall(task); |
929 | return 0; | 959 | out: |
960 | return ret; | ||
930 | } | 961 | } |
931 | 962 | ||
932 | /* Dummy refresh routine: used only when destroying the context */ | 963 | /* Dummy refresh routine: used only when destroying the context */ |
@@ -1286,9 +1317,7 @@ out: | |||
1286 | static const struct rpc_authops authgss_ops = { | 1317 | static const struct rpc_authops authgss_ops = { |
1287 | .owner = THIS_MODULE, | 1318 | .owner = THIS_MODULE, |
1288 | .au_flavor = RPC_AUTH_GSS, | 1319 | .au_flavor = RPC_AUTH_GSS, |
1289 | #ifdef RPC_DEBUG | ||
1290 | .au_name = "RPCSEC_GSS", | 1320 | .au_name = "RPCSEC_GSS", |
1291 | #endif | ||
1292 | .create = gss_create, | 1321 | .create = gss_create, |
1293 | .destroy = gss_destroy, | 1322 | .destroy = gss_destroy, |
1294 | .lookup_cred = gss_lookup_cred, | 1323 | .lookup_cred = gss_lookup_cred, |
@@ -1299,6 +1328,7 @@ static const struct rpc_credops gss_credops = { | |||
1299 | .cr_name = "AUTH_GSS", | 1328 | .cr_name = "AUTH_GSS", |
1300 | .crdestroy = gss_destroy_cred, | 1329 | .crdestroy = gss_destroy_cred, |
1301 | .cr_init = gss_cred_init, | 1330 | .cr_init = gss_cred_init, |
1331 | .crbind = rpcauth_generic_bind_cred, | ||
1302 | .crmatch = gss_match, | 1332 | .crmatch = gss_match, |
1303 | .crmarshal = gss_marshal, | 1333 | .crmarshal = gss_marshal, |
1304 | .crrefresh = gss_refresh, | 1334 | .crrefresh = gss_refresh, |
@@ -1310,6 +1340,7 @@ static const struct rpc_credops gss_credops = { | |||
1310 | static const struct rpc_credops gss_nullops = { | 1340 | static const struct rpc_credops gss_nullops = { |
1311 | .cr_name = "AUTH_GSS", | 1341 | .cr_name = "AUTH_GSS", |
1312 | .crdestroy = gss_destroy_cred, | 1342 | .crdestroy = gss_destroy_cred, |
1343 | .crbind = rpcauth_generic_bind_cred, | ||
1313 | .crmatch = gss_match, | 1344 | .crmatch = gss_match, |
1314 | .crmarshal = gss_marshal, | 1345 | .crmarshal = gss_marshal, |
1315 | .crrefresh = gss_refresh_null, | 1346 | .crrefresh = gss_refresh_null, |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 537d0e8589dd..c70dd7f5258e 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
@@ -104,9 +104,7 @@ nul_validate(struct rpc_task *task, __be32 *p) | |||
104 | const struct rpc_authops authnull_ops = { | 104 | const struct rpc_authops authnull_ops = { |
105 | .owner = THIS_MODULE, | 105 | .owner = THIS_MODULE, |
106 | .au_flavor = RPC_AUTH_NULL, | 106 | .au_flavor = RPC_AUTH_NULL, |
107 | #ifdef RPC_DEBUG | ||
108 | .au_name = "NULL", | 107 | .au_name = "NULL", |
109 | #endif | ||
110 | .create = nul_create, | 108 | .create = nul_create, |
111 | .destroy = nul_destroy, | 109 | .destroy = nul_destroy, |
112 | .lookup_cred = nul_lookup_cred, | 110 | .lookup_cred = nul_lookup_cred, |
@@ -125,6 +123,7 @@ static | |||
125 | const struct rpc_credops null_credops = { | 123 | const struct rpc_credops null_credops = { |
126 | .cr_name = "AUTH_NULL", | 124 | .cr_name = "AUTH_NULL", |
127 | .crdestroy = nul_destroy_cred, | 125 | .crdestroy = nul_destroy_cred, |
126 | .crbind = rpcauth_generic_bind_cred, | ||
128 | .crmatch = nul_match, | 127 | .crmatch = nul_match, |
129 | .crmarshal = nul_marshal, | 128 | .crmarshal = nul_marshal, |
130 | .crrefresh = nul_refresh, | 129 | .crrefresh = nul_refresh, |
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 5ed91e5bcee4..44920b90bdc4 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
@@ -60,7 +60,8 @@ static struct rpc_cred * | |||
60 | unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | 60 | unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) |
61 | { | 61 | { |
62 | struct unx_cred *cred; | 62 | struct unx_cred *cred; |
63 | int i; | 63 | unsigned int groups = 0; |
64 | unsigned int i; | ||
64 | 65 | ||
65 | dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", | 66 | dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", |
66 | acred->uid, acred->gid); | 67 | acred->uid, acred->gid); |
@@ -70,21 +71,17 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |||
70 | 71 | ||
71 | rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops); | 72 | rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops); |
72 | cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; | 73 | cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; |
73 | if (flags & RPCAUTH_LOOKUP_ROOTCREDS) { | 74 | |
74 | cred->uc_uid = 0; | 75 | if (acred->group_info != NULL) |
75 | cred->uc_gid = 0; | 76 | groups = acred->group_info->ngroups; |
76 | cred->uc_gids[0] = NOGROUP; | 77 | if (groups > NFS_NGROUPS) |
77 | } else { | 78 | groups = NFS_NGROUPS; |
78 | int groups = acred->group_info->ngroups; | 79 | |
79 | if (groups > NFS_NGROUPS) | 80 | cred->uc_gid = acred->gid; |
80 | groups = NFS_NGROUPS; | 81 | for (i = 0; i < groups; i++) |
81 | 82 | cred->uc_gids[i] = GROUP_AT(acred->group_info, i); | |
82 | cred->uc_gid = acred->gid; | 83 | if (i < NFS_NGROUPS) |
83 | for (i = 0; i < groups; i++) | 84 | cred->uc_gids[i] = NOGROUP; |
84 | cred->uc_gids[i] = GROUP_AT(acred->group_info, i); | ||
85 | if (i < NFS_NGROUPS) | ||
86 | cred->uc_gids[i] = NOGROUP; | ||
87 | } | ||
88 | 85 | ||
89 | return &cred->uc_base; | 86 | return &cred->uc_base; |
90 | } | 87 | } |
@@ -118,26 +115,21 @@ static int | |||
118 | unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) | 115 | unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) |
119 | { | 116 | { |
120 | struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base); | 117 | struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base); |
121 | int i; | 118 | unsigned int groups = 0; |
119 | unsigned int i; | ||
122 | 120 | ||
123 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { | ||
124 | int groups; | ||
125 | 121 | ||
126 | if (cred->uc_uid != acred->uid | 122 | if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid) |
127 | || cred->uc_gid != acred->gid) | 123 | return 0; |
128 | return 0; | ||
129 | 124 | ||
125 | if (acred->group_info != NULL) | ||
130 | groups = acred->group_info->ngroups; | 126 | groups = acred->group_info->ngroups; |
131 | if (groups > NFS_NGROUPS) | 127 | if (groups > NFS_NGROUPS) |
132 | groups = NFS_NGROUPS; | 128 | groups = NFS_NGROUPS; |
133 | for (i = 0; i < groups ; i++) | 129 | for (i = 0; i < groups ; i++) |
134 | if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i)) | 130 | if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i)) |
135 | return 0; | 131 | return 0; |
136 | return 1; | 132 | return 1; |
137 | } | ||
138 | return (cred->uc_uid == 0 | ||
139 | && cred->uc_gid == 0 | ||
140 | && cred->uc_gids[0] == (gid_t) NOGROUP); | ||
141 | } | 133 | } |
142 | 134 | ||
143 | /* | 135 | /* |
@@ -218,9 +210,7 @@ void __init rpc_init_authunix(void) | |||
218 | const struct rpc_authops authunix_ops = { | 210 | const struct rpc_authops authunix_ops = { |
219 | .owner = THIS_MODULE, | 211 | .owner = THIS_MODULE, |
220 | .au_flavor = RPC_AUTH_UNIX, | 212 | .au_flavor = RPC_AUTH_UNIX, |
221 | #ifdef RPC_DEBUG | ||
222 | .au_name = "UNIX", | 213 | .au_name = "UNIX", |
223 | #endif | ||
224 | .create = unx_create, | 214 | .create = unx_create, |
225 | .destroy = unx_destroy, | 215 | .destroy = unx_destroy, |
226 | .lookup_cred = unx_lookup_cred, | 216 | .lookup_cred = unx_lookup_cred, |
@@ -245,6 +235,7 @@ static | |||
245 | const struct rpc_credops unix_credops = { | 235 | const struct rpc_credops unix_credops = { |
246 | .cr_name = "AUTH_UNIX", | 236 | .cr_name = "AUTH_UNIX", |
247 | .crdestroy = unx_destroy_cred, | 237 | .crdestroy = unx_destroy_cred, |
238 | .crbind = rpcauth_generic_bind_cred, | ||
248 | .crmatch = unx_match, | 239 | .crmatch = unx_match, |
249 | .crmarshal = unx_marshal, | 240 | .crmarshal = unx_marshal, |
250 | .crrefresh = unx_refresh, | 241 | .crrefresh = unx_refresh, |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 7b96ff38002f..8945307556ec 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -544,7 +544,7 @@ EXPORT_SYMBOL_GPL(rpc_run_task); | |||
544 | * @msg: RPC call parameters | 544 | * @msg: RPC call parameters |
545 | * @flags: RPC call flags | 545 | * @flags: RPC call flags |
546 | */ | 546 | */ |
547 | int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | 547 | int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags) |
548 | { | 548 | { |
549 | struct rpc_task *task; | 549 | struct rpc_task *task; |
550 | struct rpc_task_setup task_setup_data = { | 550 | struct rpc_task_setup task_setup_data = { |
@@ -575,7 +575,7 @@ EXPORT_SYMBOL_GPL(rpc_call_sync); | |||
575 | * @data: user call data | 575 | * @data: user call data |
576 | */ | 576 | */ |
577 | int | 577 | int |
578 | rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | 578 | rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, |
579 | const struct rpc_call_ops *tk_ops, void *data) | 579 | const struct rpc_call_ops *tk_ops, void *data) |
580 | { | 580 | { |
581 | struct rpc_task *task; | 581 | struct rpc_task *task; |
@@ -1062,7 +1062,7 @@ call_transmit(struct rpc_task *task) | |||
1062 | if (task->tk_msg.rpc_proc->p_decode != NULL) | 1062 | if (task->tk_msg.rpc_proc->p_decode != NULL) |
1063 | return; | 1063 | return; |
1064 | task->tk_action = rpc_exit_task; | 1064 | task->tk_action = rpc_exit_task; |
1065 | rpc_wake_up_task(task); | 1065 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); |
1066 | } | 1066 | } |
1067 | 1067 | ||
1068 | /* | 1068 | /* |
@@ -1116,7 +1116,8 @@ call_status(struct rpc_task *task) | |||
1116 | case -ETIMEDOUT: | 1116 | case -ETIMEDOUT: |
1117 | task->tk_action = call_timeout; | 1117 | task->tk_action = call_timeout; |
1118 | if (task->tk_client->cl_discrtry) | 1118 | if (task->tk_client->cl_discrtry) |
1119 | xprt_force_disconnect(task->tk_xprt); | 1119 | xprt_conditional_disconnect(task->tk_xprt, |
1120 | req->rq_connect_cookie); | ||
1120 | break; | 1121 | break; |
1121 | case -ECONNREFUSED: | 1122 | case -ECONNREFUSED: |
1122 | case -ENOTCONN: | 1123 | case -ENOTCONN: |
@@ -1168,6 +1169,11 @@ call_timeout(struct rpc_task *task) | |||
1168 | clnt->cl_protname, clnt->cl_server); | 1169 | clnt->cl_protname, clnt->cl_server); |
1169 | } | 1170 | } |
1170 | rpc_force_rebind(clnt); | 1171 | rpc_force_rebind(clnt); |
1172 | /* | ||
1173 | * Did our request time out due to an RPCSEC_GSS out-of-sequence | ||
1174 | * event? RFC2203 requires the server to drop all such requests. | ||
1175 | */ | ||
1176 | rpcauth_invalcred(task); | ||
1171 | 1177 | ||
1172 | retry: | 1178 | retry: |
1173 | clnt->cl_stats->rpcretrans++; | 1179 | clnt->cl_stats->rpcretrans++; |
@@ -1195,18 +1201,6 @@ call_decode(struct rpc_task *task) | |||
1195 | task->tk_flags &= ~RPC_CALL_MAJORSEEN; | 1201 | task->tk_flags &= ~RPC_CALL_MAJORSEEN; |
1196 | } | 1202 | } |
1197 | 1203 | ||
1198 | if (task->tk_status < 12) { | ||
1199 | if (!RPC_IS_SOFT(task)) { | ||
1200 | task->tk_action = call_bind; | ||
1201 | clnt->cl_stats->rpcretrans++; | ||
1202 | goto out_retry; | ||
1203 | } | ||
1204 | dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", | ||
1205 | clnt->cl_protname, task->tk_status); | ||
1206 | task->tk_action = call_timeout; | ||
1207 | goto out_retry; | ||
1208 | } | ||
1209 | |||
1210 | /* | 1204 | /* |
1211 | * Ensure that we see all writes made by xprt_complete_rqst() | 1205 | * Ensure that we see all writes made by xprt_complete_rqst() |
1212 | * before it changed req->rq_received. | 1206 | * before it changed req->rq_received. |
@@ -1218,6 +1212,18 @@ call_decode(struct rpc_task *task) | |||
1218 | WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, | 1212 | WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, |
1219 | sizeof(req->rq_rcv_buf)) != 0); | 1213 | sizeof(req->rq_rcv_buf)) != 0); |
1220 | 1214 | ||
1215 | if (req->rq_rcv_buf.len < 12) { | ||
1216 | if (!RPC_IS_SOFT(task)) { | ||
1217 | task->tk_action = call_bind; | ||
1218 | clnt->cl_stats->rpcretrans++; | ||
1219 | goto out_retry; | ||
1220 | } | ||
1221 | dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", | ||
1222 | clnt->cl_protname, task->tk_status); | ||
1223 | task->tk_action = call_timeout; | ||
1224 | goto out_retry; | ||
1225 | } | ||
1226 | |||
1221 | /* Verify the RPC header */ | 1227 | /* Verify the RPC header */ |
1222 | p = call_verify(task); | 1228 | p = call_verify(task); |
1223 | if (IS_ERR(p)) { | 1229 | if (IS_ERR(p)) { |
@@ -1236,10 +1242,14 @@ call_decode(struct rpc_task *task) | |||
1236 | task->tk_status); | 1242 | task->tk_status); |
1237 | return; | 1243 | return; |
1238 | out_retry: | 1244 | out_retry: |
1239 | req->rq_received = req->rq_private_buf.len = 0; | ||
1240 | task->tk_status = 0; | 1245 | task->tk_status = 0; |
1241 | if (task->tk_client->cl_discrtry) | 1246 | /* Note: call_verify() may have freed the RPC slot */ |
1242 | xprt_force_disconnect(task->tk_xprt); | 1247 | if (task->tk_rqstp == req) { |
1248 | req->rq_received = req->rq_rcv_buf.len = 0; | ||
1249 | if (task->tk_client->cl_discrtry) | ||
1250 | xprt_conditional_disconnect(task->tk_xprt, | ||
1251 | req->rq_connect_cookie); | ||
1252 | } | ||
1243 | } | 1253 | } |
1244 | 1254 | ||
1245 | /* | 1255 | /* |
@@ -1531,7 +1541,7 @@ void rpc_show_tasks(void) | |||
1531 | proc = -1; | 1541 | proc = -1; |
1532 | 1542 | ||
1533 | if (RPC_IS_QUEUED(t)) | 1543 | if (RPC_IS_QUEUED(t)) |
1534 | rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); | 1544 | rpc_waitq = rpc_qname(t->tk_waitqueue); |
1535 | 1545 | ||
1536 | printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", | 1546 | printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", |
1537 | t->tk_pid, proc, | 1547 | t->tk_pid, proc, |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 56aa018dce3a..0517967a68bf 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -298,7 +298,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
298 | 298 | ||
299 | /* Put self on queue before sending rpcbind request, in case | 299 | /* Put self on queue before sending rpcbind request, in case |
300 | * rpcb_getport_done completes before we return from rpc_run_task */ | 300 | * rpcb_getport_done completes before we return from rpc_run_task */ |
301 | rpc_sleep_on(&xprt->binding, task, NULL, NULL); | 301 | rpc_sleep_on(&xprt->binding, task, NULL); |
302 | 302 | ||
303 | /* Someone else may have bound if we slept */ | 303 | /* Someone else may have bound if we slept */ |
304 | if (xprt_bound(xprt)) { | 304 | if (xprt_bound(xprt)) { |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 4c669121e607..6eab9bf94baf 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -38,9 +38,9 @@ static struct kmem_cache *rpc_buffer_slabp __read_mostly; | |||
38 | static mempool_t *rpc_task_mempool __read_mostly; | 38 | static mempool_t *rpc_task_mempool __read_mostly; |
39 | static mempool_t *rpc_buffer_mempool __read_mostly; | 39 | static mempool_t *rpc_buffer_mempool __read_mostly; |
40 | 40 | ||
41 | static void __rpc_default_timer(struct rpc_task *task); | ||
42 | static void rpc_async_schedule(struct work_struct *); | 41 | static void rpc_async_schedule(struct work_struct *); |
43 | static void rpc_release_task(struct rpc_task *task); | 42 | static void rpc_release_task(struct rpc_task *task); |
43 | static void __rpc_queue_timer_fn(unsigned long ptr); | ||
44 | 44 | ||
45 | /* | 45 | /* |
46 | * RPC tasks sit here while waiting for conditions to improve. | 46 | * RPC tasks sit here while waiting for conditions to improve. |
@@ -57,41 +57,30 @@ struct workqueue_struct *rpciod_workqueue; | |||
57 | * queue->lock and bh_disabled in order to avoid races within | 57 | * queue->lock and bh_disabled in order to avoid races within |
58 | * rpc_run_timer(). | 58 | * rpc_run_timer(). |
59 | */ | 59 | */ |
60 | static inline void | 60 | static void |
61 | __rpc_disable_timer(struct rpc_task *task) | 61 | __rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task) |
62 | { | 62 | { |
63 | if (task->tk_timeout == 0) | ||
64 | return; | ||
63 | dprintk("RPC: %5u disabling timer\n", task->tk_pid); | 65 | dprintk("RPC: %5u disabling timer\n", task->tk_pid); |
64 | task->tk_timeout_fn = NULL; | ||
65 | task->tk_timeout = 0; | 66 | task->tk_timeout = 0; |
67 | list_del(&task->u.tk_wait.timer_list); | ||
68 | if (list_empty(&queue->timer_list.list)) | ||
69 | del_timer(&queue->timer_list.timer); | ||
66 | } | 70 | } |
67 | 71 | ||
68 | /* | 72 | static void |
69 | * Run a timeout function. | 73 | rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires) |
70 | * We use the callback in order to allow __rpc_wake_up_task() | ||
71 | * and friends to disable the timer synchronously on SMP systems | ||
72 | * without calling del_timer_sync(). The latter could cause a | ||
73 | * deadlock if called while we're holding spinlocks... | ||
74 | */ | ||
75 | static void rpc_run_timer(struct rpc_task *task) | ||
76 | { | 74 | { |
77 | void (*callback)(struct rpc_task *); | 75 | queue->timer_list.expires = expires; |
78 | 76 | mod_timer(&queue->timer_list.timer, expires); | |
79 | callback = task->tk_timeout_fn; | ||
80 | task->tk_timeout_fn = NULL; | ||
81 | if (callback && RPC_IS_QUEUED(task)) { | ||
82 | dprintk("RPC: %5u running timer\n", task->tk_pid); | ||
83 | callback(task); | ||
84 | } | ||
85 | smp_mb__before_clear_bit(); | ||
86 | clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate); | ||
87 | smp_mb__after_clear_bit(); | ||
88 | } | 77 | } |
89 | 78 | ||
90 | /* | 79 | /* |
91 | * Set up a timer for the current task. | 80 | * Set up a timer for the current task. |
92 | */ | 81 | */ |
93 | static inline void | 82 | static void |
94 | __rpc_add_timer(struct rpc_task *task, rpc_action timer) | 83 | __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task) |
95 | { | 84 | { |
96 | if (!task->tk_timeout) | 85 | if (!task->tk_timeout) |
97 | return; | 86 | return; |
@@ -99,27 +88,10 @@ __rpc_add_timer(struct rpc_task *task, rpc_action timer) | |||
99 | dprintk("RPC: %5u setting alarm for %lu ms\n", | 88 | dprintk("RPC: %5u setting alarm for %lu ms\n", |
100 | task->tk_pid, task->tk_timeout * 1000 / HZ); | 89 | task->tk_pid, task->tk_timeout * 1000 / HZ); |
101 | 90 | ||
102 | if (timer) | 91 | task->u.tk_wait.expires = jiffies + task->tk_timeout; |
103 | task->tk_timeout_fn = timer; | 92 | if (list_empty(&queue->timer_list.list) || time_before(task->u.tk_wait.expires, queue->timer_list.expires)) |
104 | else | 93 | rpc_set_queue_timer(queue, task->u.tk_wait.expires); |
105 | task->tk_timeout_fn = __rpc_default_timer; | 94 | list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); |
106 | set_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate); | ||
107 | mod_timer(&task->tk_timer, jiffies + task->tk_timeout); | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Delete any timer for the current task. Because we use del_timer_sync(), | ||
112 | * this function should never be called while holding queue->lock. | ||
113 | */ | ||
114 | static void | ||
115 | rpc_delete_timer(struct rpc_task *task) | ||
116 | { | ||
117 | if (RPC_IS_QUEUED(task)) | ||
118 | return; | ||
119 | if (test_and_clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate)) { | ||
120 | del_singleshot_timer_sync(&task->tk_timer); | ||
121 | dprintk("RPC: %5u deleting timer\n", task->tk_pid); | ||
122 | } | ||
123 | } | 95 | } |
124 | 96 | ||
125 | /* | 97 | /* |
@@ -161,7 +133,7 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task * | |||
161 | list_add(&task->u.tk_wait.list, &queue->tasks[0]); | 133 | list_add(&task->u.tk_wait.list, &queue->tasks[0]); |
162 | else | 134 | else |
163 | list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); | 135 | list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); |
164 | task->u.tk_wait.rpc_waitq = queue; | 136 | task->tk_waitqueue = queue; |
165 | queue->qlen++; | 137 | queue->qlen++; |
166 | rpc_set_queued(task); | 138 | rpc_set_queued(task); |
167 | 139 | ||
@@ -181,22 +153,18 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task) | |||
181 | list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); | 153 | list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); |
182 | list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); | 154 | list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); |
183 | } | 155 | } |
184 | list_del(&task->u.tk_wait.list); | ||
185 | } | 156 | } |
186 | 157 | ||
187 | /* | 158 | /* |
188 | * Remove request from queue. | 159 | * Remove request from queue. |
189 | * Note: must be called with spin lock held. | 160 | * Note: must be called with spin lock held. |
190 | */ | 161 | */ |
191 | static void __rpc_remove_wait_queue(struct rpc_task *task) | 162 | static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) |
192 | { | 163 | { |
193 | struct rpc_wait_queue *queue; | 164 | __rpc_disable_timer(queue, task); |
194 | queue = task->u.tk_wait.rpc_waitq; | ||
195 | |||
196 | if (RPC_IS_PRIORITY(queue)) | 165 | if (RPC_IS_PRIORITY(queue)) |
197 | __rpc_remove_wait_queue_priority(task); | 166 | __rpc_remove_wait_queue_priority(task); |
198 | else | 167 | list_del(&task->u.tk_wait.list); |
199 | list_del(&task->u.tk_wait.list); | ||
200 | queue->qlen--; | 168 | queue->qlen--; |
201 | dprintk("RPC: %5u removed from queue %p \"%s\"\n", | 169 | dprintk("RPC: %5u removed from queue %p \"%s\"\n", |
202 | task->tk_pid, queue, rpc_qname(queue)); | 170 | task->tk_pid, queue, rpc_qname(queue)); |
@@ -229,6 +197,9 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c | |||
229 | INIT_LIST_HEAD(&queue->tasks[i]); | 197 | INIT_LIST_HEAD(&queue->tasks[i]); |
230 | queue->maxpriority = nr_queues - 1; | 198 | queue->maxpriority = nr_queues - 1; |
231 | rpc_reset_waitqueue_priority(queue); | 199 | rpc_reset_waitqueue_priority(queue); |
200 | queue->qlen = 0; | ||
201 | setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue); | ||
202 | INIT_LIST_HEAD(&queue->timer_list.list); | ||
232 | #ifdef RPC_DEBUG | 203 | #ifdef RPC_DEBUG |
233 | queue->name = qname; | 204 | queue->name = qname; |
234 | #endif | 205 | #endif |
@@ -245,6 +216,12 @@ void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) | |||
245 | } | 216 | } |
246 | EXPORT_SYMBOL_GPL(rpc_init_wait_queue); | 217 | EXPORT_SYMBOL_GPL(rpc_init_wait_queue); |
247 | 218 | ||
219 | void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) | ||
220 | { | ||
221 | del_timer_sync(&queue->timer_list.timer); | ||
222 | } | ||
223 | EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); | ||
224 | |||
248 | static int rpc_wait_bit_killable(void *word) | 225 | static int rpc_wait_bit_killable(void *word) |
249 | { | 226 | { |
250 | if (fatal_signal_pending(current)) | 227 | if (fatal_signal_pending(current)) |
@@ -313,7 +290,6 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); | |||
313 | */ | 290 | */ |
314 | static void rpc_make_runnable(struct rpc_task *task) | 291 | static void rpc_make_runnable(struct rpc_task *task) |
315 | { | 292 | { |
316 | BUG_ON(task->tk_timeout_fn); | ||
317 | rpc_clear_queued(task); | 293 | rpc_clear_queued(task); |
318 | if (rpc_test_and_set_running(task)) | 294 | if (rpc_test_and_set_running(task)) |
319 | return; | 295 | return; |
@@ -326,7 +302,7 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
326 | int status; | 302 | int status; |
327 | 303 | ||
328 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); | 304 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); |
329 | status = queue_work(task->tk_workqueue, &task->u.tk_work); | 305 | status = queue_work(rpciod_workqueue, &task->u.tk_work); |
330 | if (status < 0) { | 306 | if (status < 0) { |
331 | printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); | 307 | printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); |
332 | task->tk_status = status; | 308 | task->tk_status = status; |
@@ -343,7 +319,7 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
343 | * as it's on a wait queue. | 319 | * as it's on a wait queue. |
344 | */ | 320 | */ |
345 | static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 321 | static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, |
346 | rpc_action action, rpc_action timer) | 322 | rpc_action action) |
347 | { | 323 | { |
348 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", | 324 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", |
349 | task->tk_pid, rpc_qname(q), jiffies); | 325 | task->tk_pid, rpc_qname(q), jiffies); |
@@ -357,11 +333,11 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
357 | 333 | ||
358 | BUG_ON(task->tk_callback != NULL); | 334 | BUG_ON(task->tk_callback != NULL); |
359 | task->tk_callback = action; | 335 | task->tk_callback = action; |
360 | __rpc_add_timer(task, timer); | 336 | __rpc_add_timer(q, task); |
361 | } | 337 | } |
362 | 338 | ||
363 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 339 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, |
364 | rpc_action action, rpc_action timer) | 340 | rpc_action action) |
365 | { | 341 | { |
366 | /* Mark the task as being activated if so needed */ | 342 | /* Mark the task as being activated if so needed */ |
367 | rpc_set_active(task); | 343 | rpc_set_active(task); |
@@ -370,18 +346,19 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
370 | * Protect the queue operations. | 346 | * Protect the queue operations. |
371 | */ | 347 | */ |
372 | spin_lock_bh(&q->lock); | 348 | spin_lock_bh(&q->lock); |
373 | __rpc_sleep_on(q, task, action, timer); | 349 | __rpc_sleep_on(q, task, action); |
374 | spin_unlock_bh(&q->lock); | 350 | spin_unlock_bh(&q->lock); |
375 | } | 351 | } |
376 | EXPORT_SYMBOL_GPL(rpc_sleep_on); | 352 | EXPORT_SYMBOL_GPL(rpc_sleep_on); |
377 | 353 | ||
378 | /** | 354 | /** |
379 | * __rpc_do_wake_up_task - wake up a single rpc_task | 355 | * __rpc_do_wake_up_task - wake up a single rpc_task |
356 | * @queue: wait queue | ||
380 | * @task: task to be woken up | 357 | * @task: task to be woken up |
381 | * | 358 | * |
382 | * Caller must hold queue->lock, and have cleared the task queued flag. | 359 | * Caller must hold queue->lock, and have cleared the task queued flag. |
383 | */ | 360 | */ |
384 | static void __rpc_do_wake_up_task(struct rpc_task *task) | 361 | static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task *task) |
385 | { | 362 | { |
386 | dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n", | 363 | dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n", |
387 | task->tk_pid, jiffies); | 364 | task->tk_pid, jiffies); |
@@ -395,8 +372,7 @@ static void __rpc_do_wake_up_task(struct rpc_task *task) | |||
395 | return; | 372 | return; |
396 | } | 373 | } |
397 | 374 | ||
398 | __rpc_disable_timer(task); | 375 | __rpc_remove_wait_queue(queue, task); |
399 | __rpc_remove_wait_queue(task); | ||
400 | 376 | ||
401 | rpc_make_runnable(task); | 377 | rpc_make_runnable(task); |
402 | 378 | ||
@@ -404,48 +380,32 @@ static void __rpc_do_wake_up_task(struct rpc_task *task) | |||
404 | } | 380 | } |
405 | 381 | ||
406 | /* | 382 | /* |
407 | * Wake up the specified task | 383 | * Wake up a queued task while the queue lock is being held |
408 | */ | 384 | */ |
409 | static void __rpc_wake_up_task(struct rpc_task *task) | 385 | static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task) |
410 | { | 386 | { |
411 | if (rpc_start_wakeup(task)) { | 387 | if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue) |
412 | if (RPC_IS_QUEUED(task)) | 388 | __rpc_do_wake_up_task(queue, task); |
413 | __rpc_do_wake_up_task(task); | ||
414 | rpc_finish_wakeup(task); | ||
415 | } | ||
416 | } | 389 | } |
417 | 390 | ||
418 | /* | 391 | /* |
419 | * Default timeout handler if none specified by user | 392 | * Wake up a task on a specific queue |
420 | */ | 393 | */ |
421 | static void | 394 | void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task) |
422 | __rpc_default_timer(struct rpc_task *task) | ||
423 | { | 395 | { |
424 | dprintk("RPC: %5u timeout (default timer)\n", task->tk_pid); | 396 | spin_lock_bh(&queue->lock); |
425 | task->tk_status = -ETIMEDOUT; | 397 | rpc_wake_up_task_queue_locked(queue, task); |
426 | rpc_wake_up_task(task); | 398 | spin_unlock_bh(&queue->lock); |
427 | } | 399 | } |
400 | EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); | ||
428 | 401 | ||
429 | /* | 402 | /* |
430 | * Wake up the specified task | 403 | * Wake up the specified task |
431 | */ | 404 | */ |
432 | void rpc_wake_up_task(struct rpc_task *task) | 405 | static void rpc_wake_up_task(struct rpc_task *task) |
433 | { | 406 | { |
434 | rcu_read_lock_bh(); | 407 | rpc_wake_up_queued_task(task->tk_waitqueue, task); |
435 | if (rpc_start_wakeup(task)) { | ||
436 | if (RPC_IS_QUEUED(task)) { | ||
437 | struct rpc_wait_queue *queue = task->u.tk_wait.rpc_waitq; | ||
438 | |||
439 | /* Note: we're already in a bh-safe context */ | ||
440 | spin_lock(&queue->lock); | ||
441 | __rpc_do_wake_up_task(task); | ||
442 | spin_unlock(&queue->lock); | ||
443 | } | ||
444 | rpc_finish_wakeup(task); | ||
445 | } | ||
446 | rcu_read_unlock_bh(); | ||
447 | } | 408 | } |
448 | EXPORT_SYMBOL_GPL(rpc_wake_up_task); | ||
449 | 409 | ||
450 | /* | 410 | /* |
451 | * Wake up the next task on a priority queue. | 411 | * Wake up the next task on a priority queue. |
@@ -495,7 +455,7 @@ new_queue: | |||
495 | new_owner: | 455 | new_owner: |
496 | rpc_set_waitqueue_owner(queue, task->tk_owner); | 456 | rpc_set_waitqueue_owner(queue, task->tk_owner); |
497 | out: | 457 | out: |
498 | __rpc_wake_up_task(task); | 458 | rpc_wake_up_task_queue_locked(queue, task); |
499 | return task; | 459 | return task; |
500 | } | 460 | } |
501 | 461 | ||
@@ -508,16 +468,14 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) | |||
508 | 468 | ||
509 | dprintk("RPC: wake_up_next(%p \"%s\")\n", | 469 | dprintk("RPC: wake_up_next(%p \"%s\")\n", |
510 | queue, rpc_qname(queue)); | 470 | queue, rpc_qname(queue)); |
511 | rcu_read_lock_bh(); | 471 | spin_lock_bh(&queue->lock); |
512 | spin_lock(&queue->lock); | ||
513 | if (RPC_IS_PRIORITY(queue)) | 472 | if (RPC_IS_PRIORITY(queue)) |
514 | task = __rpc_wake_up_next_priority(queue); | 473 | task = __rpc_wake_up_next_priority(queue); |
515 | else { | 474 | else { |
516 | task_for_first(task, &queue->tasks[0]) | 475 | task_for_first(task, &queue->tasks[0]) |
517 | __rpc_wake_up_task(task); | 476 | rpc_wake_up_task_queue_locked(queue, task); |
518 | } | 477 | } |
519 | spin_unlock(&queue->lock); | 478 | spin_unlock_bh(&queue->lock); |
520 | rcu_read_unlock_bh(); | ||
521 | 479 | ||
522 | return task; | 480 | return task; |
523 | } | 481 | } |
@@ -534,18 +492,16 @@ void rpc_wake_up(struct rpc_wait_queue *queue) | |||
534 | struct rpc_task *task, *next; | 492 | struct rpc_task *task, *next; |
535 | struct list_head *head; | 493 | struct list_head *head; |
536 | 494 | ||
537 | rcu_read_lock_bh(); | 495 | spin_lock_bh(&queue->lock); |
538 | spin_lock(&queue->lock); | ||
539 | head = &queue->tasks[queue->maxpriority]; | 496 | head = &queue->tasks[queue->maxpriority]; |
540 | for (;;) { | 497 | for (;;) { |
541 | list_for_each_entry_safe(task, next, head, u.tk_wait.list) | 498 | list_for_each_entry_safe(task, next, head, u.tk_wait.list) |
542 | __rpc_wake_up_task(task); | 499 | rpc_wake_up_task_queue_locked(queue, task); |
543 | if (head == &queue->tasks[0]) | 500 | if (head == &queue->tasks[0]) |
544 | break; | 501 | break; |
545 | head--; | 502 | head--; |
546 | } | 503 | } |
547 | spin_unlock(&queue->lock); | 504 | spin_unlock_bh(&queue->lock); |
548 | rcu_read_unlock_bh(); | ||
549 | } | 505 | } |
550 | EXPORT_SYMBOL_GPL(rpc_wake_up); | 506 | EXPORT_SYMBOL_GPL(rpc_wake_up); |
551 | 507 | ||
@@ -561,26 +517,48 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) | |||
561 | struct rpc_task *task, *next; | 517 | struct rpc_task *task, *next; |
562 | struct list_head *head; | 518 | struct list_head *head; |
563 | 519 | ||
564 | rcu_read_lock_bh(); | 520 | spin_lock_bh(&queue->lock); |
565 | spin_lock(&queue->lock); | ||
566 | head = &queue->tasks[queue->maxpriority]; | 521 | head = &queue->tasks[queue->maxpriority]; |
567 | for (;;) { | 522 | for (;;) { |
568 | list_for_each_entry_safe(task, next, head, u.tk_wait.list) { | 523 | list_for_each_entry_safe(task, next, head, u.tk_wait.list) { |
569 | task->tk_status = status; | 524 | task->tk_status = status; |
570 | __rpc_wake_up_task(task); | 525 | rpc_wake_up_task_queue_locked(queue, task); |
571 | } | 526 | } |
572 | if (head == &queue->tasks[0]) | 527 | if (head == &queue->tasks[0]) |
573 | break; | 528 | break; |
574 | head--; | 529 | head--; |
575 | } | 530 | } |
576 | spin_unlock(&queue->lock); | 531 | spin_unlock_bh(&queue->lock); |
577 | rcu_read_unlock_bh(); | ||
578 | } | 532 | } |
579 | EXPORT_SYMBOL_GPL(rpc_wake_up_status); | 533 | EXPORT_SYMBOL_GPL(rpc_wake_up_status); |
580 | 534 | ||
535 | static void __rpc_queue_timer_fn(unsigned long ptr) | ||
536 | { | ||
537 | struct rpc_wait_queue *queue = (struct rpc_wait_queue *)ptr; | ||
538 | struct rpc_task *task, *n; | ||
539 | unsigned long expires, now, timeo; | ||
540 | |||
541 | spin_lock(&queue->lock); | ||
542 | expires = now = jiffies; | ||
543 | list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) { | ||
544 | timeo = task->u.tk_wait.expires; | ||
545 | if (time_after_eq(now, timeo)) { | ||
546 | dprintk("RPC: %5u timeout\n", task->tk_pid); | ||
547 | task->tk_status = -ETIMEDOUT; | ||
548 | rpc_wake_up_task_queue_locked(queue, task); | ||
549 | continue; | ||
550 | } | ||
551 | if (expires == now || time_after(expires, timeo)) | ||
552 | expires = timeo; | ||
553 | } | ||
554 | if (!list_empty(&queue->timer_list.list)) | ||
555 | rpc_set_queue_timer(queue, expires); | ||
556 | spin_unlock(&queue->lock); | ||
557 | } | ||
558 | |||
581 | static void __rpc_atrun(struct rpc_task *task) | 559 | static void __rpc_atrun(struct rpc_task *task) |
582 | { | 560 | { |
583 | rpc_wake_up_task(task); | 561 | task->tk_status = 0; |
584 | } | 562 | } |
585 | 563 | ||
586 | /* | 564 | /* |
@@ -589,7 +567,7 @@ static void __rpc_atrun(struct rpc_task *task) | |||
589 | void rpc_delay(struct rpc_task *task, unsigned long delay) | 567 | void rpc_delay(struct rpc_task *task, unsigned long delay) |
590 | { | 568 | { |
591 | task->tk_timeout = delay; | 569 | task->tk_timeout = delay; |
592 | rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun); | 570 | rpc_sleep_on(&delay_queue, task, __rpc_atrun); |
593 | } | 571 | } |
594 | EXPORT_SYMBOL_GPL(rpc_delay); | 572 | EXPORT_SYMBOL_GPL(rpc_delay); |
595 | 573 | ||
@@ -644,10 +622,6 @@ static void __rpc_execute(struct rpc_task *task) | |||
644 | BUG_ON(RPC_IS_QUEUED(task)); | 622 | BUG_ON(RPC_IS_QUEUED(task)); |
645 | 623 | ||
646 | for (;;) { | 624 | for (;;) { |
647 | /* | ||
648 | * Garbage collection of pending timers... | ||
649 | */ | ||
650 | rpc_delete_timer(task); | ||
651 | 625 | ||
652 | /* | 626 | /* |
653 | * Execute any pending callback. | 627 | * Execute any pending callback. |
@@ -816,8 +790,6 @@ EXPORT_SYMBOL_GPL(rpc_free); | |||
816 | static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data) | 790 | static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data) |
817 | { | 791 | { |
818 | memset(task, 0, sizeof(*task)); | 792 | memset(task, 0, sizeof(*task)); |
819 | setup_timer(&task->tk_timer, (void (*)(unsigned long))rpc_run_timer, | ||
820 | (unsigned long)task); | ||
821 | atomic_set(&task->tk_count, 1); | 793 | atomic_set(&task->tk_count, 1); |
822 | task->tk_flags = task_setup_data->flags; | 794 | task->tk_flags = task_setup_data->flags; |
823 | task->tk_ops = task_setup_data->callback_ops; | 795 | task->tk_ops = task_setup_data->callback_ops; |
@@ -832,7 +804,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
832 | task->tk_owner = current->tgid; | 804 | task->tk_owner = current->tgid; |
833 | 805 | ||
834 | /* Initialize workqueue for async tasks */ | 806 | /* Initialize workqueue for async tasks */ |
835 | task->tk_workqueue = rpciod_workqueue; | 807 | task->tk_workqueue = task_setup_data->workqueue; |
836 | 808 | ||
837 | task->tk_client = task_setup_data->rpc_client; | 809 | task->tk_client = task_setup_data->rpc_client; |
838 | if (task->tk_client != NULL) { | 810 | if (task->tk_client != NULL) { |
@@ -845,12 +817,11 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
845 | task->tk_action = rpc_prepare_task; | 817 | task->tk_action = rpc_prepare_task; |
846 | 818 | ||
847 | if (task_setup_data->rpc_message != NULL) { | 819 | if (task_setup_data->rpc_message != NULL) { |
848 | memcpy(&task->tk_msg, task_setup_data->rpc_message, sizeof(task->tk_msg)); | 820 | task->tk_msg.rpc_proc = task_setup_data->rpc_message->rpc_proc; |
821 | task->tk_msg.rpc_argp = task_setup_data->rpc_message->rpc_argp; | ||
822 | task->tk_msg.rpc_resp = task_setup_data->rpc_message->rpc_resp; | ||
849 | /* Bind the user cred */ | 823 | /* Bind the user cred */ |
850 | if (task->tk_msg.rpc_cred != NULL) | 824 | rpcauth_bindcred(task, task_setup_data->rpc_message->rpc_cred, task_setup_data->flags); |
851 | rpcauth_holdcred(task); | ||
852 | else | ||
853 | rpcauth_bindcred(task); | ||
854 | if (task->tk_action == NULL) | 825 | if (task->tk_action == NULL) |
855 | rpc_call_start(task); | 826 | rpc_call_start(task); |
856 | } | 827 | } |
@@ -868,13 +839,6 @@ rpc_alloc_task(void) | |||
868 | return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); | 839 | return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); |
869 | } | 840 | } |
870 | 841 | ||
871 | static void rpc_free_task(struct rcu_head *rcu) | ||
872 | { | ||
873 | struct rpc_task *task = container_of(rcu, struct rpc_task, u.tk_rcu); | ||
874 | dprintk("RPC: %5u freeing task\n", task->tk_pid); | ||
875 | mempool_free(task, rpc_task_mempool); | ||
876 | } | ||
877 | |||
878 | /* | 842 | /* |
879 | * Create a new task for the specified client. | 843 | * Create a new task for the specified client. |
880 | */ | 844 | */ |
@@ -898,12 +862,25 @@ out: | |||
898 | return task; | 862 | return task; |
899 | } | 863 | } |
900 | 864 | ||
901 | 865 | static void rpc_free_task(struct rpc_task *task) | |
902 | void rpc_put_task(struct rpc_task *task) | ||
903 | { | 866 | { |
904 | const struct rpc_call_ops *tk_ops = task->tk_ops; | 867 | const struct rpc_call_ops *tk_ops = task->tk_ops; |
905 | void *calldata = task->tk_calldata; | 868 | void *calldata = task->tk_calldata; |
906 | 869 | ||
870 | if (task->tk_flags & RPC_TASK_DYNAMIC) { | ||
871 | dprintk("RPC: %5u freeing task\n", task->tk_pid); | ||
872 | mempool_free(task, rpc_task_mempool); | ||
873 | } | ||
874 | rpc_release_calldata(tk_ops, calldata); | ||
875 | } | ||
876 | |||
877 | static void rpc_async_release(struct work_struct *work) | ||
878 | { | ||
879 | rpc_free_task(container_of(work, struct rpc_task, u.tk_work)); | ||
880 | } | ||
881 | |||
882 | void rpc_put_task(struct rpc_task *task) | ||
883 | { | ||
907 | if (!atomic_dec_and_test(&task->tk_count)) | 884 | if (!atomic_dec_and_test(&task->tk_count)) |
908 | return; | 885 | return; |
909 | /* Release resources */ | 886 | /* Release resources */ |
@@ -915,9 +892,11 @@ void rpc_put_task(struct rpc_task *task) | |||
915 | rpc_release_client(task->tk_client); | 892 | rpc_release_client(task->tk_client); |
916 | task->tk_client = NULL; | 893 | task->tk_client = NULL; |
917 | } | 894 | } |
918 | if (task->tk_flags & RPC_TASK_DYNAMIC) | 895 | if (task->tk_workqueue != NULL) { |
919 | call_rcu_bh(&task->u.tk_rcu, rpc_free_task); | 896 | INIT_WORK(&task->u.tk_work, rpc_async_release); |
920 | rpc_release_calldata(tk_ops, calldata); | 897 | queue_work(task->tk_workqueue, &task->u.tk_work); |
898 | } else | ||
899 | rpc_free_task(task); | ||
921 | } | 900 | } |
922 | EXPORT_SYMBOL_GPL(rpc_put_task); | 901 | EXPORT_SYMBOL_GPL(rpc_put_task); |
923 | 902 | ||
@@ -937,9 +916,6 @@ static void rpc_release_task(struct rpc_task *task) | |||
937 | } | 916 | } |
938 | BUG_ON (RPC_IS_QUEUED(task)); | 917 | BUG_ON (RPC_IS_QUEUED(task)); |
939 | 918 | ||
940 | /* Synchronously delete any running timer */ | ||
941 | rpc_delete_timer(task); | ||
942 | |||
943 | #ifdef RPC_DEBUG | 919 | #ifdef RPC_DEBUG |
944 | task->tk_magic = 0; | 920 | task->tk_magic = 0; |
945 | #endif | 921 | #endif |
@@ -1029,11 +1005,20 @@ rpc_destroy_mempool(void) | |||
1029 | kmem_cache_destroy(rpc_task_slabp); | 1005 | kmem_cache_destroy(rpc_task_slabp); |
1030 | if (rpc_buffer_slabp) | 1006 | if (rpc_buffer_slabp) |
1031 | kmem_cache_destroy(rpc_buffer_slabp); | 1007 | kmem_cache_destroy(rpc_buffer_slabp); |
1008 | rpc_destroy_wait_queue(&delay_queue); | ||
1032 | } | 1009 | } |
1033 | 1010 | ||
1034 | int | 1011 | int |
1035 | rpc_init_mempool(void) | 1012 | rpc_init_mempool(void) |
1036 | { | 1013 | { |
1014 | /* | ||
1015 | * The following is not strictly a mempool initialisation, | ||
1016 | * but there is no harm in doing it here | ||
1017 | */ | ||
1018 | rpc_init_wait_queue(&delay_queue, "delayq"); | ||
1019 | if (!rpciod_start()) | ||
1020 | goto err_nomem; | ||
1021 | |||
1037 | rpc_task_slabp = kmem_cache_create("rpc_tasks", | 1022 | rpc_task_slabp = kmem_cache_create("rpc_tasks", |
1038 | sizeof(struct rpc_task), | 1023 | sizeof(struct rpc_task), |
1039 | 0, SLAB_HWCACHE_ALIGN, | 1024 | 0, SLAB_HWCACHE_ALIGN, |
@@ -1054,13 +1039,6 @@ rpc_init_mempool(void) | |||
1054 | rpc_buffer_slabp); | 1039 | rpc_buffer_slabp); |
1055 | if (!rpc_buffer_mempool) | 1040 | if (!rpc_buffer_mempool) |
1056 | goto err_nomem; | 1041 | goto err_nomem; |
1057 | if (!rpciod_start()) | ||
1058 | goto err_nomem; | ||
1059 | /* | ||
1060 | * The following is not strictly a mempool initialisation, | ||
1061 | * but there is no harm in doing it here | ||
1062 | */ | ||
1063 | rpc_init_wait_queue(&delay_queue, "delayq"); | ||
1064 | return 0; | 1042 | return 0; |
1065 | err_nomem: | 1043 | err_nomem: |
1066 | rpc_destroy_mempool(); | 1044 | rpc_destroy_mempool(); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d5553b8179f9..75d748eee0eb 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -188,9 +188,9 @@ out_sleep: | |||
188 | task->tk_timeout = 0; | 188 | task->tk_timeout = 0; |
189 | task->tk_status = -EAGAIN; | 189 | task->tk_status = -EAGAIN; |
190 | if (req && req->rq_ntrans) | 190 | if (req && req->rq_ntrans) |
191 | rpc_sleep_on(&xprt->resend, task, NULL, NULL); | 191 | rpc_sleep_on(&xprt->resend, task, NULL); |
192 | else | 192 | else |
193 | rpc_sleep_on(&xprt->sending, task, NULL, NULL); | 193 | rpc_sleep_on(&xprt->sending, task, NULL); |
194 | return 0; | 194 | return 0; |
195 | } | 195 | } |
196 | EXPORT_SYMBOL_GPL(xprt_reserve_xprt); | 196 | EXPORT_SYMBOL_GPL(xprt_reserve_xprt); |
@@ -238,9 +238,9 @@ out_sleep: | |||
238 | task->tk_timeout = 0; | 238 | task->tk_timeout = 0; |
239 | task->tk_status = -EAGAIN; | 239 | task->tk_status = -EAGAIN; |
240 | if (req && req->rq_ntrans) | 240 | if (req && req->rq_ntrans) |
241 | rpc_sleep_on(&xprt->resend, task, NULL, NULL); | 241 | rpc_sleep_on(&xprt->resend, task, NULL); |
242 | else | 242 | else |
243 | rpc_sleep_on(&xprt->sending, task, NULL, NULL); | 243 | rpc_sleep_on(&xprt->sending, task, NULL); |
244 | return 0; | 244 | return 0; |
245 | } | 245 | } |
246 | EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong); | 246 | EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong); |
@@ -447,13 +447,13 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks); | |||
447 | * @task: task to be put to sleep | 447 | * @task: task to be put to sleep |
448 | * | 448 | * |
449 | */ | 449 | */ |
450 | void xprt_wait_for_buffer_space(struct rpc_task *task) | 450 | void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action) |
451 | { | 451 | { |
452 | struct rpc_rqst *req = task->tk_rqstp; | 452 | struct rpc_rqst *req = task->tk_rqstp; |
453 | struct rpc_xprt *xprt = req->rq_xprt; | 453 | struct rpc_xprt *xprt = req->rq_xprt; |
454 | 454 | ||
455 | task->tk_timeout = req->rq_timeout; | 455 | task->tk_timeout = req->rq_timeout; |
456 | rpc_sleep_on(&xprt->pending, task, NULL, NULL); | 456 | rpc_sleep_on(&xprt->pending, task, action); |
457 | } | 457 | } |
458 | EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); | 458 | EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); |
459 | 459 | ||
@@ -472,7 +472,7 @@ void xprt_write_space(struct rpc_xprt *xprt) | |||
472 | if (xprt->snd_task) { | 472 | if (xprt->snd_task) { |
473 | dprintk("RPC: write space: waking waiting task on " | 473 | dprintk("RPC: write space: waking waiting task on " |
474 | "xprt %p\n", xprt); | 474 | "xprt %p\n", xprt); |
475 | rpc_wake_up_task(xprt->snd_task); | 475 | rpc_wake_up_queued_task(&xprt->pending, xprt->snd_task); |
476 | } | 476 | } |
477 | spin_unlock_bh(&xprt->transport_lock); | 477 | spin_unlock_bh(&xprt->transport_lock); |
478 | } | 478 | } |
@@ -602,11 +602,37 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) | |||
602 | /* Try to schedule an autoclose RPC call */ | 602 | /* Try to schedule an autoclose RPC call */ |
603 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) | 603 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) |
604 | queue_work(rpciod_workqueue, &xprt->task_cleanup); | 604 | queue_work(rpciod_workqueue, &xprt->task_cleanup); |
605 | else if (xprt->snd_task != NULL) | 605 | xprt_wake_pending_tasks(xprt, -ENOTCONN); |
606 | rpc_wake_up_task(xprt->snd_task); | 606 | spin_unlock_bh(&xprt->transport_lock); |
607 | } | ||
608 | |||
609 | /** | ||
610 | * xprt_conditional_disconnect - force a transport to disconnect | ||
611 | * @xprt: transport to disconnect | ||
612 | * @cookie: 'connection cookie' | ||
613 | * | ||
614 | * This attempts to break the connection if and only if 'cookie' matches | ||
615 | * the current transport 'connection cookie'. It ensures that we don't | ||
616 | * try to break the connection more than once when we need to retransmit | ||
617 | * a batch of RPC requests. | ||
618 | * | ||
619 | */ | ||
620 | void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie) | ||
621 | { | ||
622 | /* Don't race with the test_bit() in xprt_clear_locked() */ | ||
623 | spin_lock_bh(&xprt->transport_lock); | ||
624 | if (cookie != xprt->connect_cookie) | ||
625 | goto out; | ||
626 | if (test_bit(XPRT_CLOSING, &xprt->state) || !xprt_connected(xprt)) | ||
627 | goto out; | ||
628 | set_bit(XPRT_CLOSE_WAIT, &xprt->state); | ||
629 | /* Try to schedule an autoclose RPC call */ | ||
630 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) | ||
631 | queue_work(rpciod_workqueue, &xprt->task_cleanup); | ||
632 | xprt_wake_pending_tasks(xprt, -ENOTCONN); | ||
633 | out: | ||
607 | spin_unlock_bh(&xprt->transport_lock); | 634 | spin_unlock_bh(&xprt->transport_lock); |
608 | } | 635 | } |
609 | EXPORT_SYMBOL_GPL(xprt_force_disconnect); | ||
610 | 636 | ||
611 | static void | 637 | static void |
612 | xprt_init_autodisconnect(unsigned long data) | 638 | xprt_init_autodisconnect(unsigned long data) |
@@ -653,7 +679,7 @@ void xprt_connect(struct rpc_task *task) | |||
653 | task->tk_rqstp->rq_bytes_sent = 0; | 679 | task->tk_rqstp->rq_bytes_sent = 0; |
654 | 680 | ||
655 | task->tk_timeout = xprt->connect_timeout; | 681 | task->tk_timeout = xprt->connect_timeout; |
656 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); | 682 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status); |
657 | xprt->stat.connect_start = jiffies; | 683 | xprt->stat.connect_start = jiffies; |
658 | xprt->ops->connect(task); | 684 | xprt->ops->connect(task); |
659 | } | 685 | } |
@@ -749,18 +775,20 @@ EXPORT_SYMBOL_GPL(xprt_update_rtt); | |||
749 | void xprt_complete_rqst(struct rpc_task *task, int copied) | 775 | void xprt_complete_rqst(struct rpc_task *task, int copied) |
750 | { | 776 | { |
751 | struct rpc_rqst *req = task->tk_rqstp; | 777 | struct rpc_rqst *req = task->tk_rqstp; |
778 | struct rpc_xprt *xprt = req->rq_xprt; | ||
752 | 779 | ||
753 | dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", | 780 | dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", |
754 | task->tk_pid, ntohl(req->rq_xid), copied); | 781 | task->tk_pid, ntohl(req->rq_xid), copied); |
755 | 782 | ||
756 | task->tk_xprt->stat.recvs++; | 783 | xprt->stat.recvs++; |
757 | task->tk_rtt = (long)jiffies - req->rq_xtime; | 784 | task->tk_rtt = (long)jiffies - req->rq_xtime; |
758 | 785 | ||
759 | list_del_init(&req->rq_list); | 786 | list_del_init(&req->rq_list); |
787 | req->rq_private_buf.len = copied; | ||
760 | /* Ensure all writes are done before we update req->rq_received */ | 788 | /* Ensure all writes are done before we update req->rq_received */ |
761 | smp_wmb(); | 789 | smp_wmb(); |
762 | req->rq_received = req->rq_private_buf.len = copied; | 790 | req->rq_received = copied; |
763 | rpc_wake_up_task(task); | 791 | rpc_wake_up_queued_task(&xprt->pending, task); |
764 | } | 792 | } |
765 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); | 793 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); |
766 | 794 | ||
@@ -769,17 +797,17 @@ static void xprt_timer(struct rpc_task *task) | |||
769 | struct rpc_rqst *req = task->tk_rqstp; | 797 | struct rpc_rqst *req = task->tk_rqstp; |
770 | struct rpc_xprt *xprt = req->rq_xprt; | 798 | struct rpc_xprt *xprt = req->rq_xprt; |
771 | 799 | ||
800 | if (task->tk_status != -ETIMEDOUT) | ||
801 | return; | ||
772 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); | 802 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); |
773 | 803 | ||
774 | spin_lock(&xprt->transport_lock); | 804 | spin_lock_bh(&xprt->transport_lock); |
775 | if (!req->rq_received) { | 805 | if (!req->rq_received) { |
776 | if (xprt->ops->timer) | 806 | if (xprt->ops->timer) |
777 | xprt->ops->timer(task); | 807 | xprt->ops->timer(task); |
778 | task->tk_status = -ETIMEDOUT; | 808 | } else |
779 | } | 809 | task->tk_status = 0; |
780 | task->tk_timeout = 0; | 810 | spin_unlock_bh(&xprt->transport_lock); |
781 | rpc_wake_up_task(task); | ||
782 | spin_unlock(&xprt->transport_lock); | ||
783 | } | 811 | } |
784 | 812 | ||
785 | /** | 813 | /** |
@@ -849,6 +877,7 @@ void xprt_transmit(struct rpc_task *task) | |||
849 | } else if (!req->rq_bytes_sent) | 877 | } else if (!req->rq_bytes_sent) |
850 | return; | 878 | return; |
851 | 879 | ||
880 | req->rq_connect_cookie = xprt->connect_cookie; | ||
852 | status = xprt->ops->send_request(task); | 881 | status = xprt->ops->send_request(task); |
853 | if (status == 0) { | 882 | if (status == 0) { |
854 | dprintk("RPC: %5u xmit complete\n", task->tk_pid); | 883 | dprintk("RPC: %5u xmit complete\n", task->tk_pid); |
@@ -864,7 +893,7 @@ void xprt_transmit(struct rpc_task *task) | |||
864 | if (!xprt_connected(xprt)) | 893 | if (!xprt_connected(xprt)) |
865 | task->tk_status = -ENOTCONN; | 894 | task->tk_status = -ENOTCONN; |
866 | else if (!req->rq_received) | 895 | else if (!req->rq_received) |
867 | rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); | 896 | rpc_sleep_on(&xprt->pending, task, xprt_timer); |
868 | spin_unlock_bh(&xprt->transport_lock); | 897 | spin_unlock_bh(&xprt->transport_lock); |
869 | return; | 898 | return; |
870 | } | 899 | } |
@@ -875,7 +904,7 @@ void xprt_transmit(struct rpc_task *task) | |||
875 | */ | 904 | */ |
876 | task->tk_status = status; | 905 | task->tk_status = status; |
877 | if (status == -ECONNREFUSED) | 906 | if (status == -ECONNREFUSED) |
878 | rpc_sleep_on(&xprt->sending, task, NULL, NULL); | 907 | rpc_sleep_on(&xprt->sending, task, NULL); |
879 | } | 908 | } |
880 | 909 | ||
881 | static inline void do_xprt_reserve(struct rpc_task *task) | 910 | static inline void do_xprt_reserve(struct rpc_task *task) |
@@ -895,7 +924,7 @@ static inline void do_xprt_reserve(struct rpc_task *task) | |||
895 | dprintk("RPC: waiting for request slot\n"); | 924 | dprintk("RPC: waiting for request slot\n"); |
896 | task->tk_status = -EAGAIN; | 925 | task->tk_status = -EAGAIN; |
897 | task->tk_timeout = 0; | 926 | task->tk_timeout = 0; |
898 | rpc_sleep_on(&xprt->backlog, task, NULL, NULL); | 927 | rpc_sleep_on(&xprt->backlog, task, NULL); |
899 | } | 928 | } |
900 | 929 | ||
901 | /** | 930 | /** |
@@ -1052,6 +1081,11 @@ static void xprt_destroy(struct kref *kref) | |||
1052 | xprt->shutdown = 1; | 1081 | xprt->shutdown = 1; |
1053 | del_timer_sync(&xprt->timer); | 1082 | del_timer_sync(&xprt->timer); |
1054 | 1083 | ||
1084 | rpc_destroy_wait_queue(&xprt->binding); | ||
1085 | rpc_destroy_wait_queue(&xprt->pending); | ||
1086 | rpc_destroy_wait_queue(&xprt->sending); | ||
1087 | rpc_destroy_wait_queue(&xprt->resend); | ||
1088 | rpc_destroy_wait_queue(&xprt->backlog); | ||
1055 | /* | 1089 | /* |
1056 | * Tear down transport state and free the rpc_xprt | 1090 | * Tear down transport state and free the rpc_xprt |
1057 | */ | 1091 | */ |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 613daf8c1ff7..ddbe981ab516 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -136,12 +136,6 @@ static ctl_table sunrpc_table[] = { | |||
136 | #endif | 136 | #endif |
137 | 137 | ||
138 | /* | 138 | /* |
139 | * How many times to try sending a request on a socket before waiting | ||
140 | * for the socket buffer to clear. | ||
141 | */ | ||
142 | #define XS_SENDMSG_RETRY (10U) | ||
143 | |||
144 | /* | ||
145 | * Time out for an RPC UDP socket connect. UDP socket connects are | 139 | * Time out for an RPC UDP socket connect. UDP socket connects are |
146 | * synchronous, but we set a timeout anyway in case of resource | 140 | * synchronous, but we set a timeout anyway in case of resource |
147 | * exhaustion on the local host. | 141 | * exhaustion on the local host. |
@@ -516,6 +510,14 @@ out: | |||
516 | return sent; | 510 | return sent; |
517 | } | 511 | } |
518 | 512 | ||
513 | static void xs_nospace_callback(struct rpc_task *task) | ||
514 | { | ||
515 | struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); | ||
516 | |||
517 | transport->inet->sk_write_pending--; | ||
518 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
519 | } | ||
520 | |||
519 | /** | 521 | /** |
520 | * xs_nospace - place task on wait queue if transmit was incomplete | 522 | * xs_nospace - place task on wait queue if transmit was incomplete |
521 | * @task: task to put to sleep | 523 | * @task: task to put to sleep |
@@ -531,20 +533,27 @@ static void xs_nospace(struct rpc_task *task) | |||
531 | task->tk_pid, req->rq_slen - req->rq_bytes_sent, | 533 | task->tk_pid, req->rq_slen - req->rq_bytes_sent, |
532 | req->rq_slen); | 534 | req->rq_slen); |
533 | 535 | ||
534 | if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { | 536 | /* Protect against races with write_space */ |
535 | /* Protect against races with write_space */ | 537 | spin_lock_bh(&xprt->transport_lock); |
536 | spin_lock_bh(&xprt->transport_lock); | 538 | |
537 | 539 | /* Don't race with disconnect */ | |
538 | /* Don't race with disconnect */ | 540 | if (xprt_connected(xprt)) { |
539 | if (!xprt_connected(xprt)) | 541 | if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { |
540 | task->tk_status = -ENOTCONN; | 542 | /* |
541 | else if (test_bit(SOCK_NOSPACE, &transport->sock->flags)) | 543 | * Notify TCP that we're limited by the application |
542 | xprt_wait_for_buffer_space(task); | 544 | * window size |
545 | */ | ||
546 | set_bit(SOCK_NOSPACE, &transport->sock->flags); | ||
547 | transport->inet->sk_write_pending++; | ||
548 | /* ...and wait for more buffer space */ | ||
549 | xprt_wait_for_buffer_space(task, xs_nospace_callback); | ||
550 | } | ||
551 | } else { | ||
552 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
553 | task->tk_status = -ENOTCONN; | ||
554 | } | ||
543 | 555 | ||
544 | spin_unlock_bh(&xprt->transport_lock); | 556 | spin_unlock_bh(&xprt->transport_lock); |
545 | } else | ||
546 | /* Keep holding the socket if it is blocked */ | ||
547 | rpc_delay(task, HZ>>4); | ||
548 | } | 557 | } |
549 | 558 | ||
550 | /** | 559 | /** |
@@ -588,19 +597,20 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
588 | } | 597 | } |
589 | 598 | ||
590 | switch (status) { | 599 | switch (status) { |
600 | case -EAGAIN: | ||
601 | xs_nospace(task); | ||
602 | break; | ||
591 | case -ENETUNREACH: | 603 | case -ENETUNREACH: |
592 | case -EPIPE: | 604 | case -EPIPE: |
593 | case -ECONNREFUSED: | 605 | case -ECONNREFUSED: |
594 | /* When the server has died, an ICMP port unreachable message | 606 | /* When the server has died, an ICMP port unreachable message |
595 | * prompts ECONNREFUSED. */ | 607 | * prompts ECONNREFUSED. */ |
596 | break; | 608 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); |
597 | case -EAGAIN: | ||
598 | xs_nospace(task); | ||
599 | break; | 609 | break; |
600 | default: | 610 | default: |
611 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
601 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 612 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
602 | -status); | 613 | -status); |
603 | break; | ||
604 | } | 614 | } |
605 | 615 | ||
606 | return status; | 616 | return status; |
@@ -650,7 +660,6 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
650 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 660 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
651 | struct xdr_buf *xdr = &req->rq_snd_buf; | 661 | struct xdr_buf *xdr = &req->rq_snd_buf; |
652 | int status; | 662 | int status; |
653 | unsigned int retry = 0; | ||
654 | 663 | ||
655 | xs_encode_tcp_record_marker(&req->rq_snd_buf); | 664 | xs_encode_tcp_record_marker(&req->rq_snd_buf); |
656 | 665 | ||
@@ -681,9 +690,10 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
681 | return 0; | 690 | return 0; |
682 | } | 691 | } |
683 | 692 | ||
693 | if (status != 0) | ||
694 | continue; | ||
684 | status = -EAGAIN; | 695 | status = -EAGAIN; |
685 | if (retry++ > XS_SENDMSG_RETRY) | 696 | break; |
686 | break; | ||
687 | } | 697 | } |
688 | 698 | ||
689 | switch (status) { | 699 | switch (status) { |
@@ -695,12 +705,13 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
695 | case -ENOTCONN: | 705 | case -ENOTCONN: |
696 | case -EPIPE: | 706 | case -EPIPE: |
697 | status = -ENOTCONN; | 707 | status = -ENOTCONN; |
708 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
698 | break; | 709 | break; |
699 | default: | 710 | default: |
700 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 711 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
701 | -status); | 712 | -status); |
713 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
702 | xs_tcp_shutdown(xprt); | 714 | xs_tcp_shutdown(xprt); |
703 | break; | ||
704 | } | 715 | } |
705 | 716 | ||
706 | return status; | 717 | return status; |
@@ -1073,6 +1084,7 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes) | |||
1073 | { | 1084 | { |
1074 | struct rpc_xprt *xprt; | 1085 | struct rpc_xprt *xprt; |
1075 | read_descriptor_t rd_desc; | 1086 | read_descriptor_t rd_desc; |
1087 | int read; | ||
1076 | 1088 | ||
1077 | dprintk("RPC: xs_tcp_data_ready...\n"); | 1089 | dprintk("RPC: xs_tcp_data_ready...\n"); |
1078 | 1090 | ||
@@ -1084,8 +1096,10 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes) | |||
1084 | 1096 | ||
1085 | /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ | 1097 | /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ |
1086 | rd_desc.arg.data = xprt; | 1098 | rd_desc.arg.data = xprt; |
1087 | rd_desc.count = 65536; | 1099 | do { |
1088 | tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); | 1100 | rd_desc.count = 65536; |
1101 | read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); | ||
1102 | } while (read > 0); | ||
1089 | out: | 1103 | out: |
1090 | read_unlock(&sk->sk_callback_lock); | 1104 | read_unlock(&sk->sk_callback_lock); |
1091 | } | 1105 | } |
@@ -1128,6 +1142,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1128 | break; | 1142 | break; |
1129 | case TCP_FIN_WAIT1: | 1143 | case TCP_FIN_WAIT1: |
1130 | /* The client initiated a shutdown of the socket */ | 1144 | /* The client initiated a shutdown of the socket */ |
1145 | xprt->connect_cookie++; | ||
1131 | xprt->reestablish_timeout = 0; | 1146 | xprt->reestablish_timeout = 0; |
1132 | set_bit(XPRT_CLOSING, &xprt->state); | 1147 | set_bit(XPRT_CLOSING, &xprt->state); |
1133 | smp_mb__before_clear_bit(); | 1148 | smp_mb__before_clear_bit(); |
@@ -1140,6 +1155,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1140 | set_bit(XPRT_CLOSING, &xprt->state); | 1155 | set_bit(XPRT_CLOSING, &xprt->state); |
1141 | xprt_force_disconnect(xprt); | 1156 | xprt_force_disconnect(xprt); |
1142 | case TCP_SYN_SENT: | 1157 | case TCP_SYN_SENT: |
1158 | xprt->connect_cookie++; | ||
1143 | case TCP_CLOSING: | 1159 | case TCP_CLOSING: |
1144 | /* | 1160 | /* |
1145 | * If the server closed down the connection, make sure that | 1161 | * If the server closed down the connection, make sure that |
@@ -1186,9 +1202,11 @@ static void xs_udp_write_space(struct sock *sk) | |||
1186 | 1202 | ||
1187 | if (unlikely(!(sock = sk->sk_socket))) | 1203 | if (unlikely(!(sock = sk->sk_socket))) |
1188 | goto out; | 1204 | goto out; |
1205 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
1206 | |||
1189 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | 1207 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
1190 | goto out; | 1208 | goto out; |
1191 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | 1209 | if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) |
1192 | goto out; | 1210 | goto out; |
1193 | 1211 | ||
1194 | xprt_write_space(xprt); | 1212 | xprt_write_space(xprt); |
@@ -1219,9 +1237,11 @@ static void xs_tcp_write_space(struct sock *sk) | |||
1219 | 1237 | ||
1220 | if (unlikely(!(sock = sk->sk_socket))) | 1238 | if (unlikely(!(sock = sk->sk_socket))) |
1221 | goto out; | 1239 | goto out; |
1240 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
1241 | |||
1222 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | 1242 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
1223 | goto out; | 1243 | goto out; |
1224 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | 1244 | if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) |
1225 | goto out; | 1245 | goto out; |
1226 | 1246 | ||
1227 | xprt_write_space(xprt); | 1247 | xprt_write_space(xprt); |