diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
commit | 563307b2fa15d687abc54bd980b9847ebf0e3231 (patch) | |
tree | 7f16be30217a2e66360ede97aa27d07a4ebd7e55 /fs/nfs | |
parent | 10c993a6b5418cb1026775765ba4c70ffb70853d (diff) | |
parent | 233607dbbc823caf685e778cabc49fb7f679900b (diff) |
Merge git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (80 commits)
SUNRPC: Invalidate the RPCSEC_GSS session if the server dropped the request
make nfs_automount_list static
NFS: remove duplicate flags assignment from nfs_validate_mount_data
NFS - fix potential NULL pointer dereference v2
SUNRPC: Don't change the RPCSEC_GSS context on a credential that is in use
SUNRPC: Fix a race in gss_refresh_upcall()
SUNRPC: Don't disconnect more than once if retransmitting NFSv4 requests
SUNRPC: Remove the unused export of xprt_force_disconnect
SUNRPC: remove XS_SENDMSG_RETRY
SUNRPC: Protect creds against early garbage collection
NFSv4: Attempt to use machine credentials in SETCLIENTID calls
NFSv4: Reintroduce machine creds
NFSv4: Don't use cred->cr_ops->cr_name in nfs4_proc_setclientid()
nfs: fix printout of multiword bitfields
nfs: return negative error value from nfs{,4}_stat_to_errno
NLM/lockd: Ensure client locking calls use correct credentials
NFS: Remove the buggy lock-if-signalled case from do_setlk()
NLM/lockd: Fix a race when cancelling a blocking lock
NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call
NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel
...
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/Makefile | 3 | ||||
-rw-r--r-- | fs/nfs/client.c | 23 | ||||
-rw-r--r-- | fs/nfs/dir.c | 2 | ||||
-rw-r--r-- | fs/nfs/direct.c | 88 | ||||
-rw-r--r-- | fs/nfs/file.c | 18 | ||||
-rw-r--r-- | fs/nfs/inode.c | 45 | ||||
-rw-r--r-- | fs/nfs/internal.h | 13 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 113 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 71 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 39 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 49 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 147 | ||||
-rw-r--r-- | fs/nfs/read.c | 94 | ||||
-rw-r--r-- | fs/nfs/super.c | 147 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 207 |
17 files changed, 671 insertions, 392 deletions
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 | } |