mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-09-21 11:53:01 +00:00
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
|
@ -638,42 +638,83 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* coda_upcall and coda_downcall routines.
|
* 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);
|
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 (;;) {
|
for (;;) {
|
||||||
if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
|
if (CODA_INTERRUPTIBLE(req))
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
else
|
else
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||||
|
|
||||||
/* got a reply */
|
/* got a reply */
|
||||||
if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
|
if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
|
if (blocked && time_after(jiffies, timeout) &&
|
||||||
/* if this process really wants to die, let it go */
|
CODA_INTERRUPTIBLE(req))
|
||||||
if ( sigismember(&(current->pending.signal), SIGKILL) ||
|
{
|
||||||
sigismember(&(current->pending.signal), SIGINT) )
|
unblock_signals(&old);
|
||||||
break;
|
blocked = 0;
|
||||||
/* signal is present: after timeout always return
|
|
||||||
really smart idea, probably useless ... */
|
|
||||||
if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
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;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_del(&(req->uc_chain));
|
|
||||||
|
|
||||||
/* Interrupted before venus read it. */
|
/* Interrupted before venus read it. */
|
||||||
if (!(req->uc_flags & REQ_READ))
|
if (!(req->uc_flags & REQ_READ))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
|
@ -85,7 +85,6 @@ struct upc_req {
|
||||||
u_short uc_opcode; /* copied from data to save lookup */
|
u_short uc_opcode; /* copied from data to save lookup */
|
||||||
int uc_unique;
|
int uc_unique;
|
||||||
wait_queue_head_t uc_sleep; /* process' wait queue */
|
wait_queue_head_t uc_sleep; /* process' wait queue */
|
||||||
unsigned long uc_posttime;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REQ_ASYNC 0x1
|
#define REQ_ASYNC 0x1
|
||||||
|
|
Loading…
Reference in a new issue