Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

lbcbsup.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1990 Microsoft Corporation 00004 00005 Module Name: 00006 00007 LbcbSup.c 00008 00009 Abstract: 00010 00011 This module provides support for manipulating log buffer control blocks. 00012 00013 Author: 00014 00015 Brian Andrew [BrianAn] 20-June-1991 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "lfsprocs.h" 00022 00023 // 00024 // The debug trace level 00025 // 00026 00027 #define Dbg (DEBUG_TRACE_LBCB_SUP) 00028 00029 #ifdef ALLOC_PRAGMA 00030 #pragma alloc_text(PAGE, LfsFlushLbcb) 00031 #pragma alloc_text(PAGE, LfsFlushToLsnPriv) 00032 #pragma alloc_text(PAGE, LfsGetLbcb) 00033 #endif 00034 00035 00036 VOID 00037 LfsFlushLbcb ( 00038 IN PLFCB Lfcb, 00039 IN PLBCB Lbcb 00040 ) 00041 00042 /*++ 00043 00044 Routine Description: 00045 00046 This routine is called to make sure the data within an Lbcb makes it out 00047 to disk. The Lbcb must either already be in the workque or it must be 00048 a restart Lbcb. 00049 00050 Arguments: 00051 00052 Lfcb - This is the file control block for the log file. 00053 00054 Lbcb - This is the Lbcb to flush. 00055 00056 Return Value: 00057 00058 None. 00059 00060 --*/ 00061 00062 { 00063 LSN LastLsn; 00064 PLSN FlushedLsn; 00065 00066 PAGED_CODE(); 00067 00068 DebugTrace( +1, Dbg, "LfsFlushLbcb: Entered\n", 0 ); 00069 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00070 DebugTrace( 0, Dbg, "Lbcb -> %08lx\n", Lbcb ); 00071 00072 LastLsn = Lbcb->LastEndLsn; 00073 00074 // 00075 // If this is a restart area we use the restart counter in the 00076 // Lfcb. Otherwise we can use the LastFlushedLsn value in the 00077 // Lfcb. This way we can determine that the Lbcb that interests 00078 // us has made it out to disk. 00079 // 00080 00081 if (LfsLbcbIsRestart( Lbcb )) { 00082 00083 FlushedLsn = &Lfcb->LastFlushedRestartLsn; 00084 00085 } else { 00086 00087 FlushedLsn = &Lfcb->LastFlushedLsn; 00088 } 00089 00090 // 00091 // We loop here until the desired Lsn has made it to disk. 00092 // If we are able to do the I/O, we will perform it. 00093 // 00094 00095 do { 00096 00097 // 00098 // 00099 // If we can do the Io, call down to flush the Lfcb. 00100 // 00101 00102 if (Lfcb->LfsIoState == LfsNoIoInProgress) { 00103 00104 LfsFlushLfcb( Lfcb, Lbcb ); 00105 00106 break; 00107 } 00108 00109 // 00110 // Otherwise we release the Lfcb and immediately wait on the event. 00111 // 00112 00113 Lfcb->Waiters += 1; 00114 00115 LfsReleaseLfcb( Lfcb ); 00116 00117 KeWaitForSingleObject( &Lfcb->Sync->Event, 00118 Executive, 00119 KernelMode, 00120 FALSE, 00121 NULL ); 00122 00123 LfsAcquireLfcb( Lfcb ); 00124 Lfcb->Waiters -= 1; 00125 00126 } while ( LastLsn.QuadPart > FlushedLsn->QuadPart ); 00127 00128 DebugTrace( -1, Dbg, "LfsFlushLbcb: Exit\n", 0 ); 00129 return; 00130 } 00131 00132 00133 VOID 00134 LfsFlushToLsnPriv ( 00135 IN PLFCB Lfcb, 00136 IN LSN Lsn 00137 ) 00138 00139 /*++ 00140 00141 Routine Description: 00142 00143 This routine is the worker routine which performs the work of flushing 00144 a particular Lsn to disk. This routine is always called with the 00145 Lfcb acquired. This routines makes no guarantee about whether the Lfcb 00146 is acquired on exit. 00147 00148 Arguments: 00149 00150 Lfcb - This is the file control block for the log file. 00151 00152 Lsn - This is the Lsn to flush to disk. 00153 00154 Return Value: 00155 00156 None. 00157 00158 --*/ 00159 00160 { 00161 BOOLEAN UseLastRecordLbcb = FALSE; 00162 PLBCB LastRecordLbcb = NULL; 00163 00164 PAGED_CODE(); 00165 00166 DebugTrace( +1, Dbg, "LfsFlushToLsnPriv: Entered\n", 0 ); 00167 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00168 DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart ); 00169 DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn.HighPart ); 00170 00171 // 00172 // We check if the Lsn is in the valid range. Raising an 00173 // exception if not. 00174 // 00175 00176 if (Lsn.QuadPart > Lfcb->RestartArea->CurrentLsn.QuadPart) { 00177 00178 UseLastRecordLbcb = TRUE; 00179 } 00180 00181 // 00182 // If the Lsn has already been flushed we are done. 00183 // Otherwise we need to look through the workqueues and the 00184 // active queue. 00185 // 00186 00187 if (Lsn.QuadPart > Lfcb->LastFlushedLsn.QuadPart) { 00188 00189 PLIST_ENTRY ThisEntry; 00190 PLBCB ThisLbcb; 00191 00192 // 00193 // Check the workqueue first. We are looking for the last 00194 // buffer block of a log page block which contains this 00195 // Lsn. 00196 // 00197 00198 ThisEntry = Lfcb->LbcbWorkque.Flink; 00199 00200 // 00201 // We keep looping. 00202 // 00203 00204 while (TRUE) { 00205 00206 ThisLbcb = CONTAINING_RECORD( ThisEntry, 00207 LBCB, 00208 WorkqueLinks ); 00209 00210 // 00211 // We pass over any restart areas. We also skip any 00212 // Lbcb's which do not contain the end of a log record. 00213 // 00214 00215 if (!LfsLbcbIsRestart( ThisLbcb ) 00216 && FlagOn( ThisLbcb->Flags, LOG_PAGE_LOG_RECORD_END )) { 00217 00218 LastRecordLbcb = ThisLbcb; 00219 00220 // 00221 // If the last complete Lsn in this Lbcb is greater or equal 00222 // to the desired Lsn, we exit the loop. 00223 // 00224 00225 if (ThisLbcb->LastEndLsn.QuadPart >= Lsn.QuadPart) { 00226 00227 break; 00228 } 00229 } 00230 00231 // 00232 // Otherwise move to the next Lbcb. 00233 // 00234 00235 ThisEntry = ThisEntry->Flink; 00236 00237 // 00238 // If we have reached the end of the list then break out. We 00239 // were given an Lsn which is larger than any flushed Lsn so 00240 // we will just flush to the end of the log file. 00241 // 00242 00243 if (ThisEntry == &Lfcb->LbcbWorkque) { 00244 00245 if (UseLastRecordLbcb) { 00246 00247 ThisLbcb = LastRecordLbcb; 00248 } 00249 00250 break; 00251 } 00252 } 00253 00254 if (ThisLbcb != NULL) { 00255 00256 // 00257 // If we are not supporting a packed log file and this Lbcb is from 00258 // the active queue, we need to check that losing the tail of the 00259 // will not swallow up any of our reserved space. 00260 // 00261 00262 if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) 00263 && FlagOn( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE )) { 00264 00265 LONGLONG CurrentAvail; 00266 LONGLONG UnusedBytes; 00267 00268 // 00269 // Find the unused bytes. 00270 // 00271 00272 UnusedBytes = 0; 00273 00274 LfsCurrentAvailSpace( Lfcb, 00275 &CurrentAvail, 00276 (PULONG)&UnusedBytes ); 00277 00278 CurrentAvail = CurrentAvail - Lfcb->TotalUndoCommitment; 00279 00280 if (UnusedBytes > CurrentAvail) { 00281 00282 DebugTrace( -1, Dbg, "Have to preserve these bytes for possible aborts\n", 0 ); 00283 00284 ExRaiseStatus( STATUS_LOG_FILE_FULL ); 00285 } 00286 00287 // 00288 // We want to make sure we don't write any more data into this 00289 // page. Remove this from the active queue. 00290 // 00291 00292 RemoveEntryList( &ThisLbcb->ActiveLinks ); 00293 ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); 00294 } 00295 00296 // 00297 // We now have the Lbcb we want to flush to disk. 00298 // 00299 00300 LfsFlushLbcb( Lfcb, ThisLbcb ); 00301 } 00302 } 00303 00304 DebugTrace( -1, Dbg, "LfsFlushToLsnPriv: Exit\n", 0 ); 00305 00306 return; 00307 } 00308 00309 00310 PLBCB 00311 LfsGetLbcb ( 00312 IN PLFCB Lfcb 00313 ) 00314 00315 /*++ 00316 00317 Routine Description: 00318 00319 This routine is called to add a Lbcb to the active queue. 00320 00321 Arguments: 00322 00323 Lfcb - This is the file control block for the log file. 00324 00325 Return Value: 00326 00327 PLBCB - Pointer to the Lbcb allocated. 00328 00329 --*/ 00330 00331 { 00332 PLBCB Lbcb = NULL; 00333 PVOID PageHeader; 00334 PBCB PageHeaderBcb = NULL; 00335 00336 BOOLEAN WrappedOrUsaError; 00337 00338 PAGED_CODE(); 00339 00340 DebugTrace( +1, Dbg, "LfsGetLbcb: Entered\n", 0 ); 00341 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00342 00343 // 00344 // Use a try-finally to facilitate cleanup. 00345 // 00346 00347 try { 00348 00349 // 00350 // Pin the desired record page. 00351 // 00352 00353 LfsPreparePinWriteData( Lfcb, 00354 Lfcb->NextLogPage, 00355 (ULONG)Lfcb->LogPageSize, 00356 &PageHeader, 00357 &PageHeaderBcb ); 00358 00359 // 00360 // Put our signature into the page so we won't fail if we 00361 // see a previous 'BAAD' signature. 00362 // 00363 00364 *((PULONG) PageHeader) = LFS_SIGNATURE_RECORD_PAGE_ULONG; 00365 00366 // 00367 // Now allocate an Lbcb. 00368 // 00369 00370 LfsAllocateLbcb( Lfcb, &Lbcb ); 00371 00372 // 00373 // If we are at the beginning of the file we test that the 00374 // sequence number won't wrap to 0. 00375 // 00376 00377 if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL ) 00378 && ( Lfcb->NextLogPage == Lfcb->FirstLogPage )) { 00379 00380 Lfcb->SeqNumber = Lfcb->SeqNumber + 1; 00381 00382 // 00383 // If the sequence number is going from 0 to 1, then 00384 // this is the first time the log file has wrapped. We want 00385 // to remember this because it means that we can now do 00386 // large spiral writes. 00387 // 00388 00389 if (Int64ShllMod32( Lfcb->SeqNumber, Lfcb->FileDataBits ) == 0) { 00390 00391 DebugTrace( 0, Dbg, "Log sequence number about to wrap: Lfcb -> %08lx\n", Lfcb ); 00392 KeBugCheck( FILE_SYSTEM ); 00393 } 00394 00395 // 00396 // If this number is greater or equal to the wrap sequence number in 00397 // the Lfcb, set the wrap flag in the Lbcb. 00398 // 00399 00400 if (!FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED ) 00401 && ( Lfcb->SeqNumber >= Lfcb->SeqNumberForWrap )) { 00402 00403 SetFlag( Lbcb->LbcbFlags, LBCB_LOG_WRAPPED ); 00404 SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED ); 00405 } 00406 } 00407 00408 // 00409 // Now initialize the rest of the Lbcb fields. 00410 // 00411 00412 Lbcb->FileOffset = Lfcb->NextLogPage; 00413 Lbcb->SeqNumber = Lfcb->SeqNumber; 00414 Lbcb->BufferOffset = Lfcb->LogPageDataOffset; 00415 00416 // 00417 // Store the next page in the Lfcb. 00418 // 00419 00420 LfsNextLogPageOffset( Lfcb, 00421 Lfcb->NextLogPage, 00422 &Lfcb->NextLogPage, 00423 &WrappedOrUsaError ); 00424 00425 Lbcb->Length = Lfcb->LogPageSize; 00426 Lbcb->PageHeader = PageHeader; 00427 Lbcb->LogPageBcb = PageHeaderBcb; 00428 00429 Lbcb->ResourceThread = ExGetCurrentResourceThread(); 00430 Lbcb->ResourceThread = (ERESOURCE_THREAD) ((ULONG) Lbcb->ResourceThread | 3); 00431 00432 // 00433 // If we are reusing a previous page then set a flag in 00434 // the Lbcb to indicate that we should flush a copy 00435 // first. 00436 // 00437 00438 if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) { 00439 00440 SetFlag( Lbcb->LbcbFlags, LBCB_FLUSH_COPY ); 00441 ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL ); 00442 00443 (ULONG)Lbcb->BufferOffset = Lfcb->ReusePageOffset; 00444 00445 Lbcb->Flags = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Flags; 00446 Lbcb->LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn; 00447 Lbcb->LastEndLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Header.Packed.LastEndLsn; 00448 } 00449 00450 // 00451 // Put the Lbcb on the active queue 00452 // 00453 00454 InsertTailList( &Lfcb->LbcbActive, &Lbcb->ActiveLinks ); 00455 00456 SetFlag( Lbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); 00457 00458 // 00459 // Now that we have succeeded, set the owner thread to Thread + 1 so the resource 00460 // package will know not to peek in this thread. It may be deallocated before 00461 // we release the Bcb during flush. 00462 // 00463 00464 CcSetBcbOwnerPointer( Lbcb->LogPageBcb, (PVOID) Lbcb->ResourceThread ); 00465 00466 } finally { 00467 00468 DebugUnwind( LfsGetLbcb ); 00469 00470 // 00471 // If an error occurred, we need to clean up any blocks which 00472 // have not been added to the active queue. 00473 // 00474 00475 if (AbnormalTermination()) { 00476 00477 if (Lbcb != NULL) { 00478 00479 LfsDeallocateLbcb( Lfcb, Lbcb ); 00480 Lbcb = NULL; 00481 } 00482 00483 // 00484 // Unpin the system page if pinned. 00485 // 00486 00487 if (PageHeaderBcb != NULL) { 00488 00489 CcUnpinData( PageHeaderBcb ); 00490 } 00491 } 00492 00493 DebugTrace( -1, Dbg, "LfsGetLbcb: Exit\n", 0 ); 00494 } 00495 00496 return Lbcb; 00497 }

Generated on Sat May 15 19:40:36 2004 for test by doxygen 1.3.7