📄 dcachecbio.c
字号:
{ logMsg(fmt,a1,a2,a3,a4,a5,a6); }#include "assert.h"/********************************************************************************* dcacheDevCreate - Create a disk cache** This routine creates a disk cache unit. * The disk cache unit accesses the disk through the subordinate CBIO* device driver, provided with the <subDev> argument.** A valid block device handle may be provided instead of a CBIO* handle, in which case it will be automatically converted into* a CBIO device by using the wrapper functionality from cbioLib.** Memory which will be used for caching disk data may be provided by the* caller with <ramAddr>, or it will be allocated by dcacheDevCreate() from* the common system memory pool, if <memAddr> is passed as NULL. <memSize> is* the amount of memory to use for disk caching, if 0 is passed, then a* certain default value will be calculated, based on available memory.* <description> is a string describing the device, used later by* dcacheShow(), and is useful when there are many cached disk devices.** A maximum of 16 disk cache devices are supported at this time.* * RETURNS: disk cache device handle, or NULL if there is not enough* memory to satisfy the request, or the <blkDev> handle is invalid.** INTERNAL* There is not an appropriate Destroy function at this time.*/CBIO_DEV_ID dcacheDevCreate ( CBIO_DEV_ID subDev, /* block device handle */ char * ramAddr, /* where it is in memory (NULL = malloc) */ int memSize, /* amount of memory to use */ char * description /* device description string */ ) { CBIO_DEV * pDev = NULL ; CBIO_DEV * pSubDev = NULL ; int i ; pSubDev = cbioDevVerify( subDev, FALSE ) ; if(pSubDev == NULL) { return NULL; /* failed */ } /* Fill in defaults for args with 0 value */ if( memSize == 0) memSize = min( memFindMax()/16, 188*1024 ) ; cbioLibInit(); /* just in case */ if( cbioClassId->createRtn != NULL ) pDev = (CBIO_DEV_ID) cbioClassId->createRtn( ramAddr, memSize ); if( pDev == NULL ) return( NULL ); /* failed */ pDev->pDc = NULL ; /* cbioFuncs is staticly allocated in each driver. */ pDev->pFuncs = &cbioFuncs; /* mutex is not created yet */ taskLock(); /* allocate extension control structure */ for(i = (int) 0; i < (int) NELEMENTS(dcacheCtrl); i++) { if( dcacheCtrl[i].cbio_dev == NULL ) { pDev->pDc = & dcacheCtrl[i] ; break; } } if( pDev->pDc == NULL ) { taskUnlock(); /* FIXME - if too many devs, mem leak */ errno = ENODEV; return NULL; } bzero( (caddr_t) pDev->pDc, sizeof(struct dcache_ctrl)); /* backward connect the cbio device */ pDev->pDc->cbio_dev = pDev ; taskUnlock(); /* connect the underlying block driver */ pDev->pDc->dc_subDev = pSubDev ; if( description != NULL ) pDev->pDc->dc_desc = strdup(description) ; else pDev->pDc->dc_desc = "" ; dacacheDevInit( pDev ); /* Create the Updater task if not already created */ if( dcacheUpdTaskId == 0 ) { dcacheUpdTaskId = taskSpawn( "tDcacheUpd", dcacheUpdTaskPriority, dcacheUpdTaskOptions, dcacheUpdTaskStack, (FUNCPTR) dcacheUpd, 0,0,0,0,0,0,0,0,0,0) ; } /* return device handle */ return( pDev ); }/******************************************************************************** * dcacheErrorHandler - handle I/O errors and device changes** INTERNAL** Error handling here are performed with the assumption that* any possible recovery was already performed by the driver, i.e. retries,* corrections, maybe even reassignments.* This means there is not much we can do at this level.* Still, most errors are probably due to device change, which* is not limited to strictly removable devices, as hard drives* that appear Fixed are in fact hot swappable in some environments.** Other issues such as mapping a sectors as BAD in the FAT, or Bad* Block Reassignment (SCSI) will be left to the Utilities to handle,* e.g. Surface Scan is the way to do such mappings.** RETURNS: the return value will mean if the disk cache should* continue operation, or abort the current operation and return* an ERROR to the file system.**/LOCAL STATUS dcacheErrorHandler ( CBIO_DEV_ID dev, DCACHE_DESC * pDesc, enum cbio_rw rw ) { STATUS stat = ERROR ; /* OK means cache may continue, ERROR - abort */ static char errorMsgTemplate[] = "disk cache error: device %x block %d errno %x, %s\n" ; /* record this errno */ dev->params.cbio_lastErrno = errno ; /* record the block # where error occurred */ if( pDesc != NULL ) dev->params.cbio_lastErrBlk = pDesc->block ; else dev->params.cbio_lastErrBlk = NONE ; DEBUG_MSG( "disk cache error: errno=%x, block=%x, removable=%s, " "readyChanged=%s\n", dev->params.cbio_lastErrno, dev->params.cbio_lastErrBlk, (int) (dev->pDc->dc_subDev->params.cbio_removable)?"Yes":"No", (int) (dev->pDc->dc_subDev->cbio_readyChanged)?"Yes":"No", 0, 0 ); /* now shall we see if the error was due to device removal */ /* first, let us assume the driver has set the flag */ if( TRUE == dev->pDc->dc_subDev->cbio_readyChanged ) { stat = ERROR ; dev->cbio_readyChanged = TRUE ; } /* next, we will double-check if the device is ready */ else { stat = dev->pDc->dc_subDev->pFuncs->cbio_ioctl( dev->pDc->dc_subDev, CBIO_STATUS_CHK, 0); if( stat == ERROR ) dev->cbio_readyChanged = TRUE ; } /* so if the reason was device removal, stop right here */ if( TRUE == dev->cbio_readyChanged ) { /* override errno for removed disk */ errno = S_ioLib_DISK_NOT_PRESENT ; /* dont issue warning for read errors on removal, only for writes */ if( rw == CBIO_WRITE ) { /* write error, issue warning to the console */ INFO_MSG(errorMsgTemplate, (int) dev, dev->params.cbio_lastErrBlk, dev->params.cbio_lastErrno, (int) "disk removed while writing data, probable data loss", 0,0 ); } return(ERROR); } /* at this point, it is a certain block which is causing this error */ /* override errno if not set by driver */ if( errno == 0 ) errno = S_ioLib_DEVICE_ERROR ; if( rw == CBIO_READ ) { INFO_MSG(errorMsgTemplate, (int) dev, dev->params.cbio_lastErrBlk, dev->params.cbio_lastErrno, (int) "disk read failed", 0,0 ); return(ERROR); } else { /* * this policy will be questioned for some time to come */ INFO_MSG(errorMsgTemplate, (int) dev, dev->params.cbio_lastErrBlk, dev->params.cbio_lastErrno, (int) "disk write failed, data loss may have occurred", 0,0 ); return(ERROR); } /*NOTREACH*/ }/******************************************************************************** * dcacheBlockCksum - calculate a checksum signature for a cache block** calculate a 32-bit signature for a block, using a permuted-shift checksum*/LOCAL u_long dcacheBlockCksum( CBIO_DEV_ID dev, DCACHE_DESC *pDesc ) { FAST u_long cksum = 0 ; FAST int i ; FAST u_short *p ; p = (ushort *) pDesc->data ; i = dev->params.cbio_bytesPerBlk >> 1 ; for( ; i > 0 ; i -- ) cksum += *p++ << (i & 0x3) ; return( cksum ); }/******************************************************************************** * dcacheHashRemove - remove a block desc from hash table**/LOCAL void dcacheHashRemove ( CBIO_DEV_ID dev, DCACHE_DESC *pDesc ) { FAST DCACHE_DESC *pTmp = NULL ; FAST DCACHE_DESC **pHashSlot ; FAST struct dcache_ctrl * pDc = dev->pDc ; if( pDesc->state != CB_STATE_EMPTY && pDc->dc_hashSize != 0 ) { /* empty blocks are not expected to be in hash, or no hash table */ pHashSlot = &(pDc->dc_hashBase [ pDesc->block % pDc->dc_hashSize ]); pTmp = *pHashSlot ; if( pTmp == pDesc ) { *pHashSlot = pTmp->hashNext ; } else { while( pTmp != NULL ) { if( pTmp->hashNext == pDesc ) { pTmp->hashNext = pDesc->hashNext; break; } pTmp = pTmp->hashNext ; } } } /* assert that we did not fail to find in hash unless has is void */ assert( (pTmp != NULL) == (pDc->dc_hashSize > 0) ); pDesc->busy = 0; pDesc->block = NONE ; pDesc->state = CB_STATE_EMPTY ; pDesc->hashNext = NULL ; }/******************************************************************************** * dcacheChangeDetect - detect a possible disk change** This will return ERROR and set cbio_readyChanged to TRUE* if a change in the boot block's checksum is detected.*/LOCAL STATUS dcacheChangeDetect ( CBIO_DEV_ID dev, BOOL invalidate ) { DCACHE_DESC *pDesc ; block_t bootBlockNum = DCACHE_BOOT_BLOCK_NUM ; FAST u_long cksum ; DEBUG_MSG("change detect, idle was %d ms\n", 1000 * (tickGet() - dev->pDc->dc_actTick)/sysClkRateGet(), 0,0,0,0,0); dev->pDc->dc_actTick = tickGet() ; pDesc = dcacheBlockGet(dev, bootBlockNum, NULL, /*readData=*/ TRUE); if( pDesc == NULL ) return ERROR ; if( pDesc->state != CB_STATE_CLEAN ) { return OK; } else if ((pDesc->state == CB_STATE_CLEAN) && invalidate ) { /* invalidate the boot block to read it from disk */ dcacheHashRemove(dev, pDesc); } cksum = dcacheBlockCksum( dev, pDesc ); if ( dev->pDc->dc_diskSignature != cksum ) { DEBUG_MSG("disk changed, signature old %x, new %x\n", dev->pDc->dc_diskSignature, cksum, 0,0,0,0 ); dev->cbio_readyChanged = TRUE ; dev->pDc->dc_diskSignature = cksum ; errno = S_ioLib_DISK_NOT_PRESENT ; return ERROR ; } return OK ; }/******************************************************************************** * dcacheListAddSort - add descriptor to a sorted list**/LOCAL void dcacheListAddSort( DL_LIST * pList, DCACHE_DESC * pDesc ) { FAST DCACHE_DESC * pTmp = NULL ; if( DLL_EMPTY( pList )) { dllAdd( pList, &pDesc->lruList ); return; } /* start at the tail */ for( pTmp = (DCACHE_DESC *) DLL_LAST(pList) ; pTmp != NULL ; pTmp = (DCACHE_DESC *) DLL_PREVIOUS( pTmp ) ) { if( pTmp->block < pDesc->block ) { /* insert before pTmp */ dllInsert( pList, &pTmp->lruList, &pDesc->lruList ); return; } } /* else it should be first */ dllInsert( pList, NULL, &pDesc->lruList ); return; }/******************************************************************************** * dcacheFlushBatch - flush a batch of sorted blocks to disk **/LOCAL STATUS dcacheFlushBatch ( CBIO_DEV_ID dev, DL_LIST * pList, BOOL doInvalidate ) { FAST DCACHE_DESC * pTmp, * pContig ; FAST struct dcache_ctrl * pDc = dev->pDc ; STATUS ret, retstat = OK ; u_long burstCount, ix ; caddr_t pData ; if ( dev->params.cbio_removable && (pDc->dc_actTick < tickGet() - sysClkRateGet() * DCACHE_IDLE_SECS )) { if( dcacheChangeDetect( dev, FALSE ) == ERROR ) return ERROR; } for( pTmp = (DCACHE_DESC *) DLL_FIRST(pList) ; pTmp != NULL ; pTmp = (DCACHE_DESC *) DLL_FIRST(pList) ) { pContig = pTmp ; for(burstCount = 1 ; burstCount <= pDc->dc_BigBufSize; burstCount++) { pContig = (DCACHE_DESC *) DLL_NEXT( pContig ); if( pContig == NULL ) break ; if( pContig->block != (pTmp->block + burstCount) ) break ; } /*for burstCount */ if( burstCount == 1 ) { /* non-contiguous block, write directly from cache block */ ret = pDc->dc_subDev->pFuncs->cbio_blkRW( pDc->dc_subDev, pTmp->block, 1, pTmp->data, CBIO_WRITE, NULL ); pDc->dc_lastAccBlock = pTmp->block + 1 ; } else { /* contiguous burst write */ /* in case we overcounted */ burstCount = min(burstCount, pDc->dc_BigBufSize);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -