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.

524 lines
15 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. store.c
  5. Abstract:
  6. Interface for storing and retrieving checkpoint data on the quorum
  7. disk.
  8. Author:
  9. John Vert (jvert) 1/14/1997
  10. Revision History:
  11. --*/
  12. #include "cpp.h"
  13. #include <ntddvol.h>
  14. DWORD
  15. CppGetCheckpointFile(
  16. IN PFM_RESOURCE Resource,
  17. IN DWORD dwId,
  18. OUT OPTIONAL LPWSTR *pDirectoryName,
  19. OUT LPWSTR *pFileName,
  20. IN OPTIONAL LPCWSTR lpszQuorumDir,
  21. IN BOOLEAN fCryptoCheckpoint
  22. )
  23. /*++
  24. Routine Description:
  25. Constructs the correct directory and file names for the checkpoint
  26. file on the quorum disk.
  27. Arguments:
  28. Resource - Supplies the quorum resource.
  29. dwId - Supplies the checkpoint ID
  30. DirectoryName - if present, returns the full name of the directory the
  31. checkpoint file should be created in. This buffer must be
  32. freed by the caller with LocalFree
  33. FileName - Returns the full pathname of the checkpoint file. This buffer must
  34. be freed by the caller with LocalFree
  35. lpszQuorumDir - If present, supplies the quorum directory to use.
  36. If not present, the current quorum directory is used.
  37. fCryptoCheckpoint - Indicates if the checkpoint is a crypto checkpoint.
  38. Return Value:
  39. ERROR_SUCCESS if successful
  40. Win32 error code otherwise
  41. --*/
  42. {
  43. DWORD Status;
  44. LPCWSTR ResourceId;
  45. LPWSTR QuorumDir=NULL;
  46. DWORD QuorumDirLength=0;
  47. LPWSTR Dir;
  48. DWORD DirLen;
  49. LPWSTR File;
  50. DWORD FileLen;
  51. WCHAR Buff[13]; // 8.3 + NULL
  52. if (lpszQuorumDir == NULL) {
  53. Status = DmQuerySz( DmQuorumKey,
  54. cszPath,
  55. &QuorumDir,
  56. &QuorumDirLength,
  57. &QuorumDirLength);
  58. if (Status != ERROR_SUCCESS) {
  59. ClRtlLogPrint(LOG_CRITICAL,
  60. "[CP] CppGetCheckpointFile failed to get quorum path %1!d!\n",
  61. Status);
  62. return(Status);
  63. }
  64. } else {
  65. QuorumDir = (LPWSTR)lpszQuorumDir;
  66. QuorumDirLength = (lstrlenW(QuorumDir)+1)*sizeof(WCHAR);
  67. }
  68. ResourceId = OmObjectId(Resource);
  69. DirLen = QuorumDirLength + sizeof(WCHAR) + (lstrlenW(ResourceId)*sizeof(WCHAR));
  70. Dir = LocalAlloc(LMEM_FIXED, DirLen);
  71. if (Dir == NULL) {
  72. if (lpszQuorumDir == NULL) {
  73. LocalFree(QuorumDir);
  74. }
  75. return(ERROR_NOT_ENOUGH_MEMORY);
  76. }
  77. lstrcpyW(Dir, QuorumDir);
  78. lstrcatW(Dir, L"\\");
  79. lstrcatW(Dir, ResourceId);
  80. if (lpszQuorumDir == NULL) {
  81. LocalFree(QuorumDir);
  82. }
  83. //
  84. // Now construct the file name
  85. //
  86. FileLen = DirLen + sizeof(WCHAR) + sizeof(Buff);
  87. File = LocalAlloc(LMEM_FIXED, FileLen);
  88. if (File == NULL) {
  89. LocalFree(Dir);
  90. return(ERROR_NOT_ENOUGH_MEMORY);
  91. }
  92. if (fCryptoCheckpoint) {
  93. wsprintfW(Buff, L"%08lx.CPR", dwId);
  94. } else {
  95. wsprintfW(Buff, L"%08lx.CPT", dwId);
  96. }
  97. lstrcpyW(File, Dir);
  98. lstrcatW(File, L"\\");
  99. lstrcatW(File, Buff);
  100. if (ARGUMENT_PRESENT(pDirectoryName)) {
  101. *pDirectoryName = Dir;
  102. } else {
  103. LocalFree(Dir);
  104. }
  105. *pFileName = File;
  106. return(ERROR_SUCCESS);
  107. }
  108. DWORD
  109. CppReadCheckpoint(
  110. IN PFM_RESOURCE Resource,
  111. IN DWORD dwCheckpointId,
  112. IN LPCWSTR lpszFileName,
  113. IN BOOLEAN fCryptoCheckpoint
  114. )
  115. /*++
  116. Routine Description:
  117. Reads a checkpoint off the quorum disk.
  118. Arguments:
  119. Resource - Supplies the resource associated with this data.
  120. dwCheckpointId - Supplies the unique checkpoint ID describing this data. The caller is
  121. responsible for ensuring the uniqueness of the checkpoint ID.
  122. lpszFileName - Supplies the filename where the data should be retrieved.
  123. fCryptoCheckpoint - Indicates if the checkpoint is a crypto checkpoint.
  124. Return Value:
  125. ERROR_SUCCESS if successful
  126. Win32 error code otherwise
  127. --*/
  128. {
  129. DWORD Status = ERROR_SUCCESS;
  130. LPWSTR FileName = NULL;
  131. BOOL Success;
  132. //
  133. // Chittur Subbaraman (chitturs) - 8/2/99
  134. //
  135. // Remove gQuoLock acquisition from this function also following
  136. // the reasoning outlined in CppWriteCheckpoint function. Note that
  137. // the caller of this function will retry on specific errors.
  138. // [We have to play these hacks to survive !]
  139. //
  140. Status = CppGetCheckpointFile(Resource,
  141. dwCheckpointId,
  142. NULL,
  143. &FileName,
  144. NULL,
  145. fCryptoCheckpoint);
  146. if (Status != ERROR_SUCCESS) {
  147. ClRtlLogPrint(LOG_CRITICAL,
  148. "[CP] CppReadCheckpoint - CppGetCheckpointFile failed %1!d!\n",
  149. Status);
  150. goto FnExit;
  151. }
  152. ClRtlLogPrint(LOG_NOISE,
  153. "[CP] CppReadCheckpoint restoring checkpoint from file %1!ws! to %2!ws!\n",
  154. FileName,
  155. lpszFileName);
  156. Success = CopyFile(FileName, lpszFileName, FALSE);
  157. if (!Success) {
  158. Status = GetLastError();
  159. ClRtlLogPrint(LOG_CRITICAL,
  160. "[CP] CppReadCheckpoint unable to copy file %1!ws! to %2!ws!, error %3!d!\n",
  161. FileName,
  162. lpszFileName,
  163. Status);
  164. ClRtlLogPrint(LOG_CRITICAL,
  165. "[CP] CppReadCheckpoint - Was that due to quorum resource not being up ???\n");
  166. } else {
  167. Status = ERROR_SUCCESS;
  168. }
  169. FnExit:
  170. if (FileName) LocalFree(FileName);
  171. //
  172. // Adjust the return status if the quorum volume is truly offline and that is why this
  173. // call failed.
  174. //
  175. if ( ( Status != ERROR_SUCCESS ) && ( CppIsQuorumVolumeOffline() == TRUE ) ) Status = ERROR_NOT_READY;
  176. return(Status);
  177. }
  178. DWORD
  179. CppWriteCheckpoint(
  180. IN PFM_RESOURCE Resource,
  181. IN DWORD dwCheckpointId,
  182. IN LPCWSTR lpszFileName,
  183. IN BOOLEAN fCryptoCheckpoint
  184. )
  185. /*++
  186. Routine Description:
  187. Writes a checkpoint to the quorum disk.
  188. Arguments:
  189. Resource - Supplies the resource associated with this data.
  190. dwCheckpointId - Supplies the unique checkpoint ID describing this data. The caller is responsible
  191. for ensuring the uniqueness of the checkpoint ID.
  192. lpszFileName - Supplies the name of the file with the checkpoint data.
  193. fCryptoCheckpoint - Indicates if the checkpoint is a crypto checkpoint.
  194. Return Value:
  195. ERROR_SUCCESS if successful
  196. Win32 error code otherwise
  197. --*/
  198. {
  199. DWORD Status = ERROR_SUCCESS;
  200. LPWSTR DirectoryName = NULL;
  201. LPWSTR FileName = NULL;
  202. BOOL Success;
  203. HANDLE hDirectory = INVALID_HANDLE_VALUE;
  204. //
  205. // Chittur Subbaraman (chitturs) - 8/2/99
  206. //
  207. // Remove gQuoLock acquisition from this function. This is necessary
  208. // since this function could get invoked indirectly from
  209. // FmpRmDoInterlockedDecrement (as a part of the synchronous
  210. // notification - Consider a case where the resource is failing
  211. // or going offline and you have to rundown the checkpoints as
  212. // a part of the synchronous notification. The rundown function
  213. // CppRundownCheckpoints needs to wait until the CppRegNotifyThread
  214. // completes and the latter could be stuck trying to write a
  215. // checkpoint by calling this function) before the "blockingres" count is
  216. // decremented. Now the quorum resource offline operation could
  217. // be waiting inside FmpRmOfflineResource waiting for this count
  218. // to go down to zero and this holds the gQuoLock (so as not to
  219. // let any more resources to bump up this count). So if we want
  220. // to get the gQuoLock here, we have an easy deadlock. Note that
  221. // the caller of this function will retry on specific errors.
  222. // [We have to play these hacks to survive !]
  223. //
  224. Status = CppGetCheckpointFile(Resource,
  225. dwCheckpointId,
  226. &DirectoryName,
  227. &FileName,
  228. NULL,
  229. fCryptoCheckpoint);
  230. if (Status != ERROR_SUCCESS)
  231. {
  232. ClRtlLogPrint(LOG_CRITICAL,
  233. "[CP] CppWriteCheckpoint - CppGetCheckpointFile failed %1!d!\n",
  234. Status);
  235. goto FnExit;
  236. }
  237. ClRtlLogPrint(LOG_NOISE,
  238. "[CP] CppWriteCheckpoint checkpointing file %1!ws! to file %2!ws!\n",
  239. lpszFileName,
  240. FileName);
  241. //
  242. // Create the directory.
  243. //
  244. if (!CreateDirectory(DirectoryName, NULL))
  245. {
  246. Status = GetLastError();
  247. if (Status != ERROR_ALREADY_EXISTS)
  248. {
  249. ClRtlLogPrint(LOG_CRITICAL,
  250. "[CP] CppWriteCheckpoint unable to create directory %1!ws!, error %2!d!\n",
  251. DirectoryName,
  252. Status);
  253. goto FnExit;
  254. }
  255. else
  256. {
  257. //the directory exists, it is alright, set Status to ERROR_SUCCESS
  258. Status = ERROR_SUCCESS;
  259. }
  260. }
  261. else
  262. {
  263. //
  264. // The directory was newly created. Put the appropriate ACL on it
  265. // so that only ADMINs can read it.
  266. //
  267. hDirectory = CreateFile(DirectoryName,
  268. GENERIC_READ | WRITE_DAC | READ_CONTROL,
  269. 0,
  270. NULL,
  271. OPEN_ALWAYS,
  272. FILE_FLAG_BACKUP_SEMANTICS,
  273. NULL);
  274. if (hDirectory == INVALID_HANDLE_VALUE)
  275. {
  276. Status = GetLastError();
  277. ClRtlLogPrint(LOG_CRITICAL,
  278. "[CP] CppWriteCheckpoint unable to open directory %1!ws!, error %2!d!\n",
  279. DirectoryName,
  280. Status);
  281. goto FnExit;
  282. }
  283. Status = ClRtlSetObjSecurityInfo(hDirectory,
  284. SE_FILE_OBJECT,
  285. GENERIC_ALL,
  286. GENERIC_ALL,
  287. 0);
  288. if (Status != ERROR_SUCCESS)
  289. {
  290. ClRtlLogPrint(LOG_CRITICAL,
  291. "[CP] CppWriteCheckpoint unable to set ACL on directory %1!ws!, error %2!d!\n",
  292. DirectoryName,
  293. Status);
  294. goto FnExit;
  295. }
  296. }
  297. //
  298. // Copy the file
  299. //
  300. Success = CopyFile(lpszFileName, FileName, FALSE);
  301. if (!Success)
  302. {
  303. Status = GetLastError();
  304. ClRtlLogPrint(LOG_CRITICAL,
  305. "[CP] CppWriteCheckpoint unable to copy file %1!ws! to %2!ws!, error %3!d!\n",
  306. lpszFileName,
  307. FileName,
  308. Status);
  309. }
  310. FnExit:
  311. //clean up
  312. if (DirectoryName) LocalFree(DirectoryName);
  313. if (FileName) LocalFree(FileName);
  314. if (hDirectory != INVALID_HANDLE_VALUE) CloseHandle(hDirectory);
  315. //
  316. // Adjust the return status if the quorum volume is truly offline and that is why this
  317. // call failed.
  318. //
  319. if ( ( Status != ERROR_SUCCESS ) && ( CppIsQuorumVolumeOffline() == TRUE ) ) Status = ERROR_NOT_READY;
  320. return(Status);
  321. }
  322. BOOL
  323. CppIsQuorumVolumeOffline(
  324. VOID
  325. )
  326. /*++
  327. Routine Description:
  328. Check the state of the quorum volume.
  329. Arguments:
  330. None
  331. Return Value:
  332. TRUE - Quorum volume is offline.
  333. FALSE - Quorum volume is online OR it is not possible to determine the quorum volume state
  334. Notes:
  335. This function is called in private CP functions to check if the quorum volume is offline or not.
  336. This is necessary since the error codes returned in those functions when they try to
  337. access the quorum disk when it is offline does not deterministically point out the state
  338. of the disk. Note that this function will only perform its job when the quorum volume is
  339. a physical disk since the storage stack drivers alone implement the IOCTL_IS_VOLUME_OFFLINE
  340. at the time of this implementation.
  341. --*/
  342. {
  343. HANDLE hFile = INVALID_HANDLE_VALUE;
  344. DWORD dwStatus;
  345. DWORD cbBytesReturned = 0;
  346. WCHAR szFileName[10];
  347. WCHAR szQuorumLogPath[MAX_PATH];
  348. WCHAR szQuorumDriveLetter[4];
  349. BOOL fOffline = FALSE;
  350. //
  351. // Get the quorum log path so that we can get the quorum drive letter off it.
  352. //
  353. dwStatus = DmGetQuorumLogPath( szQuorumLogPath, sizeof( szQuorumLogPath ) );
  354. if ( dwStatus != ERROR_SUCCESS )
  355. {
  356. ClRtlLogPrint(LOG_CRITICAL,
  357. "[CP] CppIsQuorumVolumeOffline: DmGetQuorumLogPath failed, Status = %1!u!...\n",
  358. dwStatus);
  359. goto FnExit;
  360. }
  361. //
  362. // Create a file name of the form \\.\Q:
  363. //
  364. lstrcpyn( szQuorumDriveLetter, szQuorumLogPath, 3 );
  365. //
  366. // See if the drive letter looks syntactically valid. We don't want to proceed further
  367. // if the quorum is a network share.
  368. //
  369. if ( !ClRtlIsPathValid( szQuorumDriveLetter ) )
  370. {
  371. ClRtlLogPrint(LOG_NOISE,
  372. "[CP] CppIsQuorumVolumeOffline: Quorum path %1!ws! does not have a drive letter, returning...\n",
  373. szQuorumLogPath);
  374. goto FnExit;
  375. }
  376. lstrcpy( szFileName, L"\\\\.\\" );
  377. lstrcat( szFileName, szQuorumDriveLetter );
  378. //
  379. // Open a handle to the quorum volume
  380. //
  381. hFile = CreateFileW( szFileName,
  382. GENERIC_READ,
  383. 0,
  384. NULL,
  385. OPEN_EXISTING,
  386. 0,
  387. NULL );
  388. if ( hFile == INVALID_HANDLE_VALUE )
  389. {
  390. dwStatus = GetLastError();
  391. ClRtlLogPrint(LOG_UNUSUAL,
  392. "[CP] CppIsQuorumVolumeOffline: CreateFile for file %1!ws! failed, Status = %2!u!...\n",
  393. szFileName,
  394. dwStatus);
  395. goto FnExit;
  396. }
  397. //
  398. // Check if the volume is offline or not
  399. //
  400. if ( !DeviceIoControl( hFile, // Device handle
  401. IOCTL_VOLUME_IS_OFFLINE, // IOCTL code
  402. NULL, // In buffer
  403. 0, // In buffer size
  404. NULL, // Out buffer
  405. 0, // Out buffer size
  406. &cbBytesReturned, // Bytes returned
  407. NULL ) ) // Overlapped
  408. {
  409. dwStatus = GetLastError();
  410. if ( dwStatus != ERROR_GEN_FAILURE )
  411. ClRtlLogPrint(LOG_UNUSUAL,
  412. "[CP] CppIsQuorumVolumeOffline: IOCTL_VOLUME_IS_OFFLINE failed, Status = %1!u!...\n",
  413. dwStatus);
  414. goto FnExit;
  415. }
  416. //
  417. // Volume is offline, adjust return status
  418. //
  419. fOffline = TRUE;
  420. ClRtlLogPrint(LOG_NOISE, "[CP] CppIsQuorumVolumeOffline: Quorum volume IS offline...\n");
  421. FnExit:
  422. if ( hFile != INVALID_HANDLE_VALUE ) CloseHandle( hFile );
  423. return ( fOffline );
  424. }// CppIsQuorumVolumeOffline