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.

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