here is a short patch that fixes a race condition when doing ioctl(2).
The race condition occurs when the user-thread executing the M_COPYIN dialog between a driver/module and the stream-head goes to sleep & is awakened by a signal.
This patch was written against LiS-2.15.0 but should probably apply without problem over a 2.16.x. Only head.c is affected.
Comments welcome.
-- FiX
-- Francois-Xavier "FiX" KOWALSKI /_ __ Tel: +33 (0)4 76 14 63 27 OpenCall Business Unit -- OCBU / //_/ Fax: +33 (0)4 76 14 43 23 Signalling Products / HP Telnet: 779-6327 http://www.hp.com/go/opencall i n v e n t
--- /vobs/tid/Opencall/Components/OCEK/code/LiS/head/head.c@@/main/ocekgre_hp/4 Mon
Mar 24 10:04:12 2003
+++ head.c Thu Mar 27 17:10:27 2003
@@ -2616,7 +2616,7 @@
{ /* flush read queue */
int msgs_before = lis_qsize(q) ;
int psw ;
- mblk_t *xp ;
+ mblk_t *xp, *tmp = NULL ;
CP(mp,0) ;
/*
@@ -2626,8 +2626,13 @@
LIS_QISRLOCK(q, &psw) ;
while ((xp = lis_get_rput_q(shead)) != NULL)
{
- msgs_before++ ;
- freemsg(xp) ;
+ /*
+ * All messages are temporary saved in a local list.
+ * Correct action will be taken after flush is complete.
+ * Unqueueing now will preserves q_count value.
+ */
+ xp->b_next = tmp ;
+ tmp = xp ;
}
LIS_QISRUNLOCK(q, &psw) ;
@@ -2642,6 +2647,29 @@
|| !lis_hipri(shead->sd_rq->q_first->b_datap->db_type)
)
CLR_SD_FLAG(shead,STRPRI); /* no PCPROTO at head */
+
+ /*
+ * Do not discard messages corresponding to
+ * an in-progress ioctl (IOCWAIT flag).
+ * Discarding them could let the ioctl sleeping for ever
+ * (unless timeout is activated)
+ * Re-queuing now (after flush) preserves q_count value.
+ */
+ LIS_QISRLOCK(q, &psw) ;
+ while ( (xp = tmp) != NULL )
+ {
+ tmp = xp->b_next ;
+ xp->b_next = NULL ;
+ if ( F_ISSET(shead->sd_flag, IOCWAIT) )
+ lis_put_rput_q(shead, xp) ;
+ else
+ {
+ msgs_before++ ;
+ freemsg(xp) ;
+ }
+ }
+ LIS_QISRUNLOCK(q, &psw) ;
+
*mp->b_rptr &= ~FLUSHR ; /* turn off flush read bit */
LisDownCounter(MSGQDSTRHD, msgs_before - lis_qsize(q)) ;
}
@@ -3033,8 +3061,12 @@
if (tmout == 0)
tmout = LIS_DFLT_TIM ;
- // while( hd->sd_iocblk == NULL )
- {
+ /*
+ * while( hd->sd_iocblk == NULL ) statement is removed.
+ * All the sleep/wakeup code is based on a semaphore.
+ * Sleep is called even if Wakeup has already popped.
+ * And the semaphore count is correctly updated.
+ */
if ( F_ISSET(hd->sd_flag,(STRDERR|STWRERR)) )
return(-hd->sd_rerror) ;
SET_SD_FLAG(hd,STIOCTMR);
@@ -3063,7 +3095,7 @@
lis_untmout(&tl);
CLR_SD_FLAG(hd,STIOCTMR);
}
- }
+
return(0); /* got msg */
}/*lis_wait_for_wiocing*/
@@ -3208,6 +3240,14 @@
* Use RTN to return below here.
*/
iocb->ioc_id = hd->sd_iocseq = lis_incr(&lis_iocseq);
+ /*
+ * Reset items that could be not clean after a previous failing ioctl
+ * (ioctl returning on signal or error)
+ * - semaphore > 0
+ * - sd_iocblk != NULL
+ */
+ lis_sem_init(&hd->sd_wiocing, 0) ;
+ hd->sd_iocblk = NULL ;
again: /* wioc lock is always held when here */
if (err < 0)
@@ -7294,5 +7334,6 @@
/*----------------------------------------------------------------------
# Local Variables: ***
# change-log-default-name: "~/src/prj/streams/src/NOTES" ***
+# c-basic-offset: 4 ***
# End: ***
----------------------------------------------------------------------*/
