diff options
author | Jan Harkes <jaharkes@cs.cmu.edu> | 2007-07-19 04:48:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:48 -0400 |
commit | fe71b5f3871af2c281a08acd4bedd2da25e46bc3 (patch) | |
tree | cdd4eafff85d86d5495eb4f7c51cfbdf689ec78a /fs/coda | |
parent | 87065519633af79e0577e32a58dcd9cf3c45a8a0 (diff) |
coda: cleanup for upcall handling path
Make the code that processes upcall responses more straightforward, uncovered
at least one bad assumption. We trusted that vc_inuse would be 0 when upcalls
are aborted, however the device may have been reopened.
Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/coda')
-rw-r--r-- | fs/coda/upcall.c | 121 |
1 files changed, 58 insertions, 63 deletions
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index a44ca4155fd5..44332efa8411 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c | |||
@@ -687,27 +687,27 @@ static inline void coda_waitfor_upcall(struct upc_req *vmp) | |||
687 | * are all mapped to -EINTR, while showing a nice warning message. (jh) | 687 | * are all mapped to -EINTR, while showing a nice warning message. (jh) |
688 | * | 688 | * |
689 | */ | 689 | */ |
690 | static int coda_upcall(struct coda_sb_info *sbi, | 690 | static int coda_upcall(struct coda_sb_info *sbi, |
691 | int inSize, int *outSize, | 691 | int inSize, int *outSize, |
692 | union inputArgs *buffer) | 692 | union inputArgs *buffer) |
693 | { | 693 | { |
694 | struct venus_comm *vcommp; | 694 | struct venus_comm *vcommp; |
695 | union outputArgs *out; | 695 | union outputArgs *out; |
696 | struct upc_req *req; | 696 | union inputArgs *sig_inputArgs; |
697 | struct upc_req *req, *sig_req; | ||
697 | int error = 0; | 698 | int error = 0; |
698 | 699 | ||
699 | vcommp = sbi->sbi_vcomm; | 700 | vcommp = sbi->sbi_vcomm; |
700 | if ( !vcommp->vc_inuse ) { | 701 | if (!vcommp->vc_inuse) { |
701 | printk("No pseudo device in upcall comms at %p\n", vcommp); | 702 | printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n"); |
702 | return -ENXIO; | 703 | return -ENXIO; |
703 | } | 704 | } |
704 | 705 | ||
705 | /* Format the request message. */ | 706 | /* Format the request message. */ |
706 | req = upc_alloc(); | 707 | req = upc_alloc(); |
707 | if (!req) { | 708 | if (!req) |
708 | printk("Failed to allocate upc_req structure\n"); | ||
709 | return -ENOMEM; | 709 | return -ENOMEM; |
710 | } | 710 | |
711 | req->uc_data = (void *)buffer; | 711 | req->uc_data = (void *)buffer; |
712 | req->uc_flags = 0; | 712 | req->uc_flags = 0; |
713 | req->uc_inSize = inSize; | 713 | req->uc_inSize = inSize; |
@@ -715,13 +715,13 @@ static int coda_upcall(struct coda_sb_info *sbi, | |||
715 | req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; | 715 | req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; |
716 | req->uc_unique = ++vcommp->vc_seq; | 716 | req->uc_unique = ++vcommp->vc_seq; |
717 | init_waitqueue_head(&req->uc_sleep); | 717 | init_waitqueue_head(&req->uc_sleep); |
718 | 718 | ||
719 | /* Fill in the common input args. */ | 719 | /* Fill in the common input args. */ |
720 | ((union inputArgs *)buffer)->ih.unique = req->uc_unique; | 720 | ((union inputArgs *)buffer)->ih.unique = req->uc_unique; |
721 | 721 | ||
722 | /* Append msg to pending queue and poke Venus. */ | 722 | /* Append msg to pending queue and poke Venus. */ |
723 | list_add_tail(&(req->uc_chain), &vcommp->vc_pending); | 723 | list_add_tail(&req->uc_chain, &vcommp->vc_pending); |
724 | 724 | ||
725 | wake_up_interruptible(&vcommp->vc_waitq); | 725 | wake_up_interruptible(&vcommp->vc_waitq); |
726 | /* We can be interrupted while we wait for Venus to process | 726 | /* We can be interrupted while we wait for Venus to process |
727 | * our request. If the interrupt occurs before Venus has read | 727 | * our request. If the interrupt occurs before Venus has read |
@@ -735,64 +735,59 @@ static int coda_upcall(struct coda_sb_info *sbi, | |||
735 | /* Go to sleep. Wake up on signals only after the timeout. */ | 735 | /* Go to sleep. Wake up on signals only after the timeout. */ |
736 | coda_waitfor_upcall(req); | 736 | coda_waitfor_upcall(req); |
737 | 737 | ||
738 | if (vcommp->vc_inuse) { /* i.e. Venus is still alive */ | 738 | /* Op went through, interrupt or not... */ |
739 | /* Op went through, interrupt or not... */ | 739 | if (req->uc_flags & REQ_WRITE) { |
740 | if (req->uc_flags & REQ_WRITE) { | ||
741 | out = (union outputArgs *)req->uc_data; | 740 | out = (union outputArgs *)req->uc_data; |
742 | /* here we map positive Venus errors to kernel errors */ | 741 | /* here we map positive Venus errors to kernel errors */ |
743 | error = -out->oh.result; | 742 | error = -out->oh.result; |
744 | *outSize = req->uc_outSize; | 743 | *outSize = req->uc_outSize; |
745 | goto exit; | 744 | goto exit; |
746 | } | 745 | } |
747 | if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { | 746 | |
748 | /* Interrupted before venus read it. */ | 747 | error = -EINTR; |
749 | list_del(&(req->uc_chain)); | 748 | if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) { |
750 | /* perhaps the best way to convince the app to | 749 | printk(KERN_WARNING "coda: Unexpected interruption.\n"); |
751 | give up? */ | ||
752 | error = -EINTR; | ||
753 | goto exit; | 750 | goto exit; |
754 | } | ||
755 | if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) { | ||
756 | /* interrupted after Venus did its read, send signal */ | ||
757 | union inputArgs *sig_inputArgs; | ||
758 | struct upc_req *sig_req; | ||
759 | |||
760 | list_del(&(req->uc_chain)); | ||
761 | error = -ENOMEM; | ||
762 | sig_req = upc_alloc(); | ||
763 | if (!sig_req) goto exit; | ||
764 | |||
765 | CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr)); | ||
766 | if (!sig_req->uc_data) { | ||
767 | upc_free(sig_req); | ||
768 | goto exit; | ||
769 | } | ||
770 | |||
771 | error = -EINTR; | ||
772 | sig_inputArgs = (union inputArgs *)sig_req->uc_data; | ||
773 | sig_inputArgs->ih.opcode = CODA_SIGNAL; | ||
774 | sig_inputArgs->ih.unique = req->uc_unique; | ||
775 | |||
776 | sig_req->uc_flags = REQ_ASYNC; | ||
777 | sig_req->uc_opcode = sig_inputArgs->ih.opcode; | ||
778 | sig_req->uc_unique = sig_inputArgs->ih.unique; | ||
779 | sig_req->uc_inSize = sizeof(struct coda_in_hdr); | ||
780 | sig_req->uc_outSize = sizeof(struct coda_in_hdr); | ||
781 | |||
782 | /* insert at head of queue! */ | ||
783 | list_add(&(sig_req->uc_chain), &vcommp->vc_pending); | ||
784 | wake_up_interruptible(&vcommp->vc_waitq); | ||
785 | } else { | ||
786 | printk("Coda: Strange interruption..\n"); | ||
787 | error = -EINTR; | ||
788 | } | ||
789 | } else { /* If venus died i.e. !VC_OPEN(vcommp) */ | ||
790 | printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n", | ||
791 | req->uc_opcode, req->uc_unique, req->uc_flags); | ||
792 | error = -ENODEV; | ||
793 | } | 751 | } |
794 | 752 | ||
795 | exit: | 753 | list_del(&(req->uc_chain)); |
754 | |||
755 | /* Interrupted before venus read it. */ | ||
756 | if (!(req->uc_flags & REQ_READ)) | ||
757 | goto exit; | ||
758 | |||
759 | /* Venus saw the upcall, make sure we can send interrupt signal */ | ||
760 | if (!vcommp->vc_inuse) { | ||
761 | printk(KERN_INFO "coda: Venus dead, not sending signal.\n"); | ||
762 | goto exit; | ||
763 | } | ||
764 | |||
765 | error = -ENOMEM; | ||
766 | sig_req = upc_alloc(); | ||
767 | if (!sig_req) goto exit; | ||
768 | |||
769 | CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr)); | ||
770 | if (!sig_req->uc_data) { | ||
771 | upc_free(sig_req); | ||
772 | goto exit; | ||
773 | } | ||
774 | |||
775 | error = -EINTR; | ||
776 | sig_inputArgs = (union inputArgs *)sig_req->uc_data; | ||
777 | sig_inputArgs->ih.opcode = CODA_SIGNAL; | ||
778 | sig_inputArgs->ih.unique = req->uc_unique; | ||
779 | |||
780 | sig_req->uc_flags = REQ_ASYNC; | ||
781 | sig_req->uc_opcode = sig_inputArgs->ih.opcode; | ||
782 | sig_req->uc_unique = sig_inputArgs->ih.unique; | ||
783 | sig_req->uc_inSize = sizeof(struct coda_in_hdr); | ||
784 | sig_req->uc_outSize = sizeof(struct coda_in_hdr); | ||
785 | |||
786 | /* insert at head of queue! */ | ||
787 | list_add(&(sig_req->uc_chain), &vcommp->vc_pending); | ||
788 | wake_up_interruptible(&vcommp->vc_waitq); | ||
789 | |||
790 | exit: | ||
796 | upc_free(req); | 791 | upc_free(req); |
797 | return error; | 792 | return error; |
798 | } | 793 | } |