📄 diskmap.c
字号:
*/LOCAL ER unmapDiskSpace( ME *me, SyncOpt opt ){ VP laddr = PageAlignL(me->mode.addr); UW lsid = me->mode.space; W npage = (W)me->npage; ER err, error = E_OK; /* Reset mapping to memory (lock state is also reset temporarily). */ err = __UnmakeSpace(laddr, npage, lsid); if ( err < E_OK ) { error = err; goto err_ret; } me->mapped = FALSE; /* Synchronize page frames and release unnecessary MapEntry */ err = syncMapEntry(me, opt); if ( err < E_OK ) { error = err; } if ( me->alloc != 0 ) { /* Release address space for mapping */ UnlockSEG(); err = FreeMemorySpace(laddr, lsid); LockSEG(); if ( err < E_OK ) { error = err; } me->alloc = FALSE; } if ( !me->memmap ) { if ( LimitMapRank(me->mode.rank) ) { MapCount--; } }err_ret:#ifdef DEBUG if ( error < E_OK ) { DEBUG_PRINT(("unmapDiskSpace err = %d\n", error)); }#endif return error;}/* ------------------------------------------------------------------------ *//* * Disk synchronization * opt = FORCEDEL Cancel page frames and then, if there are still MapEntry to which pages * frames are mapped, release them forcefully. * opt = DISCARD Cancel page frames and then, if there are still MapEntry * to which pages frames are mapped, abort processing and * return E_BUSY. * opt = SYNCONLY Page frames remain valid and are used again * when mapped next time. * opt = NOSYNC,WRITEALL Not available * * When "de = NULL", map to the whole disk. * * (*) When "opt != SYNCONLY", UnlockSEG may occur temporarily. * Therefore, call page frames in LockFS & LockSEG state. * When "opt == SYNCONLY", only LockSEG is necessary. */EXPORT ER SyncDisk( DE *de, VW info, SyncOpt opt ){ ID did; ME *me; W i; ER err, error = E_OK; did = ( de != NULL )? toDiskID(de): 0; /* Perform synchronous processing in order of MapEntry. */ for ( i = 0; i < (W)MaxMapEntry; ++i ) { /* Skip unused entries. */ if ( MapEntryTable[i].next != (VP)TSD_MET_VAL_M1 ) { continue; } me = MapEntryTable[i].me; /* Check if they are to be synchronized. */ if (( did != 0 )&&( me->did != did )) { continue; } if ( info != 0 ) { if ( !(( me->mode.info == info ) ||( me->mode.info == 0 )) ) { continue; } } if (( opt != SYNCONLY )&& me->mapped ) { if ( opt == DISCARD ) { error = E_BUSY; goto err_ret; } /* Forced reset of maps and synchronous processing */ err = unmapDiskSpace(me, opt); if ( err < E_OK ) { error = err; } } else { /* Synchronous processing */ err = syncMapEntry(me, opt); if ( err < E_OK ) { error = err; } } } if ( opt != SYNCONLY ) { /* Cancel the remaining page frames. */ DiscardPageFrameDE(de); }err_ret:#ifdef DEBUG if ( error < E_OK ) { DEBUG_PRINT(("SyncDisk err = %d\n", error)); }#endif return error;}/* * Page in disk maps. */EXPORT ER PageInMapDisk( ID mid, VP laddr ){ ME *me; ER err; me = checkMapID(mid); if ( me == NULL ) { err = E_ID; goto err_ret; } if ( !me->memmap ) { err = pageinMapEntry(me, laddr); if ( err < E_OK ) { goto err_ret; } } return E_OK;err_ret: DEBUG_PRINT(("PageInMapDisk err = %d\n", err)); return err;}/* * Page out disk maps. * Write pfe page frames to the disk, and separate all me * where pfe are mapped. * Do not change page frame queues to which pfe are connected. * pfe must not be PFS_lock. * * When "nowrite = TRUE", return E_BUSY instead of * writing page frames to the disk (page-out). */EXPORT ER PageOutMapDisk( PFE *pfe, BOOL nowrite ){ ME *me; MEL *mel; PTE pte; VP laddr; ME *maxme = NULL; UW maxpage = 0; ER err; /* Set all mapped pages to absent. */ for ( mel = pfe->md.mel; mel != NULL; mel = mel->next_me ) { me = mel->me; if ( me->npage > maxpage ) { maxme = me; maxpage = me->npage; } laddr = mappingAddress(me, pfe); if ( laddr == INVADR ) { continue; /* Already unmapped */ } pte.w = GET_PTE(laddr, me->mode.space); /* Not treated as disk map after copy-on-write processing. */ if ( CopyOnWriteP_done(pte.w) ) { continue; } if ( !isValidP(pte.w) ) { continue; /* Pages are already absent. */ } if ( isLocalSpace(laddr) != 0 ) { /* Update process statistical information */ PINFO *pinfo = GetPINFO_lsid(me->mode.space); if ( pinfo != NULL ) { pinfo->allocpage--; pinfo->poutcount++; } } /* Set pages to absent. */ pte.w = 0; pte.c.pfa = toMapID(me); pte.w = CHG_PTE(laddr, me->mode.space, pte.w, ~(UW)(PT_Address|PT_Present|PT_Valid|PT_Update|PT_Accessed), TRUE); /* If a write-protect page has been updated, * return an error without writing it to the disk. * Write-protect pages are sometimes updated by BMS. * In such a case, do not write them to the disk. * Return an error so that such pages do not remain * on the disk cache. */ if ( isUpdateP(pte.w) ) { if ( isWritableP(pte.w) ) { pfe->upd = TRUE; } else { pfe->err = TRUE; } } } /* Not necessary to write pages to the disk unless they have been updated. */ if ( pfe->upd != 0 ) { if ( nowrite != 0 ) { err = E_BUSY; goto err_ret; } if ( maxme != NULL ) { /* Write a map with the largest number of pages as a representative. */ (void)writeMapEntry(maxme, SYNCONLY); /* Ignore errors. */ } } /* Separate pfe from map. */ while ( (mel = pfe->md.mel) != NULL ) { deleteMapLink(mel); } return E_OK;err_ret:#ifdef DEBUG if ( !(nowrite &&( err == E_BUSY)) ) { DEBUG_PRINT(("PageOutMapDisk nowrite = %d err = %d\n", nowrite, err)); }#endif return err;}/* ------------------------------------------------------------------------ *//* * Disk map * Map a group of physical blocks (block[]) on a disk specified with diskid to * consecutive address spaces. * If logical address spaces are not free, return error. If there is no free space * in real memory (mode.real=1), wait until there is free space. * Return mapid (> 0) as a function value. * * (*) Note that page fault may occur when access is made * to block[] or *mode. * (*) Note that during LockSEG(), it is not allowed to call Icalloc, Ifree, * AllocMemorySpace, or FreeMemorySpace. */EXPORT ER _MapDisk( ID diskid, PhyBlk block[], MapMode *mode ){ DE *de; ME *me, *old_me = NULL; ID mid = 0; VP laddr; W n, npage, ofs; UW lsid; ER err; lsid = mode->space; if ( lsid >= MaxLSID ) { err = E_PAR; goto err_ret1; } LockFS(); if ( LimitMapRank(mode->rank) ) { if ( MapCount >= MapLimit ) { err = E_LIMIT; goto err_ret2; } } de = checkDiskID(diskid); if ( de == NULL ) { err = E_ID; goto err_ret2; } /* Check block specification. */ n = checkBlockPara(de, block, &npage); if ( n < E_OK ) { err = n; goto err_ret2; } /* Reserve memory for MapEntry. */ me = Icalloc(1U, MapEntrySize((UW)n)); if ( me == NULL ) { err = E_NOMEM; goto err_ret2; } me->mode = *mode; me->sync = mode->real; me->tid = GetMyTid(); me->mapped = TRUE; me->did = diskid; me->npage = (UW)npage; memcpy(me->pb, block, (size_t)(sizeof(PhyBlk) * (UW)n));#if RESIDENT_ONLY /* If only resident blocks are specified, force them to be resident. */ me->mode.real = 1;#elif PT_Update == 0 /* When pages cannot be updated on the hardware, whether updated * or not is not known and therefore page-out cannot be performed * until unmapping (UnmapDisk). In such a case, force any writable * maps to be resident. */ if ( (me->mode.level & MapWrite) != 0 ) { me->mode.real = 1; }#endif /* Offset address in a page located at the start of block */ ofs = BLKOFS(de, (W)block[0].blk) * de->info.blocksize; if ( me->mode.addr == INVADR ) { /* Obtain address space for mapping */ laddr = AllocMemorySpace(npage, lsid); if ( laddr == NULL ) { err = E_NOMEM; goto err_ret3; }#if USERLEVEL_ADDRESS_MASK /* Processing to be performed when access right is determined based on address. */ if ( (me->mode.level & MapUser) != 0 ) { laddr = (VP)((UW)laddr & (UW)USERLEVEL_ADDRESS_MASK); }#endif me->mode.addr = (VB*)laddr + ofs; me->alloc = TRUE; } else { /* Check if user-specified addresses can be used for mapping. */ if ( PageOffset(me->mode.addr) != (UW)ofs ) { err = E_PAR; goto err_ret3; } laddr = (VB*)me->mode.addr - ofs;#if USERLEVEL_ADDRESS_MASK /* Processing to be performed when access right is determined based on address. */ /* Do not place restrictions on addresses in the case of MapSystem. */ if ( (me->mode.level & MapUser) != 0 ) { if (((UW)laddr & ~(UW)USERLEVEL_ADDRESS_MASK) != 0U ) { err = E_NOSPT; goto err_ret3; } }#endif } LockSEG(); /* Register MapEntry */ mid = registMapEntry(me, &old_me); if ( mid < E_OK ) { err = mid; goto err_ret4; } if ( de->memadr == INVADR ) { /* Normal disk map */ err = mapDiskSpace(de, me, laddr); if ( err < E_OK ) { goto err_ret5; } } else { /* Direct mapping to memory disk */ me->memmap = TRUE; err = mapDiskMemory(de, me, laddr); if ( err < E_OK ) { goto err_ret5; } } UnlockSEG(); UnlockFS(); if ( old_me != NULL ) { Ifree(old_me); } mode->addr = (VB*)laddr + ofs; return mid;err_ret5: (void)unmapDiskSpace(me, NOSYNC);err_ret4: UnlockSEG(); if ( me->alloc != 0 ) { (void)FreeMemorySpace(laddr, lsid); }err_ret3: if ( mid <= 0 ) { Ifree(me); } if ( old_me != NULL ) { Ifree(old_me); }err_ret2: UnlockFS();err_ret1: DEBUG_PRINT(("_MapDisk err = %d\n", err)); return ERtoERR(err);}/* * Disk unmap * Delete the address spaces mapped by mapid. * Use flag to indicate whether writing has been performed at the addresses mapped by mapid. * * (*) If writing is checked on a hardware basis, ignore the flag. * (*) Note that during LockSEG(), it is not allowed to call Ifree. */EXPORT ER _UnmapDisk( ID mapid, UW flag ){ ME *me; SyncOpt opt; ER err; LockFS(); LockSEG(); me = checkMapID(mapid); if ( me == NULL ) { err = E_ID; goto err_ret; }#if PT_Update == 0 /* If updates cannot be checked on hardware: use flag. */ if ( (flag & MD_WRITE) != 0 ) { opt = ( me->sync != 0 )? WRITEALL: MARKUPD; } else { opt = ( me->sync != 0 )? SYNCONLY: NOSYNC; }#else /* If updates can be checked on hardware: do not use flag. */ opt = ( me->sync != 0 )? SYNCONLY: NOSYNC;#endif /* Reset mapping */ err = unmapDiskSpace(me, opt); if ( err < E_OK ) { goto err_ret; } me = checkFreeMapID(mapid); UnlockSEG(); if ( me != NULL ) { Ifree(me); } UnlockFS(); return E_OK;err_ret: UnlockSEG(); UnlockFS(); DEBUG_PRINT(("_UnmapDisk err = %d\n", err)); return ERtoERR(err);}/* ------------------------------------------------------------------------ *//* * Disk map-related initialization * (immediately after T-Kernel startup) */EXPORT ER InitDiskMap( void ){ W val[TSD_IDM_ARR_5]; MET *met; ER err; /* Obtain definition information from SYSCONF. */ err = GetSysConf_bms((UB*)"MaxMapID", val, 1); if ( err < E_OK ) { goto err_ret; } MaxMapEntry = (UW)val[0]; MapLimit = (MaxMapEntry * TSD_IDM_VAL_7) / TSD_IDM_DIV_10; /* 70% */ MapCount = 0U; /* Generate/initialize map management information table */ MapEntryTable = Imalloc(MaxMapEntry * sizeof(MET)); if ( MapEntryTable == NULL ) { err = E_NOMEM; goto err_ret; } FreeMapEntryTop = &MapEntryTable[MaxMapEntry - 1U]; FreeMapEntryEnd = &MapEntryTable[0]; for ( met = FreeMapEntryTop; met > FreeMapEntryEnd; --met ) { met->next = met - 1; met->me = NULL; } FreeMapEntryEnd->next = NULL; FreeMapEntryEnd->me = NULL; /* Initialize memory pool for map entry connection information */ InitFMB(&MapEntryLinkPool, sizeof(MEL)); return E_OK;err_ret: BMS_DEBUG_PRINT(("InitDiskMap err = %d\n", err)); return err;}/* ======================================================================== *//* * Debug support function */#if DEBUGFUNC_SUPPORT#define M(v, c) ( ( (v) != 0 )? (c): '-' )/* * Indicate map ID information */EXPORT void DumpMap( void ){ ME *me; W i; PhyBlk *pb; printf("FILE MAP:\n"); DumpMore(0); for ( i = 0; i < MaxMapEntry; ++i ) { if ( MapEntryTable[i].next != (VP)TSD_MET_VAL_M1 ) { continue; /* Not used */ } me = MapEntryTable[i].me; printf( " [%3d] addr:%08x npage:%-3d did:%-3d tid:%-3d info:%08x\n" " %c%c rank:%d real:%d clear:%d level:%02x space:%-5d\n" " blk:", me->mapid, /* Map ID */ me->mode.addr, /* Specify map address */ me->npage, /* Total number of pages in map */ me->did, /* Disk ID */ me->tid, /* Mapped task */ me->mode.info, /* Map information */ M(me->mapped, 'M'), /* In the process of mapping */ M(me->memmap, 'R'), /* Memory disk */ me->mode.rank, /* Specify rank */ me->mode.real, /* Specify real/virtual IO */ me->mode.clear, /* Specify clear */ me->mode.level, /* Specify access level */ me->mode.space /* Specify map space */ ); pb = me->pb; /* Disk blocks to be used */ while ( pb->len > 0 ) { printf(" %d#%d", pb->blk, pb->len); pb++; } printf("\n"); if ( DumpMore(TSD_DPM_VAL_3) ) { break; } }}#endif /* DEBUGFUNC_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -