diff options
| author | Jan Harkes <jaharkes@cs.cmu.edu> | 2007-07-19 01:48:46 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 10:04:48 -0700 | 
| commit | d9664c95afe5baa92ea56eff6a1c18e7b7a2cbe7 (patch) | |
| tree | 642019723c5ec027aabca8ce872468babc9cfacd | |
| parent | fe71b5f3871af2c281a08acd4bedd2da25e46bc3 (diff) | |
| download | olio-linux-3.10-d9664c95afe5baa92ea56eff6a1c18e7b7a2cbe7.tar.xz olio-linux-3.10-d9664c95afe5baa92ea56eff6a1c18e7b7a2cbe7.zip  | |
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>
| -rw-r--r-- | fs/coda/upcall.c | 81 | ||||
| -rw-r--r-- | include/linux/coda_psdev.h | 1 | 
2 files changed, 60 insertions, 22 deletions
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 44332efa841..ad65ee01790 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -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; + +	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 *vmp) +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(); + +		if (signal_pending(current)) { +			list_del(&req->uc_chain); +			break; +		} + +		if (blocked) +			schedule_timeout(HZ); +		else +			schedule();  	} -	remove_wait_queue(&vmp->uc_sleep, &wait); -	set_current_state(TASK_RUNNING); +	if (blocked) +		unblock_signals(&old); -	return; +	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; diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index b541bb3d1f4..f28c2f7fd45 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -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  |