aboutsummaryrefslogtreecommitdiffstats
path: root/fs/coda
diff options
context:
space:
mode:
Diffstat (limited to 'fs/coda')
-rw-r--r--fs/coda/upcall.c81
1 files changed, 60 insertions, 21 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;