Home | History | Annotate | Line # | Download | only in raidframe
rf_revent.c revision 1.1
      1 /*	$NetBSD: rf_revent.c,v 1.1 1998/11/13 04:20:34 oster Exp $	*/
      2 /*
      3  * Copyright (c) 1995 Carnegie-Mellon University.
      4  * All rights reserved.
      5  *
      6  * Author:
      7  *
      8  * Permission to use, copy, modify and distribute this software and
      9  * its documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     16  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  */
     28 /*
     29  * revent.c -- reconstruction event handling code
     30  */
     31 /*
     32  * :
     33  * Log: rf_revent.c,v
     34  * Revision 1.22  1996/08/11 00:41:11  jimz
     35  * extern hz only for kernel
     36  *
     37  * Revision 1.21  1996/07/15  05:40:41  jimz
     38  * some recon datastructure cleanup
     39  * better handling of multiple failures
     40  * added undocumented double-recon test
     41  *
     42  * Revision 1.20  1996/06/17  03:18:04  jimz
     43  * include shutdown.h for macroized ShutdownCreate
     44  *
     45  * Revision 1.19  1996/06/10  11:55:47  jimz
     46  * Straightened out some per-array/not-per-array distinctions, fixed
     47  * a couple bugs related to confusion. Added shutdown lists. Removed
     48  * layout shutdown function (now subsumed by shutdown lists).
     49  *
     50  * Revision 1.18  1996/06/07  21:33:04  jimz
     51  * begin using consistent types for sector numbers,
     52  * stripe numbers, row+col numbers, recon unit numbers
     53  *
     54  * Revision 1.17  1996/06/05  18:06:02  jimz
     55  * Major code cleanup. The Great Renaming is now done.
     56  * Better modularity. Better typing. Fixed a bunch of
     57  * synchronization bugs. Made a lot of global stuff
     58  * per-desc or per-array. Removed dead code.
     59  *
     60  * Revision 1.16  1996/06/03  23:28:26  jimz
     61  * more bugfixes
     62  * check in tree to sync for IPDS runs with current bugfixes
     63  * there still may be a problem with threads in the script test
     64  * getting I/Os stuck- not trivially reproducible (runs ~50 times
     65  * in a row without getting stuck)
     66  *
     67  * Revision 1.15  1996/05/30  12:59:18  jimz
     68  * make etimer happier, more portable
     69  *
     70  * Revision 1.14  1996/05/20  16:13:40  jimz
     71  * switch to rf_{mutex,cond}_{init,destroy}
     72  * use RF_FREELIST for revents
     73  *
     74  * Revision 1.13  1996/05/18  20:09:47  jimz
     75  * bit of cleanup to compile cleanly in kernel, once again
     76  *
     77  * Revision 1.12  1996/05/18  19:51:34  jimz
     78  * major code cleanup- fix syntax, make some types consistent,
     79  * add prototypes, clean out dead code, et cetera
     80  *
     81  */
     82 
     83 #ifdef _KERNEL
     84 #define KERNEL
     85 #endif
     86 
     87 #include <sys/errno.h>
     88 
     89 #include "rf_raid.h"
     90 #include "rf_revent.h"
     91 #include "rf_etimer.h"
     92 #include "rf_general.h"
     93 #include "rf_freelist.h"
     94 #include "rf_desc.h"
     95 #include "rf_shutdown.h"
     96 
     97 static RF_FreeList_t *rf_revent_freelist;
     98 #define RF_MAX_FREE_REVENT 128
     99 #define RF_REVENT_INC        8
    100 #define RF_REVENT_INITIAL    8
    101 
    102 
    103 #ifdef KERNEL
    104 
    105 #include <sys/proc.h>
    106 
    107 extern int hz;
    108 
    109 #ifndef __NetBSD__
    110 #define DO_WAIT(_rc)       mpsleep(&(_rc)->eventQueue, PZERO, "raidframe eventq", 0, \
    111 			      (void *) simple_lock_addr((_rc)->eq_mutex), MS_LOCK_SIMPLE)
    112 #else
    113 #define DO_WAIT(_rc)   tsleep(&(_rc)->eventQueue, PRIBIO | PCATCH, "raidframe eventq", 0)
    114 #endif
    115 
    116 #define DO_SIGNAL(_rc)     wakeup(&(_rc)->eventQueue)
    117 
    118 #else      /* KERNEL */
    119 
    120 #define DO_WAIT(_rc)       RF_WAIT_COND((_rc)->eq_cond, (_rc)->eq_mutex)
    121 #define DO_SIGNAL(_rc)     RF_SIGNAL_COND((_rc)->eq_cond)
    122 
    123 #endif     /* KERNEL */
    124 
    125 static void rf_ShutdownReconEvent(void *);
    126 
    127 static RF_ReconEvent_t *GetReconEventDesc(RF_RowCol_t row, RF_RowCol_t col,
    128 	void *arg, RF_Revent_t type);
    129 RF_ReconEvent_t *rf_GetNextReconEvent(RF_RaidReconDesc_t   *,
    130 				      RF_RowCol_t, void (*continueFunc)(void *),
    131 				      void *);
    132 
    133 static void rf_ShutdownReconEvent(ignored)
    134   void  *ignored;
    135 {
    136 	RF_FREELIST_DESTROY(rf_revent_freelist,next,(RF_ReconEvent_t *));
    137 }
    138 
    139 int rf_ConfigureReconEvent(listp)
    140   RF_ShutdownList_t  **listp;
    141 {
    142   int rc;
    143 
    144   RF_FREELIST_CREATE(rf_revent_freelist, RF_MAX_FREE_REVENT,
    145     RF_REVENT_INC, sizeof(RF_ReconEvent_t));
    146   if (rf_revent_freelist == NULL)
    147     return(ENOMEM);
    148   rc = rf_ShutdownCreate(listp, rf_ShutdownReconEvent, NULL);
    149   if (rc) {
    150     RF_ERRORMSG3("Unable to add to shutdown list file %s line %d rc=%d\n", __FILE__,
    151       __LINE__, rc);
    152     rf_ShutdownReconEvent(NULL);
    153     return(rc);
    154   }
    155   RF_FREELIST_PRIME(rf_revent_freelist, RF_REVENT_INITIAL,next,
    156     (RF_ReconEvent_t *));
    157   return(0);
    158 }
    159 
    160 /* returns the next reconstruction event, blocking the calling thread until
    161  * one becomes available
    162  */
    163 
    164 /* will now return null if it is blocked or will return an event if it is not */
    165 
    166 RF_ReconEvent_t *rf_GetNextReconEvent(reconDesc, row, continueFunc, continueArg)
    167   RF_RaidReconDesc_t   *reconDesc;
    168   RF_RowCol_t           row;
    169   void                (*continueFunc)(void *);
    170   void                 *continueArg;
    171 {
    172   RF_Raid_t *raidPtr = reconDesc->raidPtr;
    173   RF_ReconCtrl_t *rctrl = raidPtr->reconControl[row];
    174   RF_ReconEvent_t *event;
    175 
    176   RF_ASSERT( row >= 0 && row <= raidPtr->numRow );
    177   RF_LOCK_MUTEX(rctrl->eq_mutex);
    178   RF_ASSERT( (rctrl->eventQueue==NULL) == (rctrl->eq_count == 0));  /* q null and count==0 must be equivalent conditions */
    179 
    180 
    181   rctrl->continueFunc=continueFunc;
    182   rctrl->continueArg=continueArg;
    183 
    184 #ifdef SIMULATE
    185   if (!rctrl->eventQueue) {
    186     RF_UNLOCK_MUTEX(rctrl->eq_mutex);
    187     return (NULL);
    188   }
    189 #else /* SIMULATE */
    190 
    191 #ifdef KERNEL
    192 
    193 /* mpsleep timeout value: secs = timo_val/hz.  'ticks' here is defined as cycle-counter ticks, not softclock ticks */
    194 #define MAX_RECON_EXEC_TICKS 15000000  /* 150 Mhz => this many ticks in 100 ms */
    195 #define RECON_DELAY_MS 25
    196 #define RECON_TIMO     ((RECON_DELAY_MS * hz) / 1000)
    197 
    198   /* we are not pre-emptible in the kernel, but we don't want to run forever.  If we run w/o blocking
    199    * for more than MAX_RECON_EXEC_TICKS ticks of the cycle counter, delay for RECON_DELAY before continuing.
    200    * this may murder us with context switches, so we may need to increase both the MAX...TICKS and the RECON_DELAY_MS.
    201    */
    202   if (reconDesc->reconExecTimerRunning) {
    203     int status;
    204 
    205     RF_ETIMER_STOP(reconDesc->recon_exec_timer);
    206     RF_ETIMER_EVAL(reconDesc->recon_exec_timer);
    207     reconDesc->reconExecTicks += RF_ETIMER_VAL_TICKS(reconDesc->recon_exec_timer);
    208     if (reconDesc->reconExecTicks > reconDesc->maxReconExecTicks)
    209       reconDesc->maxReconExecTicks = reconDesc->reconExecTicks;
    210     if (reconDesc->reconExecTicks >= MAX_RECON_EXEC_TICKS) {
    211       /* we've been running too long.  delay for RECON_DELAY_MS */
    212 #if RF_RECON_STATS > 0
    213       reconDesc->numReconExecDelays++;
    214 #endif /* RF_RECON_STATS > 0 */
    215 #ifndef __NetBSD__
    216       status = mpsleep(&reconDesc->reconExecTicks, PZERO, "recon delay", RECON_TIMO, (void *) simple_lock_addr(rctrl->eq_mutex), MS_LOCK_SIMPLE);
    217 #else
    218       status = tsleep(&reconDesc->reconExecTicks, PRIBIO | PCATCH, "recon delay", RECON_TIMO );
    219 #endif
    220       RF_ASSERT(status == EWOULDBLOCK);
    221       reconDesc->reconExecTicks = 0;
    222     }
    223   }
    224 
    225 #endif /* KERNEL */
    226 
    227   while (!rctrl->eventQueue) {
    228 #if RF_RECON_STATS > 0
    229     reconDesc->numReconEventWaits++;
    230 #endif /* RF_RECON_STATS > 0 */
    231     DO_WAIT(rctrl);
    232 #ifdef KERNEL
    233     reconDesc->reconExecTicks = 0; /* we've just waited */
    234 #endif /* KERNEL */
    235   }
    236 
    237 #endif /* SIMULATE */
    238 
    239 #ifdef KERNEL
    240   reconDesc->reconExecTimerRunning = 1;
    241   RF_ETIMER_START(reconDesc->recon_exec_timer);
    242 #endif /* KERNEL */
    243 
    244   event = rctrl->eventQueue;
    245   rctrl->eventQueue = event->next;
    246   event->next = NULL;
    247   rctrl->eq_count--;
    248   RF_ASSERT( (rctrl->eventQueue==NULL) == (rctrl->eq_count == 0));  /* q null and count==0 must be equivalent conditions */
    249   RF_UNLOCK_MUTEX(rctrl->eq_mutex);
    250   return(event);
    251 }
    252 
    253 /* enqueues a reconstruction event on the indicated queue */
    254 void rf_CauseReconEvent(raidPtr, row, col, arg, type)
    255   RF_Raid_t    *raidPtr;
    256   RF_RowCol_t   row;
    257   RF_RowCol_t   col;
    258   void         *arg;
    259   RF_Revent_t   type;
    260 {
    261   RF_ReconCtrl_t *rctrl = raidPtr->reconControl[row];
    262   RF_ReconEvent_t *event = GetReconEventDesc(row, col, arg, type);
    263 
    264   if (type == RF_REVENT_BUFCLEAR) {
    265     RF_ASSERT(col != rctrl->fcol);
    266   }
    267 
    268   RF_ASSERT( row >= 0 && row <= raidPtr->numRow && col >=0 && col <= raidPtr->numCol );
    269   RF_LOCK_MUTEX(rctrl->eq_mutex);
    270   RF_ASSERT( (rctrl->eventQueue==NULL) == (rctrl->eq_count == 0));  /* q null and count==0 must be equivalent conditions */
    271   event->next = rctrl->eventQueue;
    272   rctrl->eventQueue = event;
    273   rctrl->eq_count++;
    274   RF_UNLOCK_MUTEX(rctrl->eq_mutex);
    275 
    276 #ifndef SIMULATE
    277   DO_SIGNAL(rctrl);
    278 #else /* !SIMULATE */
    279   (rctrl->continueFunc)(rctrl->continueArg);
    280 #endif /* !SIMULATE */
    281 }
    282 
    283 /* allocates and initializes a recon event descriptor */
    284 static RF_ReconEvent_t *GetReconEventDesc(row, col, arg, type)
    285   RF_RowCol_t   row;
    286   RF_RowCol_t   col;
    287   void         *arg;
    288   RF_Revent_t   type;
    289 {
    290 	RF_ReconEvent_t *t;
    291 
    292 	RF_FREELIST_GET(rf_revent_freelist,t,next,(RF_ReconEvent_t *));
    293 	if (t == NULL)
    294 		return(NULL);
    295 	t->col = col;
    296 	t->arg = arg;
    297 	t->type = type;
    298 	return(t);
    299 }
    300 
    301 void rf_FreeReconEventDesc(event)
    302   RF_ReconEvent_t  *event;
    303 {
    304 	RF_FREELIST_FREE(rf_revent_freelist,event,next);
    305 }
    306