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.

653 lines
15 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Restart.c
  5. Abstract:
  6. This module implements the routines which access the client restart
  7. areas.
  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_RESTART)
  17. VOID
  18. LfsSetBaseLsnPriv (
  19. IN PLFCB Lfcb,
  20. IN PLFS_CLIENT_RECORD ClientRecord,
  21. IN LSN BaseLsn
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, LfsReadRestartArea)
  25. #pragma alloc_text(PAGE, LfsSetBaseLsn)
  26. #pragma alloc_text(PAGE, LfsSetBaseLsnPriv)
  27. #pragma alloc_text(PAGE, LfsWriteRestartArea)
  28. #endif
  29. NTSTATUS
  30. LfsReadRestartArea (
  31. IN LFS_LOG_HANDLE LogHandle,
  32. IN OUT PULONG BufferLength,
  33. IN PVOID Buffer,
  34. OUT PLSN Lsn
  35. )
  36. /*++
  37. Routine Description:
  38. This routine is called by the client when he wishes to read his restart
  39. area in the log file.
  40. Arguments:
  41. LogHandle - Pointer to private Lfs structure used to identify this
  42. client.
  43. BufferLength - On entry it is the length of the user buffer. On exit
  44. it is the size of the data stored in the buffer.
  45. Buffer - Pointer to the buffer where the client restart data is to be
  46. copied.
  47. Lsn - This is the Lsn for client restart area.
  48. Return Value:
  49. None
  50. --*/
  51. {
  52. BOOLEAN UsaError;
  53. PLCH Lch;
  54. PLFS_CLIENT_RECORD ClientRecord;
  55. PLFS_RECORD_HEADER RecordHeader;
  56. PBCB RecordHeaderBcb;
  57. PLFCB Lfcb;
  58. NTSTATUS RetStatus = STATUS_SUCCESS;
  59. PAGED_CODE();
  60. DebugTrace( +1, Dbg, "LfsReadRestartArea: Entered\n", 0 );
  61. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  62. DebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
  63. DebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer );
  64. RecordHeaderBcb = NULL;
  65. Lch = (PLCH) LogHandle;
  66. //
  67. // Check that the structure is a valid log handle structure.
  68. //
  69. LfsValidateLch( Lch );
  70. //
  71. // Use a try-finally to facilitate cleanup.
  72. //
  73. try {
  74. //
  75. // Acquire the log file control block for this log file.
  76. //
  77. LfsAcquireLch( Lch );
  78. Lfcb = Lch->Lfcb;
  79. //
  80. // If the Log file has been closed then refuse access.
  81. //
  82. if (Lfcb == NULL) {
  83. ExRaiseStatus( STATUS_ACCESS_DENIED );
  84. }
  85. //
  86. // Check that the client Id is valid.
  87. //
  88. LfsValidateClientId( Lfcb, Lch );
  89. ClientRecord = Add2Ptr( Lfcb->ClientArray,
  90. Lch->ClientArrayByteOffset,
  91. PLFS_CLIENT_RECORD );
  92. //
  93. // If the client doesn't have a restart area, go ahead and exit
  94. // now.
  95. //
  96. if (ClientRecord->ClientRestartLsn.QuadPart == 0) {
  97. //
  98. // We show there is no restart area by returning a length
  99. // of zero. We also set the Lsn value to zero so that
  100. // we can catch it if the user tries to use the Lsn.
  101. //
  102. DebugTrace( 0, Dbg, "No client restart area exists\n", 0 );
  103. *BufferLength = 0;
  104. *Lsn = LfsZeroLsn;
  105. try_return( NOTHING );
  106. }
  107. //
  108. // Release the Lfcb as we won't be modifying any fields in it.
  109. //
  110. LfsReleaseLfcb( Lfcb );
  111. //
  112. // Pin the log record for this Lsn.
  113. //
  114. LfsPinOrMapLogRecordHeader( Lfcb,
  115. ClientRecord->ClientRestartLsn,
  116. FALSE,
  117. FALSE,
  118. &UsaError,
  119. &RecordHeader,
  120. &RecordHeaderBcb );
  121. //
  122. // If the Lsn values don't match, then the disk is corrupt.
  123. //
  124. if (ClientRecord->ClientRestartLsn.QuadPart != RecordHeader->ThisLsn.QuadPart) {
  125. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  126. }
  127. //
  128. // Check that the user's buffer is big enough to hold the restart
  129. // data. We raise an error status for this error.
  130. //
  131. if (RecordHeader->ClientDataLength > *BufferLength) {
  132. DebugTrace( 0, Dbg, "Client buffer is too small\n", 0 );
  133. *BufferLength = RecordHeader->ClientDataLength;
  134. *Lsn = LfsZeroLsn;
  135. try_return( RetStatus = STATUS_BUFFER_TOO_SMALL );
  136. }
  137. //
  138. // Use the cache manager to copy the data into the user's buffer.
  139. //
  140. LfsCopyReadLogRecord( Lfcb,
  141. RecordHeader,
  142. Buffer );
  143. //
  144. // Pass the length and the Lsn of the restart area back to the
  145. // caller.
  146. //
  147. *BufferLength = RecordHeader->ClientDataLength;
  148. *Lsn = RecordHeader->ThisLsn;
  149. try_exit: NOTHING;
  150. } finally {
  151. DebugUnwind( LfsReadRestartArea );
  152. //
  153. // Release the log file control block if held.
  154. //
  155. LfsReleaseLch( Lch );
  156. //
  157. // Unpin the log record header for the client restart if pinned.
  158. //
  159. if (RecordHeaderBcb != NULL) {
  160. CcUnpinData( RecordHeaderBcb );
  161. }
  162. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
  163. DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
  164. DebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
  165. DebugTrace( -1, Dbg, "LfsReadRestartArea: Exit\n", 0 );
  166. }
  167. return RetStatus;
  168. }
  169. VOID
  170. LfsWriteRestartArea (
  171. IN LFS_LOG_HANDLE LogHandle,
  172. IN ULONG BufferLength,
  173. IN PVOID Buffer,
  174. IN LOGICAL CleanShutdown,
  175. OUT PLSN Lsn
  176. )
  177. /*++
  178. Routine Description:
  179. This routine is called by the client to write a restart area to the
  180. disk. This routine will not return to the caller until the client
  181. restart area and all prior Lsn's have been flushed and the Lfs
  182. restart area on the disk has been updated.
  183. On return, all log records up to and including 'Lsn' have been flushed
  184. to the disk.
  185. Arguments:
  186. LogHandle - Pointer to private Lfs structure used to identify this client.
  187. BufferLength - On entry it is the length of the user buffer.
  188. Buffer - Pointer to the buffer where the client restart data resides.
  189. CleanShutdown - Logical indicating that the caller won't need to run
  190. restart from this restart area. Lfs can set the CLEAN_SHUTDOWN flag
  191. in its restart area as an indication for 3rd party utilities that
  192. it is safe to party on the drive.
  193. Lsn - This is the Lsn for this write operation. On input, this will be the
  194. new Base Lsn for this client.
  195. **** This was used to prevent adding an interface change to
  196. the Beta release.
  197. Return Value:
  198. None
  199. --*/
  200. {
  201. PLCH Lch;
  202. PLFCB Lfcb;
  203. PLFS_CLIENT_RECORD ClientRecord;
  204. LFS_WRITE_ENTRY WriteEntry;
  205. PAGED_CODE();
  206. DebugTrace( +1, Dbg, "LfsWriteRestartArea: Entered\n", 0 );
  207. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  208. DebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", BufferLength );
  209. DebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer );
  210. Lch = (PLCH) LogHandle;
  211. //
  212. // Check that the structure is a valid log handle structure.
  213. //
  214. LfsValidateLch( Lch );
  215. //
  216. // Use a try-finally to facilitate cleanup.
  217. //
  218. try {
  219. //
  220. // Acquire the log file control block for this log file.
  221. //
  222. LfsAcquireLch( Lch );
  223. Lfcb = Lch->Lfcb;
  224. //
  225. // If the Log file has been closed then refuse access.
  226. //
  227. if (Lfcb == NULL) {
  228. ExRaiseStatus( STATUS_ACCESS_DENIED );
  229. }
  230. //
  231. // Check that the client Id is valid.
  232. //
  233. LfsValidateClientId( Lfcb, Lch );
  234. //
  235. // If the clean shutdown flag is currently set and this caller
  236. // will run restart out of this record then clear the bit on
  237. // disk first.
  238. //
  239. if (FlagOn( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN ) &&
  240. !CleanShutdown) {
  241. ClearFlag( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN );
  242. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );
  243. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );
  244. }
  245. //
  246. // Capture the client record after possibly updating above when writing
  247. // the lfs restart areas
  248. //
  249. ClientRecord = Add2Ptr( Lfcb->ClientArray,
  250. Lch->ClientArrayByteOffset,
  251. PLFS_CLIENT_RECORD );
  252. //
  253. // Go ahead and update the Base Lsn in the client area if the value
  254. // given is not zero.
  255. //
  256. if (Lsn->QuadPart != 0) {
  257. LfsSetBaseLsnPriv( Lfcb,
  258. ClientRecord,
  259. *Lsn );
  260. }
  261. //
  262. // Write this restart area as a log record into a log page.
  263. //
  264. WriteEntry.Buffer = Buffer;
  265. WriteEntry.ByteLength = BufferLength;
  266. LfsWriteLogRecordIntoLogPage( Lfcb,
  267. Lch,
  268. 1,
  269. &WriteEntry,
  270. LfsClientRestart,
  271. NULL,
  272. LfsZeroLsn,
  273. LfsZeroLsn,
  274. 0,
  275. TRUE,
  276. Lsn );
  277. //
  278. // Update the restart area for the client.
  279. //
  280. ClientRecord->ClientRestartLsn = *Lsn;
  281. //
  282. // Write the restart area to the disk.
  283. //
  284. if (CleanShutdown) {
  285. SetFlag( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN );
  286. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );
  287. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );
  288. } else {
  289. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );
  290. }
  291. } finally {
  292. DebugUnwind( LfsWriteRestartArea );
  293. //
  294. // Release the log file control block if still held.
  295. //
  296. LfsReleaseLch( Lch );
  297. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
  298. DebugTrace( 0, Dbg, "Log (High) -> %08lx\n", Lsn->HighPart );
  299. DebugTrace( -1, Dbg, "LfsWriteRestartArea: Exit\n", 0 );
  300. }
  301. return;
  302. }
  303. VOID
  304. LfsSetBaseLsn (
  305. IN LFS_LOG_HANDLE LogHandle,
  306. IN LSN BaseLsn
  307. )
  308. /*++
  309. Routine Description:
  310. This routine is called by the client to notify the log service of the
  311. oldest Lsn he expects to need during restart. The Lfs is allowed to
  312. reuse any part of the circular log file which logically precedes
  313. this Lsn. A client may only specify a Lsn which follows the previous
  314. Lsn specified by this client.
  315. Arguments:
  316. LogHandle - Pointer to private Lfs structure used to identify this
  317. client.
  318. BaseLsn - This is the oldest Lsn the client may require during a
  319. restart.
  320. Return Value:
  321. None
  322. --*/
  323. {
  324. volatile NTSTATUS Status = STATUS_SUCCESS;
  325. PLCH Lch;
  326. PLFCB Lfcb;
  327. PLFS_CLIENT_RECORD ClientRecord;
  328. PAGED_CODE();
  329. DebugTrace( +1, Dbg, "LfsSetBaseLsn: Entered\n", 0 );
  330. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  331. DebugTrace( 0, Dbg, "Base Lsn (Low) -> %08lx\n", BaseLsn.LowPart );
  332. DebugTrace( 0, Dbg, "Base Lsn (High) -> %08lx\n", BaseLsn.HighPart );
  333. Lch = (PLCH) LogHandle;
  334. //
  335. // Check that the structure is a valid log handle structure.
  336. //
  337. LfsValidateLch( Lch );
  338. //
  339. // Use a try-except to catch errors.
  340. //
  341. try {
  342. //
  343. // Use a try-finally to facilitate cleanup.
  344. //
  345. try {
  346. //
  347. // Acquire the log file control block for this log file.
  348. //
  349. LfsAcquireLch( Lch );
  350. Lfcb = Lch->Lfcb;
  351. //
  352. // If the Log file has been closed then refuse access.
  353. //
  354. if (Lfcb == NULL) {
  355. ExRaiseStatus( STATUS_ACCESS_DENIED );
  356. }
  357. //
  358. // Check that the client Id is valid.
  359. //
  360. LfsValidateClientId( Lfcb, Lch );
  361. ClientRecord = Add2Ptr( Lfcb->ClientArray,
  362. Lch->ClientArrayByteOffset,
  363. PLFS_CLIENT_RECORD );
  364. //
  365. // We simply call the worker routine to advance the base lsn.
  366. // If we moved forward in the file, we will put our restart area in the
  367. // queue.
  368. //
  369. LfsSetBaseLsnPriv( Lfcb,
  370. ClientRecord,
  371. BaseLsn );
  372. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );
  373. } finally {
  374. DebugUnwind( LfsSetBaseLsn );
  375. //
  376. // Release the log file control block if held.
  377. //
  378. LfsReleaseLch( Lch );
  379. DebugTrace( -1, Dbg, "LfsSetBaseLsn: Exit\n", 0 );
  380. }
  381. } except (LfsExceptionFilter( GetExceptionInformation() )) {
  382. Status = GetExceptionCode();
  383. }
  384. if (Status != STATUS_SUCCESS) {
  385. ExRaiseStatus( Status );
  386. }
  387. return;
  388. }
  389. //
  390. // Local support routine
  391. //
  392. VOID
  393. LfsSetBaseLsnPriv (
  394. IN PLFCB Lfcb,
  395. IN PLFS_CLIENT_RECORD ClientRecord,
  396. IN LSN BaseLsn
  397. )
  398. /*++
  399. Routine Description:
  400. This worker routine is called internally by Lfs to modify the
  401. oldest Lsn a client expects to need during restart. The Lfs is allowed to
  402. reuse any part of the circular log file which logically precedes
  403. this Lsn. A client may only specify a Lsn which follows the previous
  404. Lsn specified by this client.
  405. Arguments:
  406. Lfcb - Log context block for this file.
  407. ClientRecord - For the client whose base Lsn is being modified.
  408. BaseLsn - This is the oldest Lsn the client may require during a
  409. restart.
  410. Return Value:
  411. None.
  412. --*/
  413. {
  414. PAGED_CODE();
  415. DebugTrace( +1, Dbg, "LfsSetBaseLsn: Entered\n", 0 );
  416. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  417. DebugTrace( 0, Dbg, "Base Lsn (Low) -> %08lx\n", BaseLsn.LowPart );
  418. DebugTrace( 0, Dbg, "Base Lsn (High) -> %08lx\n", BaseLsn.HighPart );
  419. //
  420. // We only proceed if the client is moving forward in the file.
  421. //
  422. if (BaseLsn.QuadPart > Lfcb->OldestLsn.QuadPart) {
  423. if (BaseLsn.QuadPart > ClientRecord->OldestLsn.QuadPart) {
  424. ClientRecord->OldestLsn = BaseLsn;
  425. }
  426. Lfcb->OldestLsn = BaseLsn;
  427. //
  428. // We walk through all the active clients and find the new
  429. // oldest Lsn for the log file.
  430. //
  431. LfsFindOldestClientLsn( Lfcb->RestartArea,
  432. Lfcb->ClientArray,
  433. &Lfcb->OldestLsn );
  434. Lfcb->OldestLsnOffset = LfsLsnToFileOffset( Lfcb, Lfcb->OldestLsn );
  435. ClearFlag( Lfcb->Flags, LFCB_NO_OLDEST_LSN );
  436. LfsFindCurrentAvail( Lfcb );
  437. }
  438. DebugTrace( -1, Dbg, "LfsSetBaseLsnPriv: Exit\n", 0 );
  439. return;
  440. }