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>
This commit is contained in:
parent
fe71b5f387
commit
d9664c95af
2 changed files with 61 additions and 23 deletions
|
@ -638,42 +638,83 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
|
|||
|
||||
/*
|
||||
* coda_upcall and coda_downcall routines.
|
||||
*
|
||||
*/
|
||||
static void block_signals(sigset_t *old)
|
||||
{
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
*old = current->blocked;
|
||||
|
||||
static inline void coda_waitfor_upcall(struct upc_req *vmp)
|
||||
sigfillset(¤t->blocked);
|
||||
sigdelset(¤t->blocked, SIGKILL);
|
||||
sigdelset(¤t->blocked, SIGSTOP);
|
||||
sigdelset(¤t->blocked, SIGINT);
|
||||
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
|
||||
static void unblock_signals(sigset_t *old)
|
||||
{
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = *old;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
|
||||
/* Don't allow signals to interrupt the following upcalls before venus
|
||||
* has seen them,
|
||||
* - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
|
||||
* - CODA_STORE (to avoid data loss)
|
||||
*/
|
||||
#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
|
||||
(((r)->uc_opcode != CODA_CLOSE && \
|
||||
(r)->uc_opcode != CODA_STORE && \
|
||||
(r)->uc_opcode != CODA_RELEASE) || \
|
||||
(r)->uc_flags & REQ_READ))
|
||||
|
||||
static inline void coda_waitfor_upcall(struct upc_req *req)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
unsigned long timeout = jiffies + coda_timeout * HZ;
|
||||
sigset_t old;
|
||||
int blocked;
|
||||
|
||||
vmp->uc_posttime = jiffies;
|
||||
block_signals(&old);
|
||||
blocked = 1;
|
||||
|
||||
add_wait_queue(&vmp->uc_sleep, &wait);
|
||||
add_wait_queue(&req->uc_sleep, &wait);
|
||||
for (;;) {
|
||||
if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
|
||||
if (CODA_INTERRUPTIBLE(req))
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
else
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
|
||||
/* got a reply */
|
||||
if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
|
||||
if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
|
||||
break;
|
||||
|
||||
if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
|
||||
/* if this process really wants to die, let it go */
|
||||
if ( sigismember(&(current->pending.signal), SIGKILL) ||
|
||||
sigismember(&(current->pending.signal), SIGINT) )
|
||||
break;
|
||||
/* signal is present: after timeout always return
|
||||
really smart idea, probably useless ... */
|
||||
if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
|
||||
break;
|
||||
if (blocked && time_after(jiffies, timeout) &&
|
||||
CODA_INTERRUPTIBLE(req))
|
||||
{
|
||||
unblock_signals(&old);
|
||||
blocked = 0;
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
remove_wait_queue(&vmp->uc_sleep, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
return;
|
||||
if (signal_pending(current)) {
|
||||
list_del(&req->uc_chain);
|
||||
break;
|
||||
}
|
||||
|
||||
if (blocked)
|
||||
schedule_timeout(HZ);
|
||||
else
|
||||
schedule();
|
||||
}
|
||||
if (blocked)
|
||||
unblock_signals(&old);
|
||||
|
||||
remove_wait_queue(&req->uc_sleep, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
|
||||
|
@ -750,8 +791,6 @@ static int coda_upcall(struct coda_sb_info *sbi,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
list_del(&(req->uc_chain));
|
||||
|
||||
/* Interrupted before venus read it. */
|
||||
if (!(req->uc_flags & REQ_READ))
|
||||
goto exit;
|
||||
|
|
|
@ -85,7 +85,6 @@ struct upc_req {
|
|||
u_short uc_opcode; /* copied from data to save lookup */
|
||||
int uc_unique;
|
||||
wait_queue_head_t uc_sleep; /* process' wait queue */
|
||||
unsigned long uc_posttime;
|
||||
};
|
||||
|
||||
#define REQ_ASYNC 0x1
|
||||
|
|
Loading…
Reference in a new issue