diff options
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); |
