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.

445 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. install.c
  5. Abstract:
  6. Staging File Install Command Server.
  7. Author:
  8. Billy J. Fuller 09-Jun-1997
  9. Environment
  10. User mode winnt
  11. --*/
  12. #include <ntreppch.h>
  13. #pragma hdrstop
  14. #include <frs.h>
  15. #include <tablefcn.h>
  16. #include <perrepsr.h>
  17. //
  18. // Struct for the Staging File Generator Command Server
  19. // Contains info about the queues and the threads
  20. //
  21. COMMAND_SERVER InstallCs;
  22. ULONG MaxInstallCsThreads;
  23. //
  24. // Count the number of files currently being installed.
  25. //
  26. LONG FrsFilesInInstall = -1;
  27. #if 0
  28. //
  29. // Currently unused.
  30. //
  31. //
  32. // Retry times
  33. //
  34. #define INSTALLCS_RETRY_MIN (1 * 1000) // 1 second
  35. #define INSTALLCS_RETRY_MAX (10 * 1000) // 10 seconds
  36. BOOL
  37. InstallCsDelCsSubmit(
  38. IN PCOMMAND_PACKET Cmd
  39. )
  40. /*++
  41. Routine Description:
  42. Set the timer and kick off a delayed staging file command
  43. Arguments:
  44. Cmd
  45. Return Value:
  46. None.
  47. --*/
  48. {
  49. #undef DEBSUB
  50. #define DEBSUB "InstallCsDelCsSubmit:"
  51. //
  52. // Extend the retry time (but not too long)
  53. //
  54. RsTimeout(Cmd) <<= 1;
  55. if (RsTimeout(Cmd) > INSTALLCS_RETRY_MAX)
  56. return FALSE;
  57. //
  58. // or too short
  59. //
  60. if (RsTimeout(Cmd) < INSTALLCS_RETRY_MIN)
  61. RsTimeout(Cmd) = INSTALLCS_RETRY_MIN;
  62. //
  63. // This command will come back to us in a bit
  64. //
  65. FrsDelCsSubmitSubmit(&InstallCs, Cmd, RsTimeout(Cmd));
  66. return TRUE;
  67. }
  68. #endif 0
  69. VOID
  70. InstallCsInstallStage(
  71. IN PCOMMAND_PACKET Cmd
  72. )
  73. /*++
  74. Routine Description:
  75. Install the staging file into the target file. If successfull then
  76. send the CO to the retire code. If not and the condition is retryable then
  77. send the CO to the retry code. Otherwise abort the CO.
  78. Arguments:
  79. Cmd
  80. Return Value:
  81. None.
  82. --*/
  83. {
  84. #undef DEBSUB
  85. #define DEBSUB "InstallCsInstallStage:"
  86. ULONG WStatus;
  87. PCHANGE_ORDER_ENTRY Coe;
  88. //
  89. // Install the staging file
  90. //
  91. Coe = RsCoe(Cmd);
  92. WStatus = StuInstallStage(Coe);
  93. if (!WIN_SUCCESS(WStatus)) {
  94. if (DOES_CO_DELETE_FILE_NAME(RsCoc(Cmd))) {
  95. //
  96. // All delete and moveout change orders go thru retire. At this
  97. // point they are done except possibly for the final on-disk
  98. // delete. If the on-disk delete failed then the
  99. // COE_FLAG_NEED_DELETE is set in the
  100. // change order which sets IDREC_FLAGS_DELETE_DEFERRED in the
  101. // IDTable record for the file.
  102. //
  103. FRS_ASSERT(COE_FLAG_ON(Coe, COE_FLAG_NEED_DELETE));
  104. SET_CHANGE_ORDER_STATE(Coe, IBCO_INSTALL_DEL_RETRY);
  105. PM_INC_CTR_REPSET(Coe->NewReplica, FInstalled, 1);
  106. //
  107. // Retire this change order
  108. //
  109. ChgOrdInboundRetired(Coe);
  110. //
  111. // non-NULL change order entries kick the completion function
  112. // to start retry/unjoin. No need since we have retired this co.
  113. //
  114. RsCoe(Cmd) = NULL;
  115. goto out;
  116. }
  117. //
  118. // Something is wrong; try again later
  119. //
  120. // If it is retryable then retry.
  121. // Note that an ERROR_FILE_NOT_FOUND return from StuExecuteInstall means that the
  122. // pre-exisitng target file was not found. Most likely because it was
  123. // deleted out from under us. We should be getting a Local change order
  124. // that will update the IDTable entry so when this CO is retried later
  125. // it will get rejected.
  126. //
  127. if (WIN_RETRY_INSTALL(WStatus) ||
  128. (WStatus == ERROR_FILE_NOT_FOUND)) {
  129. CHANGE_ORDER_TRACEW(3, Coe, "Retrying install", WStatus);
  130. //
  131. // Retry this single change order if the namespace isn't
  132. // being altered (not a create or rename). Otherwise,
  133. // unjoin the cxtion and force all change orders through
  134. // retry so they will be retried in order at join; just
  135. // in case this change order affects later ones.
  136. //
  137. // Unjoining is sort of extreme; need less expensive recovery.
  138. // But if we don't unjoin (say for a rename) and a
  139. // create CO arrives next then we will have a name conflict
  140. // that should not have occurred just because a sharing violation
  141. // prevented us from doing the rename.
  142. //
  143. if ((!CoCmdIsDirectory(RsCoc(Cmd))) ||
  144. (!FrsDoesCoAlterNameSpace(RsCoc(Cmd)))) {
  145. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to install retry");
  146. ChgOrdInboundRetry(Coe, IBCO_INSTALL_RETRY);
  147. //
  148. // non-NULL change order entries kick the completion
  149. // function to start a retry/unjoin. No need since we have
  150. // retired this co.
  151. //
  152. RsCoe(Cmd) = NULL;
  153. }
  154. goto out;
  155. } else {
  156. //
  157. // Not retryable.
  158. //
  159. // Note: If it's not a problem with the staging file we should send
  160. // it on even if we can't install it. Not clear what non-retryable
  161. // errors this would apply to though. For now just abort it.
  162. //
  163. SET_COE_FLAG(Coe, COE_FLAG_STAGE_ABORTED);
  164. CHANGE_ORDER_TRACEW(3, Coe, "Install failed; co aborted", WStatus);
  165. //
  166. // Increment the Files Installed Counter
  167. //
  168. PM_INC_CTR_REPSET(Coe->NewReplica, FInstalledError, 1);
  169. }
  170. } else {
  171. //
  172. // Install succeeded. Increment the Files Installed Counter.
  173. //
  174. CHANGE_ORDER_TRACE(3, Coe, "Install success");
  175. PM_INC_CTR_REPSET(Coe->NewReplica, FInstalled, 1);
  176. //
  177. // If this CO created a preinstall file then tell the retire path to
  178. // perform the final rename. Updates to existing files don't create
  179. // preinstall files.
  180. //
  181. if (COE_FLAG_ON(Coe, COE_FLAG_PREINSTALL_CRE)) {
  182. SET_COE_FLAG(Coe, COE_FLAG_NEED_RENAME);
  183. }
  184. }
  185. //
  186. // Installing the fetched staging file
  187. //
  188. SET_CHANGE_ORDER_STATE(Coe, IBCO_INSTALL_COMPLETE);
  189. //
  190. // Retire this change order
  191. //
  192. ChgOrdInboundRetired(Coe);
  193. //
  194. // non-NULL change order entries kick the completion function
  195. // to start retry/unjoin. No need since we have retired this co.
  196. //
  197. RsCoe(Cmd) = NULL;
  198. out:
  199. //
  200. // ERROR_SUCCESS just means we have handled all of the conditions
  201. // that arose; no need for the cleanup function to intervene.
  202. //
  203. // Unless RsCoe(Cmd) is non-NULL; in which case the completion
  204. // function will initiate a retry/unjoin.
  205. //
  206. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  207. }
  208. DWORD
  209. MainInstallCs(
  210. PVOID Arg
  211. )
  212. /*++
  213. Routine Description:
  214. Entry point for a thread serving the Staging File Install Command Server.
  215. Arguments:
  216. Arg - thread
  217. Return Value:
  218. None.
  219. --*/
  220. {
  221. #undef DEBSUB
  222. #define DEBSUB "MainInstallCs:"
  223. ULONG WStatus = ERROR_SUCCESS;
  224. PCOMMAND_PACKET Cmd;
  225. PFRS_THREAD FrsThread = (PFRS_THREAD)Arg;
  226. HANDLE WaitHandles[2];
  227. //
  228. // Thread is pointing at the correct command server
  229. //
  230. FRS_ASSERT(FrsThread->Data == &InstallCs);
  231. FrsThread->Exit = ThSupExitWithTombstone;
  232. //
  233. // Try-Finally
  234. //
  235. try {
  236. //
  237. // Capture exception.
  238. //
  239. try {
  240. //
  241. // Pull entries off the queue and process them
  242. //
  243. //
  244. // Handles to wait on
  245. //
  246. WaitHandles[0] = FrsThawEvent;
  247. WaitHandles[1] = ShutDownEvent;
  248. cant_exit_yet:
  249. while (Cmd = FrsGetCommandServer(&InstallCs)) {
  250. InterlockedIncrement(&FrsFilesInInstall);
  251. DPRINT2(4,"Inc FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  252. if (FrsFrozenForBackup) {
  253. if ((InterlockedDecrement(&FrsFilesInInstall) < 0) &&
  254. FrsFrozenForBackup) {
  255. SetEvent(FrsNoInstallsInProgressEvent);
  256. }
  257. DPRINT2(4,"Dec FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  258. WaitForMultipleObjects(2, WaitHandles, FALSE, INFINITE);
  259. InterlockedIncrement(&FrsFilesInInstall);
  260. DPRINT2(4,"Inc FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  261. }
  262. switch (Cmd->Command) {
  263. case CMD_INSTALL_STAGE:
  264. DPRINT1(3, "Install: command install stage 0x%x\n", Cmd);
  265. InstallCsInstallStage(Cmd);
  266. break;
  267. default:
  268. DPRINT1(0, "Staging File Install: unknown command 0x%x\n", Cmd->Command);
  269. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  270. break;
  271. }
  272. if ((InterlockedDecrement(&FrsFilesInInstall) < 0) &&
  273. FrsFrozenForBackup) {
  274. SetEvent(FrsNoInstallsInProgressEvent);
  275. }
  276. DPRINT2(4,"Dec FrsFrozen = %d, FrsFilesInInstall = %d\n", FrsFrozenForBackup,FrsFilesInInstall);
  277. }
  278. //
  279. // Exit
  280. //
  281. FrsExitCommandServer(&InstallCs, FrsThread);
  282. goto cant_exit_yet;
  283. //
  284. // Get exception status.
  285. //
  286. } except (EXCEPTION_EXECUTE_HANDLER) {
  287. GET_EXCEPTION_CODE(WStatus);
  288. }
  289. } finally {
  290. if (WIN_SUCCESS(WStatus)) {
  291. if (AbnormalTermination()) {
  292. WStatus = ERROR_OPERATION_ABORTED;
  293. }
  294. }
  295. DPRINT_WS(0, "InstallCs finally.", WStatus);
  296. //
  297. // Trigger FRS shutdown if we terminated abnormally.
  298. //
  299. if (!WIN_SUCCESS(WStatus)) {
  300. DPRINT(0, "InstallCs terminated abnormally, forcing service shutdown.\n");
  301. FrsIsShuttingDown = TRUE;
  302. SetEvent(ShutDownEvent);
  303. } else {
  304. WStatus = ERROR_SUCCESS;
  305. }
  306. }
  307. return WStatus;
  308. }
  309. VOID
  310. FrsInstallCsInitialize(
  311. VOID
  312. )
  313. /*++
  314. Routine Description:
  315. Initialize the staging file installer
  316. Arguments:
  317. None.
  318. Return Value:
  319. None.
  320. --*/
  321. {
  322. #undef DEBSUB
  323. #define DEBSUB "FrsInstallCsInitialize:"
  324. //
  325. // Initialize the command servers
  326. //
  327. CfgRegReadDWord(FKC_MAX_INSTALLCS_THREADS, NULL, 0, &MaxInstallCsThreads);
  328. FrsInitializeCommandServer(&InstallCs, MaxInstallCsThreads, L"InstallCs", MainInstallCs);
  329. }
  330. VOID
  331. ShutDownInstallCs(
  332. VOID
  333. )
  334. /*++
  335. Routine Description:
  336. Shutdown the staging file installer command server.
  337. Arguments:
  338. None.
  339. Return Value:
  340. None.
  341. --*/
  342. {
  343. #undef DEBSUB
  344. #define DEBSUB "ShutDownInstallCs:"
  345. FrsRunDownCommandServer(&InstallCs, &InstallCs.Queue);
  346. }
  347. VOID
  348. FrsInstallCsSubmitTransfer(
  349. IN PCOMMAND_PACKET Cmd,
  350. IN USHORT Command
  351. )
  352. /*++
  353. Routine Description:
  354. Transfer a request to the staging file generator
  355. Arguments:
  356. Cmd
  357. Return Value:
  358. None.
  359. --*/
  360. {
  361. #undef DEBSUB
  362. #define DEBSUB "FrsInstallCsSubmitTransfer:"
  363. //
  364. // Submit a request to allocate staging area
  365. //
  366. Cmd->TargetQueue = &InstallCs.Queue;
  367. Cmd->Command = Command;
  368. RsTimeout(Cmd) = 0;
  369. DPRINT1(5, "Install: submit %x\n", Cmd);
  370. FrsSubmitCommandServer(&InstallCs, Cmd);
  371. }