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 | d9664c95afe5baa92ea56eff6a1c18e7b7a2cbe7 (patch) | |
tree | 642019723c5ec027aabca8ce872468babc9cfacd /fs/coda | |
parent | fe71b5f3871af2c281a08acd4bedd2da25e46bc3 (diff) |
coda: block signals during upcall processing
We ignore signals for about 30 seconds to give userspace a chance to see the
upcall. As we did not block signals we ended up in a busy loop for the
remainder of the period when a signal is received.
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 | 81 |
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 | */ |
642 | static void block_signals(sigset_t *old) | ||
643 | { | ||
644 | spin_lock_irq(¤t->sighand->siglock); | ||
645 | *old = current->blocked; | ||
646 | |||
647 | sigfillset(¤t->blocked); | ||
648 | sigdelset(¤t->blocked, SIGKILL); | ||
649 | sigdelset(¤t->blocked, SIGSTOP); | ||
650 | sigdelset(¤t->blocked, SIGINT); | ||
651 | |||
652 | recalc_sigpending(); | ||
653 | spin_unlock_irq(¤t->sighand->siglock); | ||
654 | } | ||
655 | |||
656 | static void unblock_signals(sigset_t *old) | ||
657 | { | ||
658 | spin_lock_irq(¤t->sighand->siglock); | ||
659 | current->blocked = *old; | ||
660 | recalc_sigpending(); | ||
661 | spin_unlock_irq(¤t->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 | ||
644 | static inline void coda_waitfor_upcall(struct upc_req *vmp) | 675 | static 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; |