Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

833 lines
22 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Write.c
  5. Abstract:
  6. This module implements the user routines which write log records into
  7. or flush portions of the log file.
  8. Author:
  9. Brian Andrew [BrianAn] 20-June-1991
  10. Revision History:
  11. --*/
  12. #include "lfsprocs.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_WRITE)
  17. #define LFS_PAGES_TO_VERIFY 10
  18. VOID
  19. LfsGetActiveLsnRangeInternal (
  20. IN PLFCB Lfcb,
  21. OUT PLSN OldestLsn,
  22. OUT PLSN NextLsn
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE, LfsCheckWriteRange)
  26. #pragma alloc_text(PAGE, LfsFlushToLsn)
  27. #pragma alloc_text(PAGE, LfsForceWrite)
  28. #pragma alloc_text(PAGE, LfsGetActiveLsnRange)
  29. #pragma alloc_text(PAGE, LfsGetActiveLsnRangeInternal)
  30. #pragma alloc_text(PAGE, LfsWrite)
  31. #endif
  32. VOID
  33. LfsGetActiveLsnRangeInternal (
  34. IN PLFCB Lfcb,
  35. OUT PLSN OldestLsn,
  36. OUT PLSN NextLsn
  37. )
  38. /*++
  39. Routine Description:
  40. Returns back the range that is active in the logfile from the oldest valid LSN to
  41. where the next active LSN will be.
  42. Arguments:
  43. Lfcb - the logfile lfcb
  44. OldestLsn - returns the oldest active lsn
  45. NextLsn - returns the projected next lsn to be used
  46. Return Value:
  47. None
  48. --*/
  49. {
  50. PLBCB ActiveLbcb;
  51. PAGED_CODE();
  52. //
  53. // Calculate what the next LSN will be using the regular logic
  54. // 1) if there is no active lbcb then it will be the first offset on the next
  55. // page (the seq. number will increment if it wraps)
  56. // 2) Otherwise its the Lsn contained in the top of the active lbcb list
  57. //
  58. if (!IsListEmpty( &Lfcb->LbcbActive )) {
  59. ActiveLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
  60. LBCB,
  61. ActiveLinks );
  62. NextLsn->QuadPart = LfsComputeLsnFromLbcb( Lfcb, ActiveLbcb );
  63. } else {
  64. if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL)) {
  65. NextLsn->QuadPart = LfsFileOffsetToLsn( Lfcb, Lfcb->NextLogPage + Lfcb->ReusePageOffset, Lfcb->SeqNumber );
  66. } else if (Lfcb->NextLogPage != Lfcb->FirstLogPage) {
  67. NextLsn->QuadPart = LfsFileOffsetToLsn( Lfcb, Lfcb->NextLogPage + Lfcb->LogPageDataOffset, Lfcb->SeqNumber );
  68. } else {
  69. NextLsn->QuadPart = LfsFileOffsetToLsn( Lfcb, Lfcb->NextLogPage + Lfcb->LogPageDataOffset, Lfcb->SeqNumber + 1 );
  70. }
  71. }
  72. OldestLsn->QuadPart = Lfcb->OldestLsn.QuadPart;
  73. }
  74. VOID
  75. LfsGetActiveLsnRange (
  76. IN LFS_LOG_HANDLE LogHandle,
  77. OUT PLSN OldestLsn,
  78. OUT PLSN NextLsn
  79. )
  80. /*++
  81. Routine Description:
  82. Returns back the range that is active in the logfile from the oldest valid LSN to
  83. where the next active LSN will be. For external clients since it acquires the leb sync resource
  84. Arguments:
  85. Lfcb - the logfile handle
  86. OldestLsn - returns the oldest active lsn
  87. NextLsn - returns the projected next lsn to be used
  88. Return Value:
  89. None
  90. --*/
  91. {
  92. PLCH Lch;
  93. PLFCB Lfcb;
  94. PAGED_CODE();
  95. Lch = (PLCH) LogHandle;
  96. //
  97. // Check that the structure is a valid log handle structure.
  98. //
  99. LfsValidateLch( Lch );
  100. try {
  101. //
  102. // Acquire the log file control block for this log file.
  103. //
  104. LfsAcquireLch( Lch );
  105. Lfcb = Lch->Lfcb;
  106. LfsGetActiveLsnRangeInternal( Lfcb, OldestLsn, NextLsn );
  107. } finally {
  108. LfsReleaseLch( Lch );
  109. }
  110. }
  111. BOOLEAN
  112. LfsWrite (
  113. IN LFS_LOG_HANDLE LogHandle,
  114. IN ULONG NumberOfWriteEntries,
  115. IN PLFS_WRITE_ENTRY WriteEntries,
  116. IN LFS_RECORD_TYPE RecordType,
  117. IN TRANSACTION_ID *TransactionId OPTIONAL,
  118. IN LSN UndoNextLsn,
  119. IN LSN PreviousLsn,
  120. IN LONG UndoRequirement,
  121. IN ULONG Flags,
  122. OUT PLSN Lsn
  123. )
  124. /*++
  125. Routine Description:
  126. This routine is called by a client to write a log record to the log file.
  127. The log record is lazy written and is not guaranteed to be on the disk
  128. until a subsequent LfsForceWrie or LfsWriteRestartArea or until
  129. an LfsFlushtoLsn is issued withan Lsn greater-than or equal to the Lsn
  130. returned from this service.
  131. Arguments:
  132. LogHandle - Pointer to private Lfs structure used to identify this
  133. client.
  134. NumberOfWriteEntries - Number of components of the log record.
  135. WriteEntries - Pointer to an array of write entries.
  136. RecordType - Lfs defined type for this log record.
  137. TransactionId - Id value used to group log records by complete transaction.
  138. UndoNextLsn - Lsn of a previous log record which needs to be undone in
  139. the event of a client restart.
  140. PreviousLsn - Lsn of the immediately previous log record for this client.
  141. Lsn - Lsn to be associated with this log record.
  142. UndoRequirement -
  143. Flags - if LFS_WRITE_FLAG_WRITE_AT_FRONT put this record at the front of the log and all
  144. records will continue from then on after it.
  145. Return Value:
  146. BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is
  147. available.
  148. --*/
  149. {
  150. NTSTATUS Status;
  151. BOOLEAN LogFileFull = FALSE;
  152. PLCH Lch;
  153. PLFCB Lfcb;
  154. PAGED_CODE();
  155. DebugTrace( +1, Dbg, "LfsWrite: Entered\n", 0 );
  156. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  157. DebugTrace( 0, Dbg, "NumberOfWriteEntries -> %08lx\n", NumberOfWriteEntries );
  158. DebugTrace( 0, Dbg, "WriteEntries -> %08lx\n", WriteEntries );
  159. DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType );
  160. DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId );
  161. DebugTrace( 0, Dbg, "UndoNextLsn (Low) -> %08lx\n", UndoNextLsn.LowPart );
  162. DebugTrace( 0, Dbg, "UndoNextLsn (High) -> %08lx\n", UndoNextLsn.HighPart );
  163. DebugTrace( 0, Dbg, "PreviousLsn (Low) -> %08lx\n", PreviousLsn.LowPart );
  164. DebugTrace( 0, Dbg, "PreviousLsn (High) -> %08lx\n", PreviousLsn.HighPart );
  165. Lch = (PLCH) LogHandle;
  166. //
  167. // Check that the structure is a valid log handle structure.
  168. //
  169. LfsValidateLch( Lch );
  170. //
  171. // Use a try-finally to facilitate cleanup.
  172. //
  173. try {
  174. //
  175. // Acquire the log file control block for this log file.
  176. //
  177. LfsAcquireLch( Lch );
  178. Lfcb = Lch->Lfcb;
  179. //
  180. // If the Log file has been closed then refuse access.
  181. //
  182. if (Lfcb == NULL) {
  183. ExRaiseStatus( STATUS_ACCESS_DENIED );
  184. }
  185. //
  186. // Check that the client Id is valid.
  187. //
  188. LfsValidateClientId( Lfcb, Lch );
  189. //
  190. // If the clean shutdown flag is currently set then clear it
  191. // before allowing more log records out.
  192. //
  193. if (FlagOn( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN )) {
  194. ClearFlag( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN );
  195. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );
  196. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );
  197. }
  198. //
  199. // Check for write at front flag - we can't write at front if we're about to
  200. // reuse the last page or there is no last lsn - these conditions only occur
  201. // right at mount (and only if the mount fails)
  202. //
  203. if (FlagOn( Flags, LFS_WRITE_FLAG_WRITE_AT_FRONT ) &&
  204. !FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL )) {
  205. LSN NextLsn;
  206. LSN NextBeyondLsn;
  207. LSN NextActiveLsn;
  208. LSN OldestLsn;
  209. ULONG Index;
  210. PVOID TestPageHeader = NULL;
  211. PMDL TestPageMdl = NULL;
  212. //
  213. // Calculate the projected LSN for a write at the front and the page after it
  214. //
  215. NextLsn.QuadPart = LfsFileOffsetToLsn( Lfcb, Lfcb->FirstLogPage + Lfcb->LogPageDataOffset, Lfcb->SeqNumber );
  216. NextBeyondLsn.QuadPart = LfsFileOffsetToLsn( Lfcb, Lfcb->FirstLogPage + Lfcb->LogPageDataOffset + Lfcb->LogPageSize, Lfcb->SeqNumber );
  217. LfsGetActiveLsnRangeInternal( Lfcb, &OldestLsn, &NextActiveLsn );
  218. //
  219. // Test if calculated front LSN falls in active range
  220. //
  221. #ifdef BENL_DBG
  222. KdPrint(( "LFS: NextLsn: 0x%I64x Oldest: 0x%I64x Current: 0x%I64x Computed: 0x%I64x\n", NextLsn, Lfcb->OldestLsn, Lfcb->RestartArea->CurrentLsn, NextActiveLsn ));
  223. #endif
  224. if ((NextBeyondLsn.QuadPart < OldestLsn.QuadPart) ||
  225. (NextLsn.QuadPart > NextActiveLsn.QuadPart)) {
  226. //
  227. // Walk through the active queue and remove any Lbcb's with
  228. // data from that queue. This will lets us create new active lbcbs
  229. //
  230. while (!IsListEmpty( &Lfcb->LbcbActive )) {
  231. PLBCB ThisLbcb;
  232. ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
  233. LBCB,
  234. ActiveLinks );
  235. RemoveEntryList( &ThisLbcb->ActiveLinks );
  236. ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
  237. //
  238. // If this page has some new entries, allow it to
  239. // be flushed to disk elsewhere. Otherwise deallocate it
  240. // here. We set LBCB_NOT_EMPTY when we first put data into
  241. // the page and add it to the workqueue.
  242. //
  243. if (!FlagOn( ThisLbcb->LbcbFlags, LBCB_NOT_EMPTY )) {
  244. ASSERT( NULL == ThisLbcb->WorkqueLinks.Flink );
  245. if (ThisLbcb->LogPageBcb != NULL) {
  246. CcUnpinDataForThread( ThisLbcb->LogPageBcb,
  247. ThisLbcb->ResourceThread );
  248. }
  249. LfsDeallocateLbcb( Lfcb, ThisLbcb );
  250. }
  251. }
  252. ASSERT( !FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL ) );
  253. Lfcb->NextLogPage = Lfcb->FirstLogPage;
  254. //
  255. // Do an extra verification step - to check for simultaneous writers in the log
  256. // read the next 10 pages and confirm they have expected sequence numbers
  257. //
  258. try {
  259. for (Index=0; Index < LFS_PAGES_TO_VERIFY; Index++) {
  260. ULONG Signature;
  261. LARGE_INTEGER Offset;
  262. Offset.QuadPart = Lfcb->FirstLogPage + Index * Lfcb->LogPageSize;
  263. LfsReadPage( Lfcb, &Offset, &TestPageMdl, &TestPageHeader );
  264. Signature = *((PULONG)TestPageHeader);
  265. if (Signature != LFS_SIGNATURE_BAD_USA_ULONG) {
  266. if (LfsCheckSubsequentLogPage( Lfcb,
  267. TestPageHeader,
  268. Lfcb->FirstLogPage + Index * Lfcb->LogPageSize,
  269. Lfcb->SeqNumber + 1 )) {
  270. DebugTrace( 0, Dbg, "Log file is fatally flawed\n", 0 );
  271. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  272. }
  273. }
  274. //
  275. // Make sure the current page is unpinned.
  276. //
  277. if (TestPageMdl) {
  278. IoFreeMdl( TestPageMdl );
  279. TestPageMdl = NULL;
  280. }
  281. if (TestPageHeader) {
  282. LfsFreePool( TestPageHeader );
  283. TestPageHeader = NULL ;
  284. }
  285. }
  286. } finally {
  287. if (TestPageMdl) {
  288. IoFreeMdl( TestPageMdl );
  289. TestPageMdl = NULL;
  290. }
  291. if (TestPageHeader) {
  292. LfsFreePool( TestPageHeader );
  293. TestPageHeader = NULL ;
  294. }
  295. }
  296. }
  297. }
  298. #ifdef BENL_DBG
  299. {
  300. LSN OldestLsn;
  301. LSN NextActiveLsn;
  302. LfsGetActiveLsnRangeInternal( Lfcb, &OldestLsn, &NextActiveLsn );
  303. #endif
  304. //
  305. // Write the log record.
  306. //
  307. LogFileFull = LfsWriteLogRecordIntoLogPage( Lfcb,
  308. Lch,
  309. NumberOfWriteEntries,
  310. WriteEntries,
  311. RecordType,
  312. TransactionId,
  313. UndoNextLsn,
  314. PreviousLsn,
  315. UndoRequirement,
  316. FALSE,
  317. Lsn );
  318. #ifdef BENL_DBG
  319. ASSERT( Lsn->QuadPart = NextActiveLsn.QuadPart );
  320. }
  321. #endif
  322. } finally {
  323. DebugUnwind( LfsWrite );
  324. //
  325. // Release the log file control block if held.
  326. //
  327. LfsReleaseLch( Lch );
  328. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
  329. DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
  330. DebugTrace( -1, Dbg, "LfsWrite: Exit\n", 0 );
  331. }
  332. return LogFileFull;
  333. }
  334. BOOLEAN
  335. LfsForceWrite (
  336. IN LFS_LOG_HANDLE LogHandle,
  337. IN ULONG NumberOfWriteEntries,
  338. IN PLFS_WRITE_ENTRY WriteEntries,
  339. IN LFS_RECORD_TYPE RecordType,
  340. IN TRANSACTION_ID *TransactionId,
  341. IN LSN UndoNextLsn,
  342. IN LSN PreviousLsn,
  343. IN LONG UndoRequirement,
  344. OUT PLSN Lsn
  345. )
  346. /*++
  347. Routine Description:
  348. This routine is called by a client to write a log record to the log file.
  349. This is idendical to LfsWrite except that on return the log record is
  350. guaranteed to be on disk.
  351. Arguments:
  352. LogHandle - Pointer to private Lfs structure used to identify this
  353. client.
  354. NumberOfWriteEntries - Number of components of the log record.
  355. WriteEntries - Pointer to an array of write entries.
  356. RecordType - Lfs defined type for this log record.
  357. TransactionId - Id value used to group log records by complete transaction.
  358. UndoNextLsn - Lsn of a previous log record which needs to be undone in
  359. the event of a client restart.
  360. PreviousLsn - Lsn of the immediately previous log record for this client.
  361. Lsn - Lsn to be associated with this log record.
  362. Return Value:
  363. BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is
  364. available.
  365. --*/
  366. {
  367. PLCH Lch;
  368. PLFCB Lfcb;
  369. BOOLEAN LogFileFull = FALSE;
  370. PAGED_CODE();
  371. DebugTrace( +1, Dbg, "LfsForceWrite: Entered\n", 0 );
  372. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  373. DebugTrace( 0, Dbg, "NumberOfWriteEntries -> %08lx\n", NumberOfWriteEntries );
  374. DebugTrace( 0, Dbg, "WriteEntries -> %08lx\n", WriteEntries );
  375. DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType );
  376. DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId );
  377. DebugTrace( 0, Dbg, "UndoNextLsn (Low) -> %08lx\n", UndoNextLsn.LowPart );
  378. DebugTrace( 0, Dbg, "UndoNextLsn (High) -> %08lx\n", UndoNextLsn.HighPart );
  379. DebugTrace( 0, Dbg, "PreviousLsn (Low) -> %08lx\n", PreviousLsn.LowPart );
  380. DebugTrace( 0, Dbg, "PreviousLsn (High) -> %08lx\n", PreviousLsn.HighPart );
  381. Lch = (PLCH) LogHandle;
  382. //
  383. // Check that the structure is a valid log handle structure.
  384. //
  385. LfsValidateLch( Lch );
  386. //
  387. // Use a try-finally to facilitate cleanup.
  388. //
  389. try {
  390. //
  391. // Acquire the log file control block for this log file.
  392. //
  393. LfsAcquireLch( Lch );
  394. Lfcb = Lch->Lfcb;
  395. //
  396. // If the Log file has been closed then refuse access.
  397. //
  398. if (Lfcb == NULL) {
  399. ExRaiseStatus( STATUS_ACCESS_DENIED );
  400. }
  401. //
  402. // Check that the client Id is valid.
  403. //
  404. LfsValidateClientId( Lfcb, Lch );
  405. //
  406. // If the clean shutdown flag is currently set then clear it
  407. // before allowing more log records out.
  408. //
  409. if (FlagOn( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN )) {
  410. ClearFlag( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN );
  411. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );
  412. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );
  413. }
  414. //
  415. // Write the log record.
  416. //
  417. LogFileFull = LfsWriteLogRecordIntoLogPage( Lfcb,
  418. Lch,
  419. NumberOfWriteEntries,
  420. WriteEntries,
  421. RecordType,
  422. TransactionId,
  423. UndoNextLsn,
  424. PreviousLsn,
  425. UndoRequirement,
  426. TRUE,
  427. Lsn );
  428. //
  429. // The call to add this lbcb to the workque is guaranteed to release
  430. // the Lfcb if this thread may do the Io.
  431. //
  432. LfsFlushToLsnPriv( Lfcb, *Lsn );
  433. } finally {
  434. DebugUnwind( LfsForceWrite );
  435. //
  436. // Release the log file control block if held.
  437. //
  438. LfsReleaseLch( Lch );
  439. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
  440. DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
  441. DebugTrace( -1, Dbg, "LfsForceWrite: Exit\n", 0 );
  442. }
  443. return LogFileFull;
  444. }
  445. VOID
  446. LfsFlushToLsn (
  447. IN LFS_LOG_HANDLE LogHandle,
  448. IN LSN Lsn
  449. )
  450. /*++
  451. Routine Description:
  452. This routine is called by a client to insure that all log records
  453. to a certain point have been flushed to the file. This is done by
  454. checking if the desired Lsn has even been written at all. If so we
  455. check if it has been flushed to the file. If not, we simply write
  456. the current restart area to the disk.
  457. Arguments:
  458. LogHandle - Pointer to private Lfs structure used to identify this
  459. client.
  460. Lsn - This is the Lsn that must be on the disk on return from this
  461. routine.
  462. Return Value:
  463. None
  464. --*/
  465. {
  466. PLCH Lch;
  467. PLFCB Lfcb;
  468. PAGED_CODE();
  469. DebugTrace( +1, Dbg, "LfsFlushToLsn: Entered\n", 0 );
  470. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  471. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart );
  472. DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn.HighPart );
  473. Lch = (PLCH) LogHandle;
  474. //
  475. // Check that the structure is a valid log handle structure.
  476. //
  477. LfsValidateLch( Lch );
  478. //
  479. // Use a try-finally to facilitate cleanup.
  480. //
  481. try {
  482. //
  483. // Acquire the log file control block for this log file.
  484. //
  485. LfsAcquireLch( Lch );
  486. Lfcb = Lch->Lfcb;
  487. //
  488. // If the log file has been closed we will assume the Lsn has been flushed.
  489. //
  490. if (Lfcb != NULL) {
  491. //
  492. // Volumes mounted readonly ignore flush callbacks from lazy writer.
  493. //
  494. if (!FlagOn(Lfcb->Flags, LFCB_READ_ONLY)) {
  495. //
  496. // Check that the client Id is valid.
  497. //
  498. LfsValidateClientId( Lfcb, Lch );
  499. //
  500. // Call our common routine to perform the work.
  501. //
  502. LfsFlushToLsnPriv( Lfcb, Lsn );
  503. }
  504. }
  505. } finally {
  506. DebugUnwind( LfsFlushToLsn );
  507. //
  508. // Release the log file control block if held.
  509. //
  510. LfsReleaseLch( Lch );
  511. DebugTrace( -1, Dbg, "LfsFlushToLsn: Exit\n", 0 );
  512. }
  513. return;
  514. }
  515. VOID
  516. LfsCheckWriteRange (
  517. IN PLFS_WRITE_DATA WriteData,
  518. IN OUT PLONGLONG FlushOffset,
  519. IN OUT PULONG FlushLength
  520. )
  521. /*++
  522. Routine Description:
  523. This routine is called Ntfs to Lfs when a flush occurs. This will give Lfs a chance
  524. to trim the amount of the flush. Lfs can then use a 4K log record page size
  525. for all systems (Intel and Alpha).
  526. This routine will trim the size of the IO request to the value stored in the
  527. Lfcb for this volume. We will also redirty the second half of the page if
  528. we have begun writing log records into it.
  529. Arguments:
  530. WriteData - This is the data in the user's data structure which is maintained
  531. by Lfs to describe the current writes.
  532. FlushOffset - On input this is the start of the flush passed to Ntfs from MM.
  533. On output this is the start of the actual range to flush.
  534. FlushLength - On input this is the length of the flush from the given FlushOffset.
  535. On output this is the length of the flush from the possibly modified FlushOffset.
  536. Return Value:
  537. None
  538. --*/
  539. {
  540. PLIST_ENTRY Links;
  541. PLFCB Lfcb;
  542. PLFCB NextLfcb;
  543. ULONG Range;
  544. ULONG Index;
  545. PAGED_CODE();
  546. //
  547. // Find the correct Lfcb for this request.
  548. //
  549. Lfcb = WriteData->Lfcb;
  550. //
  551. // Trim the write if not a system page size.
  552. //
  553. if (Lfcb->LogPageSize != PAGE_SIZE) {
  554. //
  555. // Check if we are trimming before the write.
  556. //
  557. if (*FlushOffset < WriteData->FileOffset) {
  558. *FlushLength -= (ULONG) (WriteData->FileOffset - *FlushOffset);
  559. *FlushOffset = WriteData->FileOffset;
  560. }
  561. //
  562. // Check that we aren't flushing too much.
  563. //
  564. if (*FlushOffset + *FlushLength > WriteData->FileOffset + WriteData->Length) {
  565. *FlushLength = (ULONG) (WriteData->FileOffset + WriteData->Length - *FlushOffset);
  566. }
  567. //
  568. // Finally check if we have to redirty a page.
  569. //
  570. Range = (ULONG)PAGE_SIZE / (ULONG)Lfcb->LogPageSize;
  571. for (Index=0; Index < Range; Index++) {
  572. if (Lfcb->DirtyLbcb[Index] &&
  573. Lfcb->DirtyLbcb[Index]->FileOffset >= *FlushLength + *FlushOffset) {
  574. *((PULONG) (Lfcb->DirtyLbcb[Index]->PageHeader)) = LFS_SIGNATURE_RECORD_PAGE_ULONG;
  575. }
  576. }
  577. }
  578. return;
  579. }