diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-04-15 16:56:39 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-04-19 16:53:05 -0400 |
commit | c9d8f89d9816c1d16ada492aa547a4d692508c0d (patch) | |
tree | d85339019cff084c11d4fceaf194fc5e34588d61 /fs/nfs/direct.c | |
parent | fdd1e74c89fe39259a29c494209abad63ff76f82 (diff) |
NFS: Ensure that the write code cleans up properly when rpc_run_task() fails
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 9d9085b93a32..abf8e0286e35 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -508,27 +508,34 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
508 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) | 508 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
509 | { | 509 | { |
510 | struct nfs_write_data *data = calldata; | 510 | struct nfs_write_data *data = calldata; |
511 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
512 | 511 | ||
513 | /* Call the NFS version-specific code */ | 512 | /* Call the NFS version-specific code */ |
514 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 513 | NFS_PROTO(data->inode)->commit_done(task, data); |
515 | return; | 514 | } |
516 | if (unlikely(task->tk_status < 0)) { | 515 | |
516 | static void nfs_direct_commit_release(void *calldata) | ||
517 | { | ||
518 | struct nfs_write_data *data = calldata; | ||
519 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
520 | int status = data->task.tk_status; | ||
521 | |||
522 | if (status < 0) { | ||
517 | dprintk("NFS: %5u commit failed with error %d.\n", | 523 | dprintk("NFS: %5u commit failed with error %d.\n", |
518 | task->tk_pid, task->tk_status); | 524 | data->task.tk_pid, status); |
519 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 525 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
520 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 526 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { |
521 | dprintk("NFS: %5u commit verify failed\n", task->tk_pid); | 527 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
522 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 528 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
523 | } | 529 | } |
524 | 530 | ||
525 | dprintk("NFS: %5u commit returned %d\n", task->tk_pid, task->tk_status); | 531 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
526 | nfs_direct_write_complete(dreq, data->inode); | 532 | nfs_direct_write_complete(dreq, data->inode); |
533 | nfs_commitdata_release(calldata); | ||
527 | } | 534 | } |
528 | 535 | ||
529 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 536 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
530 | .rpc_call_done = nfs_direct_commit_result, | 537 | .rpc_call_done = nfs_direct_commit_result, |
531 | .rpc_release = nfs_commit_release, | 538 | .rpc_release = nfs_direct_commit_release, |
532 | }; | 539 | }; |
533 | 540 | ||
534 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 541 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
@@ -596,7 +603,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
596 | 603 | ||
597 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) | 604 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) |
598 | { | 605 | { |
599 | dreq->commit_data = nfs_commit_alloc(); | 606 | dreq->commit_data = nfs_commitdata_alloc(); |
600 | if (dreq->commit_data != NULL) | 607 | if (dreq->commit_data != NULL) |
601 | dreq->commit_data->req = (struct nfs_page *) dreq; | 608 | dreq->commit_data->req = (struct nfs_page *) dreq; |
602 | } | 609 | } |
@@ -617,11 +624,20 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
617 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | 624 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
618 | { | 625 | { |
619 | struct nfs_write_data *data = calldata; | 626 | struct nfs_write_data *data = calldata; |
620 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
621 | int status = task->tk_status; | ||
622 | 627 | ||
623 | if (nfs_writeback_done(task, data) != 0) | 628 | if (nfs_writeback_done(task, data) != 0) |
624 | return; | 629 | return; |
630 | } | ||
631 | |||
632 | /* | ||
633 | * NB: Return the value of the first error return code. Subsequent | ||
634 | * errors after the first one are ignored. | ||
635 | */ | ||
636 | static void nfs_direct_write_release(void *calldata) | ||
637 | { | ||
638 | struct nfs_write_data *data = calldata; | ||
639 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
640 | int status = data->task.tk_status; | ||
625 | 641 | ||
626 | spin_lock(&dreq->lock); | 642 | spin_lock(&dreq->lock); |
627 | 643 | ||
@@ -643,23 +659,13 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | |||
643 | break; | 659 | break; |
644 | case NFS_ODIRECT_DO_COMMIT: | 660 | case NFS_ODIRECT_DO_COMMIT: |
645 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { | 661 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { |
646 | dprintk("NFS: %5u write verify failed\n", task->tk_pid); | 662 | dprintk("NFS: %5u write verify failed\n", data->task.tk_pid); |
647 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 663 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
648 | } | 664 | } |
649 | } | 665 | } |
650 | } | 666 | } |
651 | out_unlock: | 667 | out_unlock: |
652 | spin_unlock(&dreq->lock); | 668 | spin_unlock(&dreq->lock); |
653 | } | ||
654 | |||
655 | /* | ||
656 | * NB: Return the value of the first error return code. Subsequent | ||
657 | * errors after the first one are ignored. | ||
658 | */ | ||
659 | static void nfs_direct_write_release(void *calldata) | ||
660 | { | ||
661 | struct nfs_write_data *data = calldata; | ||
662 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
663 | 669 | ||
664 | if (put_dreq(dreq)) | 670 | if (put_dreq(dreq)) |
665 | nfs_direct_write_complete(dreq, data->inode); | 671 | nfs_direct_write_complete(dreq, data->inode); |