Leaked source code of windows server 2003
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.

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