aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/coda/upcall.c81
-rw-r--r--include/linux/coda_psdev.h1
2 files changed, 60 insertions, 22 deletions
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 44332efa8411..ad65ee01790f 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -638,42 +638,83 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
638 638
639/* 639/*
640 * coda_upcall and coda_downcall routines. 640 * coda_upcall and coda_downcall routines.
641 *
642 */ 641 */
642static void block_signals(sigset_t *old)
643{
644 spin_lock_irq(&current->sighand->siglock);
645 *old = current->blocked;
646
647 sigfillset(&current->blocked);
648 sigdelset(&current->blocked, SIGKILL);
649 sigdelset(&current->blocked, SIGSTOP);
650 sigdelset(&current->blocked, SIGINT);
651
652 recalc_sigpending();
653 spin_unlock_irq(&current->sighand->siglock);
654}
655
656static void unblock_signals(sigset_t *old)
657{
658 spin_lock_irq(&current->sighand->siglock);
659 current->blocked = *old;
660 recalc_sigpending();
661 spin_unlock_irq(&current->sighand->siglock);
662}
663
664/* Don't allow signals to interrupt the following upcalls before venus
665 * has seen them,
666 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
667 * - CODA_STORE (to avoid data loss)
668 */
669#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
670 (((r)->uc_opcode != CODA_CLOSE && \
671 (r)->uc_opcode != CODA_STORE && \
672 (r)->uc_opcode != CODA_RELEASE) || \
673 (r)->uc_flags & REQ_READ))
643 674
644static inline void coda_waitfor_upcall(struct upc_req *vmp) 675static inline void coda_waitfor_upcall(struct upc_req *req)
645{ 676{
646 DECLARE_WAITQUEUE(wait, current); 677 DECLARE_WAITQUEUE(wait, current);
678 unsigned long timeout = jiffies + coda_timeout * HZ;
679 sigset_t old;
680 int blocked;
647 681
648 vmp->uc_posttime = jiffies; 682 block_signals(&old);
683 blocked = 1;
649 684
650 add_wait_queue(&vmp->uc_sleep, &wait); 685 add_wait_queue(&req->uc_sleep, &wait);
651 for (;;) { 686 for (;;) {
652 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 687 if (CODA_INTERRUPTIBLE(req))
653 set_current_state(TASK_INTERRUPTIBLE); 688 set_current_state(TASK_INTERRUPTIBLE);
654 else 689 else
655 set_current_state(TASK_UNINTERRUPTIBLE); 690 set_current_state(TASK_UNINTERRUPTIBLE);
656 691
657 /* got a reply */ 692 /* got a reply */
658 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) ) 693 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
659 break; 694 break;
660 695
661 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) { 696 if (blocked && time_after(jiffies, timeout) &&
662 /* if this process really wants to die, let it go */ 697 CODA_INTERRUPTIBLE(req))
663 if ( sigismember(&(current->pending.signal), SIGKILL) || 698 {
664 sigismember(&(current->pending.signal), SIGINT) ) 699 unblock_signals(&old);
665 break; 700 blocked = 0;
666 /* signal is present: after timeout always return
667 really smart idea, probably useless ... */
668 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
669 break;
670 } 701 }
671 schedule(); 702
703 if (signal_pending(current)) {
704 list_del(&req->uc_chain);
705 break;
706 }
707
708 if (blocked)
709 schedule_timeout(HZ);
710 else
711 schedule();
672 } 712 }
673 remove_wait_queue(&vmp->uc_sleep, &wait); 713 if (blocked)
674 set_current_state(TASK_RUNNING); 714 unblock_signals(&old);
675 715
676 return; 716 remove_wait_queue(&req->uc_sleep, &wait);
717 set_current_state(TASK_RUNNING);
677} 718}
678 719
679 720
@@ -750,8 +791,6 @@ static int coda_upcall(struct coda_sb_info *sbi,
750 goto exit; 791 goto exit;
751 } 792 }
752 793
753 list_del(&(req->uc_chain));
754
755 /* Interrupted before venus read it. */ 794 /* Interrupted before venus read it. */
756 if (!(req->uc_flags & REQ_READ)) 795 if (!(req->uc_flags & REQ_READ))
757 goto exit; 796 goto exit;
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index b541bb3d1f4b..f28c2f7fd454 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -85,7 +85,6 @@ struct upc_req {
85 u_short uc_opcode; /* copied from data to save lookup */ 85 u_short uc_opcode; /* copied from data to save lookup */
86 int uc_unique; 86 int uc_unique;
87 wait_queue_head_t uc_sleep; /* process' wait queue */ 87 wait_queue_head_t uc_sleep; /* process' wait queue */
88 unsigned long uc_posttime;
89}; 88};
90 89
91#define REQ_ASYNC 0x1 90#define REQ_ASYNC 0x1