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.

10879 lines
323 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. replica.c
  5. Abstract:
  6. Replica Control Command Server (Replica).
  7. The Ds Poller periodically pulls the configuration from the DS,
  8. checks it for consistency, and then merges it with the current
  9. local configuration. The Ds Poller then makes copies of each
  10. replica for this machine and sends the copy to this replica
  11. control command server.
  12. Author:
  13. Billy J. Fuller 23-May-1997
  14. Revised:
  15. David A. Orbits 24-Jan-1998, added locking and interfaced with INLOG.
  16. Restructured Connection JOIN sequence.
  17. Jul-1999 Registry code rewrite
  18. Environment
  19. User mode winnt
  20. --*/
  21. #include <ntreppch.h>
  22. #pragma hdrstop
  23. #include <frs.h>
  24. #include <ntdsapi.h>
  25. #include <tablefcn.h>
  26. #include <ntfrsapi.h>
  27. #include <perrepsr.h>
  28. //
  29. // Connection flags.
  30. //
  31. FLAG_NAME_TABLE CxtionFlagNameTable[] = {
  32. {CXTION_FLAGS_CONSISTENT , "Consistent " },
  33. {CXTION_FLAGS_SCHEDULE_OFF , "SchedOff " },
  34. {CXTION_FLAGS_VOLATILE , "Volatile " },
  35. {CXTION_FLAGS_DEFERRED_JOIN , "DeferredJoin " },
  36. {CXTION_FLAGS_DEFERRED_UNJOIN , "DeferUnjoin " },
  37. {CXTION_FLAGS_TIMEOUT_SET , "TimeOutSet " },
  38. {CXTION_FLAGS_JOIN_GUID_VALID , "JoinGuidValid " },
  39. {CXTION_FLAGS_UNJOIN_GUID_VALID , "UnJoinGuidValid "},
  40. {CXTION_FLAGS_PERFORM_VVJOIN , "PerformVVJoin" },
  41. {CXTION_FLAGS_DEFERRED_DELETE , "DeferredDel " },
  42. {CXTION_FLAGS_PAUSED , "Paused " },
  43. {CXTION_FLAGS_HUNG_INIT_SYNC , "HungInitSync " },
  44. {CXTION_FLAGS_INIT_SYNC , "InitSync " },
  45. {CXTION_FLAGS_TRIGGER_SCHEDULE , "TriggerSched " },
  46. {0, NULL}
  47. };
  48. //
  49. // Directory and file filter lists from registry.
  50. //
  51. extern PWCHAR RegistryFileExclFilterList;
  52. extern PWCHAR RegistryDirExclFilterList;
  53. extern ULONGLONG ActiveChange;
  54. BOOL CurrentSysvolReadyIsValid;
  55. DWORD CurrentSysvolReady;
  56. //
  57. // Replica tombstone in days
  58. //
  59. DWORD ReplicaTombstone;
  60. ULONGLONG ReplicaTombstoneInFileTime;
  61. //
  62. // Retry a join every MinJoinRetry milliseconds, increasing by
  63. // MinJoinRetry every retry (but no longer than MaxJoinRetry).
  64. //
  65. #define JOIN_RETRY_EVENT (5) // record event every 5 join retries
  66. LONG MinJoinRetry;
  67. LONG MaxJoinRetry;
  68. extern DWORD CommTimeoutInMilliSeconds;
  69. //
  70. // Start replication even if the DS could not be accessed
  71. //
  72. DWORD ReplicaStartTimeout;
  73. //
  74. // Struct for the Replica Control Command Server
  75. // Contains info about the queues and the threads
  76. //
  77. COMMAND_SERVER ReplicaCmdServer;
  78. //
  79. // Table of active replicas
  80. //
  81. PGEN_TABLE ReplicasByGuid;
  82. PGEN_TABLE ReplicasByNumber;
  83. //
  84. // Table of deleted replicas discovered at startup. These replicas
  85. // never make it into the active tables, ever.
  86. //
  87. PGEN_TABLE DeletedReplicas;
  88. //
  89. // Table of cxtions deleted during runtime. They are eventually
  90. // freed at shutdown.
  91. //
  92. PGEN_TABLE DeletedCxtions;
  93. PGEN_TABLE ReplicasNotInTheDs;
  94. #define MINUTES_IN_INTERVAL (15)
  95. #define CMD_DELETE_RETRY_SHORT_TIMEOUT (10 * 1000)
  96. #define CMD_DELETE_RETRY_LONG_TIMEOUT (60 * 1000)
  97. //
  98. // Partners are not allowed to join if their clocks are out-of-sync
  99. //
  100. ULONGLONG MaxPartnerClockSkew;
  101. DWORD PartnerClockSkew;
  102. #define ReplicaCmdSetInitialTimeOut(_Cmd_, _Init_) \
  103. if (RsTimeout(Cmd) == 0) { \
  104. RsTimeout(Cmd) = (_Init_); \
  105. }
  106. #define SET_JOINED(_Replica_, _Cxtion_, _S_) \
  107. { \
  108. SetCxtionState(_Cxtion_, CxtionStateJoined); \
  109. PM_INC_CTR_REPSET((_Replica_), Joins, 1); \
  110. PM_INC_CTR_CXTION((_Cxtion_), Joins, 1); \
  111. \
  112. DPRINT3(0, ":X: ***** %s CxtG %08x "FORMAT_CXTION_PATH2"\n", \
  113. _S_, \
  114. ((_Cxtion_) != NULL) ? ((PCXTION)(_Cxtion_))->Name->Guid->Data1 : 0,\
  115. PRINT_CXTION_PATH2(_Replica_, _Cxtion_)); \
  116. if (_Cxtion_->JoinCmd && \
  117. (LONG)RsTimeout(_Cxtion_->JoinCmd) > (JOIN_RETRY_EVENT * MinJoinRetry)) { \
  118. if (_Cxtion_->Inbound) { \
  119. EPRINT3(EVENT_FRS_LONG_JOIN_DONE, \
  120. _Cxtion_->Partner->Name, ComputerName, _Replica_->Root); \
  121. } else { \
  122. EPRINT3(EVENT_FRS_LONG_JOIN_DONE, \
  123. ComputerName, _Cxtion_->Partner->Name, _Replica_->Root); \
  124. } \
  125. } \
  126. }
  127. //
  128. // Unidle the change order process queue if it is blocked.
  129. //
  130. #define UNIDLE_CO_PROCESS_QUEUE(_Replica_, _Cxtion_, _CoProcessQueue_) \
  131. { \
  132. if (_CoProcessQueue_ != NULL) { \
  133. CXTION_STATE_TRACE(3, _Cxtion_, _Replica_, 0, "CO Process Q Unblock"); \
  134. FrsRtlUnIdledQueue(_CoProcessQueue_); \
  135. _CoProcessQueue_ = NULL; \
  136. } \
  137. }
  138. //
  139. // UNJOIN TRIGGER
  140. //
  141. // Trigger an unjoin after N co's on *ONE* cxtion *ONE* time.
  142. //
  143. #if DBG
  144. #define PULL_UNJOIN_TRIGGER(_Cxtion_, _Cmd_) \
  145. { \
  146. if (_Cxtion_->UnjoinTrigger && (--_Cxtion_->UnjoinTrigger == 0)) { \
  147. DPRINT1(0, ":X: UNJOIN TRIGGER FIRED FOR %ws\n", _Cxtion_->Name->Name); \
  148. FrsCompleteCommand(_Cmd_, ERROR_OPERATION_ABORTED); \
  149. return; \
  150. } \
  151. }
  152. #define SET_UNJOIN_TRIGGER(_Cxtion_) \
  153. { \
  154. if (DebugInfo.UnjoinTrigger) { \
  155. _Cxtion_->UnjoinReset = DebugInfo.UnjoinTrigger; \
  156. DebugInfo.UnjoinTrigger = 0; \
  157. } \
  158. _Cxtion_->UnjoinTrigger = _Cxtion_->UnjoinReset; \
  159. _Cxtion_->UnjoinReset <<= 1; \
  160. _Cxtion_->UnjoinReset = 0; \
  161. }
  162. #else DBG
  163. #define SET_UNJOIN_TRIGGER(_Cxtion_)
  164. #define PULL_UNJOIN_TRIGGER(_Cxtion_, _Cmd_)
  165. #endif DBG
  166. //
  167. // Flags for RcsCheckCmd.
  168. //
  169. #define CHECK_CMD_PARTNERCOC (0x00000001)
  170. #define CHECK_CMD_REPLICA (0x00000002)
  171. #define CHECK_CMD_CXTION (0x00000004)
  172. #define CHECK_CMD_JOINGUID (0x00000008)
  173. #define CHECK_CMD_COE (0x00000010)
  174. #define CHECK_CMD_COGUID (0x00000020)
  175. #define CHECK_CMD_NOT_EXPIRED (0x00000040)
  176. #define CHECK_CMD_JOINTIME (0x00000080)
  177. #define CHECK_CMD_REPLICA_VERSION_GUID (0x00000100)
  178. #define CHECK_CMD_CXTION_OK (CHECK_CMD_REPLICA | \
  179. CHECK_CMD_CXTION)
  180. #define CHECK_CMD_CXTION_AND_COGUID_OK (CHECK_CMD_CXTION_OK | \
  181. CHECK_CMD_COGUID)
  182. #define CHECK_CMD_CXTION_AND_JOINGUID_OK (CHECK_CMD_CXTION_OK | \
  183. CHECK_CMD_JOINGUID)
  184. //
  185. // Flags for RcsCheckCxtion
  186. //
  187. #define CHECK_CXTION_EXISTS (0x00000001)
  188. #define CHECK_CXTION_INBOUND (0x00000002)
  189. #define CHECK_CXTION_OUTBOUND (0x00000004)
  190. #define CHECK_CXTION_JRNLCXTION (0x00000008)
  191. #define CHECK_CXTION_JOINGUID (0x00000010)
  192. #define CHECK_CXTION_JOINED (0x00000020)
  193. #define CHECK_CXTION_VVECTOR (0x00000040)
  194. #define CHECK_CXTION_PARTNER (0x00000080)
  195. #define CHECK_CXTION_AUTH (0x00000100)
  196. #define CHECK_CXTION_FIXJOINED (0x00000200)
  197. #define CHECK_CXTION_UNJOINGUID (0x00000400)
  198. #define CHECK_CXTION_JOIN_OK (CHECK_CXTION_EXISTS | \
  199. CHECK_CXTION_JOINED | \
  200. CHECK_CXTION_JOINGUID )
  201. VOID
  202. ChgOrdStartJoinRequest(
  203. IN PREPLICA Replica,
  204. IN PCXTION Cxtion
  205. );
  206. ULONG
  207. OutLogRetireCo(
  208. PREPLICA Replica,
  209. ULONG COx,
  210. PCXTION PartnerCxtion
  211. );
  212. ULONG
  213. OutLogInitPartner(
  214. PREPLICA Replica,
  215. PCXTION PartnerInfo
  216. );
  217. ULONG
  218. RcsForceUnjoin(
  219. IN PREPLICA Replica,
  220. IN PCXTION Cxtion
  221. );
  222. VOID
  223. RcsCreatePerfmonCxtionName(
  224. PREPLICA Replica,
  225. PCXTION Cxtion
  226. );
  227. DWORD
  228. SndCsAssignCommQueue(
  229. VOID
  230. );
  231. VOID
  232. SndCsCreateCxtion(
  233. IN OUT PCXTION Cxtion
  234. );
  235. VOID
  236. SndCsDestroyCxtion(
  237. IN PCXTION Cxtion,
  238. IN DWORD CxtionFlags
  239. );
  240. VOID
  241. SndCsSubmitCommPkt(
  242. IN PREPLICA Replica,
  243. IN PCXTION Cxtion,
  244. IN PCHANGE_ORDER_ENTRY Coe,
  245. IN GUID *JoinGuid,
  246. IN BOOL SetTimeout,
  247. IN PCOMM_PACKET CommPkt,
  248. IN DWORD CommQueueIndex
  249. );
  250. VOID
  251. SndCsSubmitCommPkt2(
  252. IN PREPLICA Replica,
  253. IN PCXTION Cxtion,
  254. IN PCHANGE_ORDER_ENTRY Coe,
  255. IN BOOL SetTimeout,
  256. IN PCOMM_PACKET CommPkt
  257. );
  258. VOID
  259. SndCsSubmitCmd(
  260. IN PREPLICA Replica,
  261. IN PCXTION Cxtion,
  262. IN PCOMMAND_SERVER FlushCs,
  263. IN PCOMMAND_PACKET FlushCmd,
  264. IN DWORD CommQueueIndex
  265. );
  266. VOID
  267. ChgOrdInjectControlCo(
  268. IN PREPLICA Replica,
  269. IN PCXTION Cxtion,
  270. IN ULONG ContentCmd
  271. );
  272. VOID
  273. RcsUpdateReplicaSetMember(
  274. IN PREPLICA Replica
  275. );
  276. VOID
  277. RcsReplicaSetRegistry(
  278. IN PREPLICA Replica
  279. );
  280. VOID
  281. CfgFilesNotToBackup(
  282. IN PGEN_TABLE Replicas
  283. );
  284. DWORD
  285. NtFrsApi_Rpc_BindEx(
  286. IN PWCHAR MachineName,
  287. OUT PWCHAR *OutPrincName,
  288. OUT handle_t *OutHandle,
  289. OUT ULONG *OutParentAuthLevel
  290. );
  291. PWCHAR
  292. FrsDsConvertName(
  293. IN HANDLE Handle,
  294. IN PWCHAR InputName,
  295. IN DWORD InputFormat,
  296. IN PWCHAR DomainDnsName,
  297. IN DWORD DesiredFormat
  298. );
  299. DWORD
  300. UtilRpcServerHandleToAuthSidString(
  301. IN handle_t ServerHandle,
  302. IN PWCHAR AuthClient,
  303. OUT PWCHAR *ClientSid
  304. );
  305. VOID
  306. RcsCloseReplicaSetmember(
  307. IN PREPLICA Replica
  308. );
  309. VOID
  310. RcsCloseReplicaCxtions(
  311. IN PREPLICA Replica
  312. );
  313. ULONG
  314. DbsProcessReplicaFaultList(
  315. PDWORD pReplicaSetsDeleted
  316. );
  317. ULONG
  318. DbsCheckForOverlapErrors(
  319. IN PREPLICA Replica
  320. );
  321. PCOMMAND_PACKET
  322. CommPktToCmd(
  323. IN PCOMM_PACKET CommPkt
  324. );
  325. PCOMM_PACKET
  326. CommBuildCommPkt(
  327. IN PREPLICA Replica,
  328. IN PCXTION Cxtion,
  329. IN ULONG Command,
  330. IN PGEN_TABLE VVector,
  331. IN PCOMMAND_PACKET Cmd,
  332. IN PCHANGE_ORDER_COMMAND Coc
  333. );
  334. BOOL
  335. RcsAreAuthNamesEqual(
  336. IN PWCHAR AuthName1,
  337. IN PWCHAR AuthName2
  338. )
  339. /*++
  340. Routine Description:
  341. Are the two auth names equal?
  342. The principle name comes from an rpc server handle or
  343. from DsCrackName(NT4 ACCOUNT NAME). The formats are
  344. slightly different so this isn't a simple wcsicmp().
  345. The principle name from the server handle has the format
  346. DNS-Domain-Name\ComputerName$.
  347. The principle name from DsCrackName has the format
  348. NetBIOS-Domain-Name\ComputerName$.
  349. The principle name from RpcMgmtInqServerPrincName() has the format
  350. ComputerName$@DNS-Domain-Name
  351. The names may be stringized sids.
  352. Arguments:
  353. AuthName1 - from rpc server handle or DsCrackName()
  354. AuthName2 - from rpc server handle or DsCrackName()
  355. Return Value:
  356. TRUE - the princnames are effectively equal
  357. FALSE - not
  358. --*/
  359. {
  360. #undef DEBSUB
  361. #define DEBSUB "RcsAreAuthNamesEqual:"
  362. BOOL AreEqual = FALSE;
  363. PWCHAR c;
  364. PWCHAR Sam1Begin;
  365. PWCHAR Sam2Begin;
  366. PWCHAR Sam1End;
  367. PWCHAR Sam2End;
  368. PWCHAR Dom1Begin;
  369. PWCHAR Dom2Begin;
  370. PWCHAR Dom1End;
  371. PWCHAR Dom2End;
  372. //
  373. // NULL Param
  374. //
  375. if (!AuthName1 || !AuthName2) {
  376. if (!AuthName1 && !AuthName2) {
  377. AreEqual = TRUE;
  378. goto CLEANUP;
  379. }
  380. goto CLEANUP;
  381. }
  382. //
  383. // principal names are usually in the format domain\samaccount
  384. // or stringized SID
  385. //
  386. if (WSTR_EQ(AuthName1, AuthName2)) {
  387. AreEqual = TRUE;
  388. goto CLEANUP;
  389. }
  390. //
  391. // Find the sam account name and the domain name
  392. //
  393. for (c = AuthName1; *c && *c != L'\\' && *c != L'@'; ++c);
  394. if (*c) {
  395. //
  396. // domain\samaccount
  397. //
  398. if (*c == L'\\') {
  399. Dom1Begin = AuthName1;
  400. Dom1End = c;
  401. Sam1Begin = c + 1;
  402. Sam1End = &AuthName1[wcslen(AuthName1)];
  403. }
  404. //
  405. // samaccount@dnsdomain
  406. //
  407. else {
  408. Sam1Begin = AuthName1;
  409. Sam1End = c;
  410. Dom1Begin = c + 1;
  411. for (; *c && *c != L'.'; ++c);
  412. Dom1End = c;
  413. }
  414. }
  415. //
  416. // Unknown format
  417. //
  418. else {
  419. goto CLEANUP;
  420. }
  421. for (c = AuthName2; *c && *c != L'\\' && *c != L'@'; ++c);
  422. if (*c) {
  423. //
  424. // domain\samaccount
  425. //
  426. if (*c == L'\\') {
  427. Dom2Begin = AuthName2;
  428. Dom2End = c;
  429. Sam2Begin = c + 1;
  430. Sam2End = &AuthName2[wcslen(AuthName2)];
  431. }
  432. //
  433. // samaccount@dnsdomain
  434. //
  435. else {
  436. Sam2Begin = AuthName2;
  437. Sam2End = c;
  438. Dom2Begin = c + 1;
  439. for (; *c && *c != L'.'; ++c);
  440. Dom2End = c;
  441. }
  442. }
  443. //
  444. // Unknown format
  445. //
  446. else {
  447. goto CLEANUP;
  448. }
  449. //
  450. // Compare samaccount
  451. //
  452. while (Sam1Begin != Sam1End && Sam2Begin != Sam2End) {
  453. if (towlower(*Sam1Begin) != towlower(*Sam2Begin)) {
  454. goto CLEANUP;
  455. }
  456. ++Sam1Begin;
  457. ++Sam2Begin;
  458. }
  459. //
  460. // compare domain
  461. //
  462. while (Dom1Begin != Dom1End && Dom2Begin != Dom2End) {
  463. if (towlower(*Dom1Begin) != towlower(*Dom2Begin)) {
  464. goto CLEANUP;
  465. }
  466. ++Dom1Begin;
  467. ++Dom2Begin;
  468. }
  469. AreEqual = (Sam1Begin == Sam1End &&
  470. Sam2Begin == Sam2End &&
  471. Dom1Begin == Dom1End &&
  472. Dom2Begin == Dom2End);
  473. CLEANUP:
  474. DPRINT3(4, "Auth names %ws %s %ws\n",
  475. AuthName1, (AreEqual) ? "==" : "!=", AuthName2);
  476. return AreEqual;
  477. }
  478. PREPLICA
  479. RcsFindReplicaByNumber(
  480. IN ULONG ReplicaNumber
  481. )
  482. /*++
  483. Routine Description:
  484. Find the replica by internal number
  485. Arguments:
  486. ReplicaNumber
  487. Return Value:
  488. Address of the replica or NULL.
  489. --*/
  490. {
  491. #undef DEBSUB
  492. #define DEBSUB "RcsFindReplicaByNumber:"
  493. //
  494. // Find the replica by internal replica number (used in the Jet Table names)
  495. //
  496. return GTabLookup(ReplicasByNumber, &ReplicaNumber, NULL);
  497. }
  498. PREPLICA
  499. RcsFindReplicaByGuid(
  500. IN GUID *Guid
  501. )
  502. /*++
  503. Routine Description:
  504. Find a replica by Guid
  505. Arguments:
  506. Guid - Replica->ReplicaName->Guid
  507. Return Value:
  508. Address of the replica or NULL.
  509. --*/
  510. {
  511. #undef DEBSUB
  512. #define DEBSUB "RcsFindReplicaByGuid:"
  513. //
  514. // Find the replica by guid
  515. //
  516. return GTabLookup(ReplicasByGuid, Guid, NULL);
  517. }
  518. PREPLICA
  519. RcsFindReplicaById(
  520. IN ULONG Id
  521. )
  522. /*++
  523. Routine Description:
  524. Find a replica given the internal ID.
  525. Arguments:
  526. Id - Internal Replica ID.
  527. Return Value:
  528. Address of the replica or NULL.
  529. --*/
  530. {
  531. #undef DEBSUB
  532. #define DEBSUB "RcsFindReplicaById:"
  533. PREPLICA RetVal = NULL;
  534. ForEachListEntry( &ReplicaListHead, REPLICA, ReplicaList,
  535. if (pE->ReplicaNumber == Id) {
  536. RetVal = pE;
  537. break;
  538. }
  539. );
  540. return RetVal;
  541. }
  542. BOOL
  543. RcsCheckCmd(
  544. IN PCOMMAND_PACKET Cmd,
  545. IN PCHAR Debsub,
  546. IN ULONG Flags
  547. )
  548. /*++
  549. Routine Description:
  550. Check the command packet for the specified fields.
  551. Arguments:
  552. Cmd
  553. Hdr
  554. Flags
  555. Return Value:
  556. TRUE - packet is ok
  557. FALSE - not
  558. --*/
  559. {
  560. #undef DEBSUB
  561. #define DEBSUB "RcsCheckCmd:"
  562. BOOL Ret = TRUE;
  563. PREPLICA Replica = RsReplica(Cmd);
  564. CHAR Tstr1[128];
  565. //
  566. // Replica
  567. //
  568. if ((Flags & CHECK_CMD_REPLICA) && !RsReplica(Cmd)) {
  569. DPRINT(0, "WARN - No replica in command packet\n");
  570. FrsCompleteCommand(Cmd, ERROR_INVALID_PARAMETER);
  571. return FALSE;
  572. }
  573. //
  574. // Partner change order command
  575. //
  576. if ((Flags & CHECK_CMD_PARTNERCOC) && !RsPartnerCoc(Cmd)) {
  577. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_PARTNERCOC failed", Debsub);
  578. Ret = FALSE;
  579. }
  580. //
  581. // Replica has been (or may be) deleted
  582. //
  583. if ((Flags & CHECK_CMD_NOT_EXPIRED) &&
  584. !IS_TIME_ZERO(RsReplica(Cmd)->MembershipExpires)) {
  585. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_NOT_EXPIRED failed", Debsub);
  586. Ret = FALSE;
  587. }
  588. //
  589. // Cxtion
  590. //
  591. if ((Flags & CHECK_CMD_CXTION) &&
  592. !(RsCxtion(Cmd) && RsCxtion(Cmd)->Guid)) {
  593. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_CXTION failed", Debsub);
  594. Ret = FALSE;
  595. }
  596. //
  597. // Join guid
  598. //
  599. if ((Flags & CHECK_CMD_JOINGUID) && !RsJoinGuid(Cmd)) {
  600. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_JOINGUID failed", Debsub);
  601. Ret = FALSE;
  602. }
  603. //
  604. // Replica Version Guid
  605. //
  606. if ((Flags & CHECK_CMD_REPLICA_VERSION_GUID) &&
  607. !RsReplicaVersionGuid(Cmd)) {
  608. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_REPLICA_VERSION_GUID failed", Debsub);
  609. Ret = FALSE;
  610. }
  611. //
  612. // Change order entry
  613. //
  614. if ((Flags & CHECK_CMD_COE) && !RsCoe(Cmd)) {
  615. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_COE failed", Debsub);
  616. Ret = FALSE;
  617. }
  618. //
  619. // Change order guid
  620. //
  621. if ((Flags & CHECK_CMD_COGUID) && !RsCoGuid(Cmd)) {
  622. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_COGUID failed", Debsub);
  623. Ret = FALSE;
  624. }
  625. //
  626. // Join time
  627. //
  628. if ((Flags & CHECK_CMD_JOINTIME) && !RsJoinTime(Cmd)) {
  629. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_JOINTIME failed", Debsub);
  630. Ret = FALSE;
  631. }
  632. if (!Ret) {
  633. Tstr1[sizeof(Tstr1)-1] = '\0';
  634. REPLICA_STATE_TRACE(3, Cmd, Replica, ERROR_INVALID_PARAMETER, Tstr1);
  635. FrsCompleteCommand(Cmd, ERROR_INVALID_PARAMETER);
  636. }
  637. return Ret;
  638. }
  639. ULONG
  640. RcsCheckCxtionCommon(
  641. IN PCOMMAND_PACKET Cmd,
  642. IN PCXTION Cxtion,
  643. IN PCHAR Debsub,
  644. IN ULONG Flags,
  645. OUT PFRS_QUEUE *CoProcessQueue
  646. )
  647. /*++
  648. Routine Description:
  649. find the in/outbound cxtion referenced by a command received
  650. from a remote machine.
  651. The caller should have used RcsCheckCmd() with
  652. CHECK_CMD_REPLICA
  653. CHECK_CMD_CXTION
  654. CHECK_CMD_JOINGUID (if CHECK_CXTION_JOINGUID)
  655. before calling this function.
  656. Arguments:
  657. Cmd -- Command packet
  658. Cxtion -- connection struct to be checked.
  659. Debsub
  660. Flags
  661. CoProcessQueue -- return the pointer to the process queue to unidle.
  662. Return Value:
  663. Error status code.
  664. --*/
  665. {
  666. #undef DEBSUB
  667. #define DEBSUB "RcsCheckCxtionCommon:"
  668. PREPLICA Replica = RsReplica(Cmd);
  669. //
  670. // Cxtion exists
  671. //
  672. if ((Flags & CHECK_CXTION_EXISTS) &&
  673. ((Cxtion == NULL) ||
  674. CxtionStateIs(Cxtion, CxtionStateInit))) {
  675. DPRINT2(1, "++ WARN - %s no cxtion for %08x\n", Debsub, Cmd);
  676. return ERROR_INVALID_PARAMETER;
  677. }
  678. //
  679. // Not much purpose in continuing
  680. //
  681. if (!Cxtion) {
  682. return ERROR_INVALID_PARAMETER;
  683. }
  684. //
  685. // Inbound cxtion
  686. //
  687. if ((Flags & CHECK_CXTION_INBOUND) && !Cxtion->Inbound) {
  688. DPRINT2(1, "++ WARN - %s cxtion is not inbound for %08x\n", Debsub, Cmd);
  689. //
  690. // Change order accept better not be waiting for this cxtion.
  691. //
  692. FRS_ASSERT(Cxtion->CoProcessQueue == NULL);
  693. return ERROR_INVALID_PARAMETER;
  694. }
  695. //
  696. // Outbound cxtion
  697. //
  698. if ((Flags & CHECK_CXTION_OUTBOUND) && Cxtion->Inbound) {
  699. DPRINT2(1, "++ WARN - %s cxtion is not outbound for %08x\n", Debsub, Cmd);
  700. return ERROR_INVALID_PARAMETER;
  701. }
  702. //
  703. // Jrnl cxtion
  704. //
  705. if ((Flags & CHECK_CXTION_JRNLCXTION) && !Cxtion->JrnlCxtion) {
  706. DPRINT2(1, "++ WARN - %s cxtion is not jrnlcxtion for %08x\n", Debsub, Cmd);
  707. return ERROR_INVALID_PARAMETER;
  708. }
  709. //
  710. // Version vector
  711. //
  712. if ((Flags & CHECK_CXTION_VVECTOR) && !Cxtion->VVector) {
  713. DPRINT2(1, "++ WARN - %s no version vector for %08x\n", Debsub, Cmd);
  714. return ERROR_INVALID_PARAMETER;
  715. }
  716. //
  717. // Authenticate Partner
  718. //
  719. if ((Flags & CHECK_CXTION_PARTNER)) {
  720. //
  721. // Increment the Authentications counter for
  722. // both the replica set and connection objects
  723. //
  724. PM_INC_CTR_CXTION(Cxtion, Authentications, 1);
  725. PM_INC_CTR_REPSET(Replica, Authentications, 1);
  726. if (
  727. #if DBG
  728. //
  729. // We don't enable authentication when emulating machines
  730. //
  731. !ServerGuid &&
  732. #endif DBG
  733. (Cxtion->PartnerAuthLevel == CXTION_AUTH_KERBEROS_FULL) &&
  734. RunningAsAService &&
  735. (!RcsAreAuthNamesEqual(Cxtion->PartnerSid, RsAuthSid(Cmd)) &&
  736. !RcsAreAuthNamesEqual(Cxtion->PartnerPrincName, RsAuthClient(Cmd)))) {
  737. DPRINT4(1, "++ WARN - %s %08x: PrincName %ws != %ws\n",
  738. Debsub, Cmd, RsAuthClient(Cmd), Cxtion->PartnerPrincName);
  739. DPRINT4(1, "++ WARN - %s %08x: AuthSid %ws != %ws\n",
  740. Debsub, Cmd, RsAuthSid(Cmd), Cxtion->PartnerSid);
  741. return ERROR_INVALID_PARAMETER;
  742. } else {
  743. //
  744. // Increment the Authentications in error counter for
  745. // both the replica set and connection objects
  746. //
  747. PM_INC_CTR_CXTION(Cxtion, AuthenticationsError, 1);
  748. PM_INC_CTR_REPSET(Replica, AuthenticationsError, 1);
  749. }
  750. }
  751. //
  752. // Authentication info
  753. //
  754. if ((Flags & CHECK_CXTION_AUTH)) {
  755. //
  756. // Increment the Authentications counter for
  757. // both the replica set and connection objects
  758. //
  759. PM_INC_CTR_CXTION(Cxtion, Authentications, 1);
  760. PM_INC_CTR_REPSET(Replica, Authentications, 1);
  761. if (
  762. #if DBG
  763. //
  764. // We don't enable authentication when emulating machines
  765. //
  766. !ServerGuid &&
  767. #endif DBG
  768. (Cxtion->PartnerAuthLevel == CXTION_AUTH_KERBEROS_FULL) &&
  769. (RsAuthLevel(Cmd) != RPC_C_AUTHN_LEVEL_PKT_PRIVACY ||
  770. (RsAuthN(Cmd) != RPC_C_AUTHN_GSS_KERBEROS &&
  771. RsAuthN(Cmd) != RPC_C_AUTHN_GSS_NEGOTIATE))) {
  772. DPRINT2(1, "++ WARN - %s bad authentication for %08x\n", Debsub, Cmd);
  773. return ERROR_INVALID_PARAMETER;
  774. } else {
  775. //
  776. // Increment the Authentications in error counter for
  777. // both the replica set and connection objects
  778. //
  779. PM_INC_CTR_CXTION(Cxtion, AuthenticationsError, 1);
  780. PM_INC_CTR_REPSET(Replica, AuthenticationsError, 1);
  781. }
  782. }
  783. //
  784. // Fix Join
  785. //
  786. // We may receive change orders after a successful join but
  787. // before we receive the JOINED packet from our inbound
  788. // partner. Fix the JOINED flag if so.
  789. //
  790. if ((Flags & CHECK_CXTION_FIXJOINED) &&
  791. CxtionStateIs(Cxtion, CxtionStateWaitJoin) &&
  792. RsJoinGuid(Cmd) &&
  793. Replica &&
  794. GUIDS_EQUAL(&Cxtion->JoinGuid, RsJoinGuid(Cmd)) &&
  795. CxtionFlagIs(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID)) {
  796. SET_JOINED(Replica, Cxtion, "OOJOINED");
  797. //
  798. // Return the pointer to the process queue to the caller so that the caller
  799. // can unidle the queue after releasing the cxtion lock.
  800. // Never try to lock the process queue when you have the cxtion lock. It will
  801. // result in a deadlock.
  802. //
  803. *CoProcessQueue = Cxtion->CoProcessQueue;
  804. Cxtion->CoProcessQueue = NULL;
  805. SET_UNJOIN_TRIGGER(Cxtion);
  806. }
  807. //
  808. // Joined
  809. //
  810. if ((Flags & CHECK_CXTION_JOINED) &&
  811. !CxtionStateIs(Cxtion, CxtionStateJoined)) {
  812. DPRINT2(1, "++ WARN - %s cxtion is not joined for %08x\n", Debsub, Cmd);
  813. return ERROR_INVALID_PARAMETER;
  814. }
  815. //
  816. // Join guid
  817. //
  818. if ((Flags & CHECK_CXTION_JOINGUID) &&
  819. (!RsJoinGuid(Cmd) ||
  820. !GUIDS_EQUAL(&Cxtion->JoinGuid, RsJoinGuid(Cmd)) ||
  821. !CxtionFlagIs(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID))) {
  822. DPRINT2(1, "++ WARN - %s wrong join guid for %08x\n", Debsub, Cmd);
  823. return ERROR_INVALID_PARAMETER;
  824. }
  825. //
  826. // UnJoin guid
  827. //
  828. if ((Flags & CHECK_CXTION_UNJOINGUID) &&
  829. (!RsJoinGuid(Cmd) ||
  830. !GUIDS_EQUAL(&Cxtion->JoinGuid, RsJoinGuid(Cmd)) ||
  831. !CxtionFlagIs(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID))) {
  832. DPRINT2(1, "++ WARN - %s wrong unjoin guid for %08x\n", Debsub, Cmd);
  833. return ERROR_INVALID_PARAMETER;
  834. }
  835. return ERROR_SUCCESS;
  836. }
  837. PCXTION
  838. RcsCheckCxtion(
  839. IN PCOMMAND_PACKET Cmd,
  840. IN PCHAR Debsub,
  841. IN ULONG Flags
  842. )
  843. /*++
  844. Routine Description:
  845. find the in/outbound cxtion referenced by a command received
  846. from a remote machine.
  847. The caller should have used RcsCheckCmd() with
  848. CHECK_CMD_REPLICA
  849. CHECK_CMD_CXTION
  850. CHECK_CMD_JOINGUID (if CHECK_CXTION_JOINGUID)
  851. before calling this function.
  852. Complete the command with an error if a specified check fails.
  853. Arguments:
  854. Cmd
  855. Debsub
  856. Flags
  857. Return Value:
  858. Address of the cxtion or NULL.
  859. --*/
  860. {
  861. #undef DEBSUB
  862. #define DEBSUB "RcsCheckCxtion:"
  863. PCXTION Cxtion;
  864. PREPLICA Replica = RsReplica(Cmd);
  865. ULONG WStatus;
  866. CHAR Tstr1[64];
  867. PFRS_QUEUE CoProcessQueue = NULL;
  868. //
  869. // Lock the connection table to sync with INLOG and OUTLOG access.
  870. //
  871. LOCK_CXTION_TABLE(Replica);
  872. //
  873. // Find the cxtion and check it.
  874. //
  875. Cxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  876. WStatus = RcsCheckCxtionCommon(Cmd, Cxtion, Debsub, Flags, &CoProcessQueue);
  877. UNLOCK_CXTION_TABLE(Replica);
  878. //
  879. // If RcsCheckCxtionCommon wanted us to unidle the process queue then do it here
  880. // after releasing the cxtion lock.
  881. //
  882. UNIDLE_CO_PROCESS_QUEUE(Replica, Cxtion, CoProcessQueue);
  883. //
  884. // If check not successfull then complete the command with an error.
  885. //
  886. if (!WIN_SUCCESS(WStatus)) {
  887. //
  888. // The join command packet is being rejected; Clear the reference.
  889. //
  890. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CheckCxtion failed", Debsub);
  891. Tstr1[sizeof(Tstr1)-1] = '\0';
  892. REPLICA_STATE_TRACE(3, Cmd, Replica, WStatus, Tstr1);
  893. if (Cxtion && Cxtion->JoinCmd == Cmd) {
  894. Cxtion->JoinCmd = NULL;
  895. }
  896. FrsCompleteCommand(Cmd, WStatus);
  897. return NULL;
  898. }
  899. //
  900. // Check is successful. Return the Cxtion.
  901. //
  902. return Cxtion;
  903. }
  904. VOID
  905. RcsJoinCxtionLater(
  906. IN PREPLICA Replica,
  907. IN PCXTION Cxtion,
  908. IN PCOMMAND_PACKET Cmd
  909. )
  910. /*++
  911. Routine Description:
  912. Check on the join status of the cxtion occasionally. Restart the join
  913. process if needed. The cxtion contains the retry timeout.
  914. Cmd contains enough info to get back to the replica\cxtion.
  915. Arguments:
  916. Replica
  917. Cxtion
  918. Cmd
  919. Return Value:
  920. None.
  921. --*/
  922. {
  923. #undef DEBSUB
  924. #define DEBSUB "RcsJoinCxtionLater:"
  925. ULONG Timeout;
  926. //
  927. // There is already a join command packet in the works; done
  928. //
  929. if (Cxtion->JoinCmd) {
  930. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  931. return;
  932. }
  933. Cxtion->JoinCmd = Cmd;
  934. Cmd->Command = CMD_JOIN_CXTION;
  935. //
  936. // Stop retrying after a while, but not too long or too short.
  937. //
  938. RsTimeout(Cmd) += MinJoinRetry;
  939. if ((LONG)RsTimeout(Cmd) < MinJoinRetry) {
  940. RsTimeout(Cmd) = MinJoinRetry;
  941. }
  942. if ((LONG)RsTimeout(Cmd) > MaxJoinRetry) {
  943. RsTimeout(Cmd) = MaxJoinRetry;
  944. }
  945. //
  946. // Add in the penalty from failed rpc calls, but not too long or too short.
  947. //
  948. Timeout = RsTimeout(Cmd) + Cxtion->Penalty;
  949. if ((LONG)Timeout < MinJoinRetry) {
  950. Timeout = MinJoinRetry;
  951. }
  952. if ((LONG)Timeout > MaxJoinRetry) {
  953. Timeout = MaxJoinRetry;
  954. }
  955. //
  956. // Inform the user that the join is taking a long time.
  957. // The user receives no notification if a join occurs in
  958. // a short time.
  959. //
  960. // A trigger scheduled cxtion will stop retrying once the
  961. // trigger interval goes off (usually in 15 minutes).
  962. //
  963. if (!(RsTimeout(Cmd) % (JOIN_RETRY_EVENT * MinJoinRetry))) {
  964. if (Cxtion->Inbound) {
  965. EPRINT4(EVENT_FRS_LONG_JOIN, Cxtion->Partner->Name, ComputerName,
  966. Replica->Root, Cxtion->PartnerDnsName);
  967. } else {
  968. EPRINT4(EVENT_FRS_LONG_JOIN, ComputerName, Cxtion->Partner->Name,
  969. Replica->Root, Cxtion->PartnerDnsName);
  970. }
  971. }
  972. //
  973. // This command will come back to us in a bit
  974. //
  975. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, Timeout);
  976. }
  977. VOID
  978. RcsJoinCxtion(
  979. IN PCOMMAND_PACKET Cmd
  980. )
  981. /*++
  982. Routine Description:
  983. Kick off the commands needed to join with our in/outbound partners.
  984. Joining an inbound partner is a two step process. First, we pass a
  985. command to the inbound log process to allow it to scan the inbound log
  986. for any change orders from this connection. These change orders are
  987. inserted on the CO process queue so we preserve ordering with new change
  988. orders that arrive after the Join completes. In addtion we extract the
  989. the sequence number and change order ID of the last change order we have
  990. pending from this inbound partner. Second, we send the join request to
  991. the inbound partner. This same path is taken whether this is a clean
  992. startup or a startup after a crash.
  993. JOINING:
  994. UNJOINED -> UNJOINED ask our partner if it is alive
  995. UNJOINED -> START our partner responded
  996. START -> STARTING call ChgOrdStartJoinRequest()
  997. STARTING -> SCANNING (when chgord starts inlog scan)
  998. SCANNING -> SENDJOIN (when chgord completes inlog scan)
  999. SENDJOIN -> WAITJOIN (when join sent to partner)
  1000. WAITJOIN -> JOINED (when partner responds)
  1001. UNJOINING
  1002. STARTING |
  1003. SCANNING |
  1004. SENDJOIN |
  1005. WAITJOIN -> UNJOINING (wait for remote change orders to retry)
  1006. UNJOINING -> UNJOINED (no more remote change orders)
  1007. UNJOINED -> DELETED (cxtion has been deleted)
  1008. Arguments:
  1009. Replica -- ptr to the Replica struct
  1010. Cxtion -- ptr to the connection struct we are talking to.
  1011. Return Value:
  1012. True if if ReJoin is needed.
  1013. --*/
  1014. {
  1015. #undef DEBSUB
  1016. #define DEBSUB "RcsJoinCxtion:"
  1017. PREPLICA Replica;
  1018. PCXTION Cxtion;
  1019. PCOMM_PACKET CPkt;
  1020. ULONG CmdCode;
  1021. DWORD CQIndex;
  1022. //
  1023. // Check the command packet
  1024. //
  1025. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK)) {
  1026. return;
  1027. }
  1028. Replica = RsReplica(Cmd);
  1029. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsJoinCxtion entry1");
  1030. //
  1031. // Find and check the cxtion
  1032. //
  1033. Cxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS);
  1034. if (!Cxtion) {
  1035. return;
  1036. }
  1037. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, RcsJoinCxtion entry2");
  1038. //
  1039. // This is our periodic join command packet
  1040. // - clear the reference
  1041. // - Ignore if the cxtion has successfully joined;
  1042. // our partner will inform us if there is a state change.
  1043. // - ignore if the replica set is in seeding state and this
  1044. // connection has been paused by the initial sync command server.
  1045. //
  1046. if (Cxtion->JoinCmd == Cmd) {
  1047. Cxtion->JoinCmd = NULL;
  1048. if ((CxtionStateIs(Cxtion, CxtionStateJoined) &&
  1049. !CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN)) ||
  1050. (BooleanFlagOn(Replica->CnfFlags,CONFIG_FLAG_SEEDING) &&
  1051. CxtionFlagIs(Cxtion,CXTION_FLAGS_PAUSED))) {
  1052. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1053. return;
  1054. }
  1055. }
  1056. //
  1057. // Don't bother joining if the service is shutting down
  1058. //
  1059. if (FrsIsShuttingDown) {
  1060. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1061. return;
  1062. }
  1063. //
  1064. // Get lock to sync with change order accept
  1065. //
  1066. LOCK_CXTION_TABLE(Replica);
  1067. switch (GetCxtionState(Cxtion)) {
  1068. case CxtionStateInit:
  1069. //
  1070. // Not setup, yet. Ignore
  1071. //
  1072. DPRINT1(4, ":X: Cxtion isn't inited at join: "FORMAT_CXTION_PATH2"\n",
  1073. PRINT_CXTION_PATH2(Replica, Cxtion));
  1074. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1075. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1076. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1077. SetCxtionState(Cxtion, CxtionStateDeleted);
  1078. }
  1079. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1080. break;
  1081. case CxtionStateUnjoined:
  1082. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1083. //
  1084. // Cxtion is deleted; nevermind
  1085. //
  1086. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1087. SetCxtionState(Cxtion, CxtionStateDeleted);
  1088. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1089. break;
  1090. }
  1091. //
  1092. // Schedule is off; nevermind
  1093. //
  1094. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  1095. DPRINT1(4, ":X: Schedule is off at join: "FORMAT_CXTION_PATH2"\n",
  1096. PRINT_CXTION_PATH2(Replica, Cxtion));
  1097. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1098. break;
  1099. }
  1100. //
  1101. // Replica is deleted; nevermind
  1102. //
  1103. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  1104. DPRINT1(4, ":S: Replica deleted at join: "FORMAT_CXTION_PATH2"\n",
  1105. PRINT_CXTION_PATH2(Replica, Cxtion));
  1106. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1107. break;
  1108. }
  1109. //
  1110. // Send our join info to our inbound partner or request an outbound
  1111. // partner to start a join. Don't send anything if this is the
  1112. // journal cxtion.
  1113. //
  1114. // Do not join with a downstream partner if this replica is still
  1115. // seeding and is not online.
  1116. //
  1117. if (Cxtion->Inbound) {
  1118. if (Cxtion->JrnlCxtion) {
  1119. DPRINT1(4, "DO NOT Send CMD_START_JOIN to jrnl cxtion: "FORMAT_CXTION_PATH2"\n",
  1120. PRINT_CXTION_PATH2(Replica, Cxtion));
  1121. } else {
  1122. DPRINT1(4, ":X: Send CMD_NEED_JOIN to inbound: "FORMAT_CXTION_PATH2"\n",
  1123. PRINT_CXTION_PATH2(Replica, Cxtion));
  1124. }
  1125. } else {
  1126. if ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  1127. Replica->IsSeeding) &&
  1128. !BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  1129. DPRINT1(4, ":X: DO NOT Send CMD_START_JOIN until we are Online: "FORMAT_CXTION_PATH2"\n",
  1130. PRINT_CXTION_PATH2(Replica, Cxtion));
  1131. } else {
  1132. DPRINT1(4, ":X: Send CMD_START_JOIN to outbound: "FORMAT_CXTION_PATH2"\n",
  1133. PRINT_CXTION_PATH2(Replica, Cxtion));
  1134. }
  1135. }
  1136. //
  1137. // Journal cxtions transition from unjoined to joined w/o
  1138. // any intervening states UNLESS someone adds code at
  1139. // this point to activate the journal for this set. But
  1140. // that would require a rewrite of the journal startup
  1141. // subsystem. Which may happen...
  1142. //
  1143. if (Cxtion->JrnlCxtion) {
  1144. DPRINT1(0, ":X: ***** JOINED "FORMAT_CXTION_PATH2"\n",
  1145. PRINT_CXTION_PATH2(Replica, Cxtion));
  1146. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, JOINED");
  1147. SetCxtionState(Cxtion, CxtionStateJoined);
  1148. SndCsCreateCxtion(Cxtion);
  1149. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1150. break;
  1151. }
  1152. //
  1153. // Do not join with a downstream partner if this replica is still
  1154. // seeding and is not online. Do not send a join if this
  1155. // is a journal cxtion. Do not join if there is already an
  1156. // active join request outstanding.
  1157. //
  1158. // The SndCs and the ReplicaCs cooperate to limit the
  1159. // number of active join "pings" so that the Snd threads
  1160. // are not hung waiting for pings to dead servers to
  1161. // time out.
  1162. //
  1163. if (!Cxtion->ActiveJoinCommPkt &&
  1164. !Cxtion->JrnlCxtion &&
  1165. (Cxtion->Inbound ||
  1166. BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE) ||
  1167. (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  1168. !Replica->IsSeeding))) {
  1169. //
  1170. // Increment the Join Notifications sent counter for
  1171. // both the replica set and connection objects
  1172. //
  1173. PM_INC_CTR_CXTION(Cxtion, JoinNSent, 1);
  1174. PM_INC_CTR_REPSET(Replica, JoinNSent, 1);
  1175. //
  1176. // Assign a comm queue if none has been assigned. A cxtion
  1177. // must use the same comm queue for a given session (join guid)
  1178. // to maintain packet order. Old packets have an invalid join
  1179. // guid and are either not sent or ignored on the receiving side.
  1180. //
  1181. if (!Cxtion->CommQueueIndex) {
  1182. Cxtion->CommQueueIndex = SndCsAssignCommQueue();
  1183. }
  1184. //
  1185. // Partner is considered slow-to-respond if the last
  1186. // rpc calls are erroring off and their cumulative
  1187. // timeouts are greater than MinJoinRetry.
  1188. //
  1189. // BUT, Don't reassign the cxtion's queue index because,
  1190. // if this is an outbound cxtion, the flush-at-join
  1191. // logic needs to know the old queue index so that it
  1192. // flushes the correct queue.
  1193. //
  1194. CQIndex = Cxtion->CommQueueIndex;
  1195. if ((LONG)Cxtion->Penalty > MinJoinRetry) {
  1196. CQIndex = 0;
  1197. }
  1198. CmdCode = (Cxtion->Inbound) ? CMD_NEED_JOIN : CMD_START_JOIN;
  1199. CPkt = CommBuildCommPkt(Replica, Cxtion, CmdCode, NULL, NULL, NULL);
  1200. //
  1201. // The SndCs and the ReplicaCs cooperate to limit the
  1202. // number of active join "pings" so that the Snd threads
  1203. // are not hung waiting for pings to dead servers to
  1204. // time out.
  1205. //
  1206. Cxtion->ActiveJoinCommPkt = CPkt;
  1207. SndCsSubmitCommPkt(Replica, Cxtion, NULL, NULL, FALSE, CPkt, CQIndex);
  1208. }
  1209. //
  1210. // Keep trying an inbound cxtion but try the outbound connection
  1211. // only once. The outbound partner will keep trying the join and
  1212. // the connection will eventually join.
  1213. //
  1214. if (Cxtion->Inbound) {
  1215. RcsJoinCxtionLater(Replica, Cxtion, Cmd);
  1216. } else {
  1217. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1218. }
  1219. break;
  1220. case CxtionStateStart:
  1221. //
  1222. // Unjoined and our partner has responed; start the join
  1223. //
  1224. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1225. //
  1226. // Cxtion is deleted; nevermind
  1227. //
  1228. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1229. SetCxtionState(Cxtion, CxtionStateDeleted);
  1230. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1231. break;
  1232. }
  1233. //
  1234. // Schedule is off; nevermind
  1235. //
  1236. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  1237. DPRINT1(4, ":X: Schedule is off at join: "FORMAT_CXTION_PATH2"\n",
  1238. PRINT_CXTION_PATH2(Replica, Cxtion));
  1239. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1240. break;
  1241. }
  1242. //
  1243. // Replica is deleted; nevermind
  1244. //
  1245. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  1246. DPRINT1(4, ":X: Replica deleted at join: "FORMAT_CXTION_PATH2"\n",
  1247. PRINT_CXTION_PATH2(Replica, Cxtion));
  1248. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1249. break;
  1250. }
  1251. if (Cxtion->Inbound) {
  1252. //
  1253. // Tell the inbound log subsystem to initialize for a Join with
  1254. // an inbound partner. When it begins processing the request it
  1255. // sets the state to STARTING. When it completes it sets the
  1256. // state to SENDJOIN and sends a CMD_JOIN_CXTION command.
  1257. //
  1258. // We need our join guid at this time because the change
  1259. // orders are stamped with the join guid during change order
  1260. // accept. Mismatched joinguids result in a unjoin-with-
  1261. // retry call so that old change orders can drain out
  1262. // of change order accept and into the replica command
  1263. // server after a cxtion is unjoined and joined again.
  1264. //
  1265. SetCxtionState(Cxtion, CxtionStateStarting);
  1266. SndCsCreateCxtion(Cxtion);
  1267. //
  1268. // ** DEADLOCK WARNING **
  1269. // The connection table lock must be unlocked before the request is
  1270. // put on the change order process queue. This is because the
  1271. // change order accept thread locks the process queue while it is
  1272. // considering the issue state of the head entry. If the CO it is
  1273. // trying to issue is for a connection being restarted it will wait
  1274. // until the cxtion starts otherwise the subsequent fetch request by
  1275. // the CO would just fail. While change_order_accept has the queue
  1276. // lock it then acquires the cxtion table lock. Thus two threads
  1277. // are acquiring two locks in different orders causing deadlock.
  1278. //
  1279. UNLOCK_CXTION_TABLE(Replica);
  1280. ChgOrdStartJoinRequest(Replica, Cxtion);
  1281. LOCK_CXTION_TABLE(Replica);
  1282. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1283. }
  1284. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1285. break;
  1286. case CxtionStateStarting:
  1287. case CxtionStateScanning:
  1288. //
  1289. // Join in process; our inbound partner will be informed later
  1290. //
  1291. DPRINT1(4, ":X: Scanning at join: "FORMAT_CXTION_PATH2"\n",
  1292. PRINT_CXTION_PATH2(Replica, Cxtion));
  1293. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1294. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1295. break;
  1296. case CxtionStateSendJoin:
  1297. case CxtionStateWaitJoin:
  1298. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1299. //
  1300. // Replica is deleted,
  1301. // The cxtion needs to be unjoined, or
  1302. // The cxtion needs to be deleted
  1303. // Unjoin
  1304. //
  1305. if (!IS_TIME_ZERO(Replica->MembershipExpires) ||
  1306. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN) ||
  1307. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1308. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  1309. break;
  1310. }
  1311. //
  1312. // Send our join info to our inbound partner
  1313. //
  1314. // This request times out if our partner doesn't answer.
  1315. //
  1316. DPRINT1(4, ":X: Send join info at send/wait join: "FORMAT_CXTION_PATH2"\n",
  1317. PRINT_CXTION_PATH2(Replica, Cxtion));
  1318. SetCxtionState(Cxtion, CxtionStateWaitJoin);
  1319. //
  1320. // Increment the Join Notifications sent counter for
  1321. // both the replica set and connection objects
  1322. //
  1323. PM_INC_CTR_CXTION(Cxtion, JoinNSent, 1);
  1324. PM_INC_CTR_REPSET(Replica, JoinNSent, 1);
  1325. CPkt = CommBuildCommPkt(Replica, Cxtion, CMD_JOINING, Replica->VVector, NULL, NULL);
  1326. SndCsSubmitCommPkt2(Replica, Cxtion, NULL, TRUE, CPkt);
  1327. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1328. break;
  1329. case CxtionStateJoined:
  1330. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1331. //
  1332. // Replica is deleted,
  1333. // The cxtion needs to be unjoined, or
  1334. // The cxtion needs to be deleted
  1335. // Unjoin
  1336. //
  1337. if (!IS_TIME_ZERO(Replica->MembershipExpires) ||
  1338. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN) ||
  1339. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1340. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  1341. break;
  1342. }
  1343. //
  1344. // Refresh our inbound partner's join state (with timeout)
  1345. //
  1346. if (Cxtion->Inbound && !Cxtion->JrnlCxtion) {
  1347. DPRINT1(4, ":X: send join info at join: "FORMAT_CXTION_PATH2"\n",
  1348. PRINT_CXTION_PATH2(Replica, Cxtion));
  1349. //
  1350. // Increment the Join Notifications sent counter for
  1351. // both the replica set and connection objects
  1352. //
  1353. PM_INC_CTR_CXTION(Cxtion, JoinNSent, 1);
  1354. PM_INC_CTR_REPSET(Replica, JoinNSent, 1);
  1355. CPkt = CommBuildCommPkt(Replica, Cxtion, CMD_JOINING, Replica->VVector, NULL, NULL);
  1356. SndCsSubmitCommPkt2(Replica, Cxtion, NULL, TRUE, CPkt);
  1357. }
  1358. //
  1359. // Already joined; nothing to do
  1360. //
  1361. DPRINT1(4, ":X: Joined at join: "FORMAT_CXTION_PATH2"\n",
  1362. PRINT_CXTION_PATH2(Replica, Cxtion));
  1363. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1364. break;
  1365. case CxtionStateUnjoining:
  1366. //
  1367. // Ignore requests to join while unjoining so that we don't
  1368. // end up with multiple inbound log scans. If this join
  1369. // request originated from our partner then the caller
  1370. // will set the CXTION_FLAGS_DEFERRED_JOIN and the join
  1371. // will start at the transition from UNJOINING to UNJOINED.
  1372. //
  1373. DPRINT1(4, ":X: Unjoining at join: "FORMAT_CXTION_PATH2"\n",
  1374. PRINT_CXTION_PATH2(Replica, Cxtion));
  1375. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1376. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1377. break;
  1378. case CxtionStateDeleted:
  1379. //
  1380. // Deleted; nothing to do
  1381. //
  1382. DPRINT1(4, ":X: Cxtion is deleted at join: "FORMAT_CXTION_PATH2"\n",
  1383. PRINT_CXTION_PATH2(Replica, Cxtion));
  1384. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1385. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1386. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1387. break;
  1388. default:
  1389. //
  1390. // ?
  1391. //
  1392. DPRINT2(0, ":X: ERROR - bad state %d for "FORMAT_CXTION_PATH2"\n",
  1393. GetCxtionState(Cxtion),
  1394. PRINT_CXTION_PATH2(Replica, Cxtion));
  1395. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1396. break;
  1397. }
  1398. UNLOCK_CXTION_TABLE(Replica);
  1399. }
  1400. VOID
  1401. RcsEmptyPreExistingDir(
  1402. IN PREPLICA Replica
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. Delete empty directories in the preexisting directory, inclusive.
  1407. WARN: The replica set must be filtering the preexisting directory.
  1408. Arguments:
  1409. Replica - The replica is filtering the preexisting directory.
  1410. Return Value:
  1411. None.
  1412. --*/
  1413. {
  1414. #undef DEBSUB
  1415. #define DEBSUB "RcsEmptyPreExistingDir:"
  1416. ULONG WStatus;
  1417. PWCHAR PreExistingPath = NULL;
  1418. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, RcsEmptyPreExistingDir entry");
  1419. //
  1420. // Not if the set isn't open
  1421. //
  1422. if (!Replica->IsOpen) {
  1423. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, RcsEmptyPreExistingDir: not open");
  1424. return;
  1425. }
  1426. //
  1427. // Not if the set isn't journaling
  1428. //
  1429. if (!Replica->IsJournaling) {
  1430. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, RcsEmptyPreExistingDir: not journaling");
  1431. return;
  1432. }
  1433. //
  1434. // Empty the preexisting directory (continue on error)
  1435. //
  1436. PreExistingPath = FrsWcsPath(Replica->Root, NTFRS_PREEXISTING_DIRECTORY);
  1437. WStatus = FrsDeletePath(PreExistingPath,
  1438. ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE |
  1439. ENUMERATE_DIRECTORY_FLAGS_DIRECTORIES_ONLY);
  1440. DPRINT1_WS(3, "++ ERROR - FrsDeletePath(%ws) (IGNORED);", PreExistingPath, WStatus);
  1441. REPLICA_STATE_TRACE(3, NULL, Replica, WStatus, "W, RcsEmptyPreExistingDir: done");
  1442. FrsFree(PreExistingPath);
  1443. }
  1444. VOID
  1445. RcsOpenReplicaSetMember(
  1446. IN PREPLICA Replica
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. Open a replica set.
  1451. Arguments:
  1452. Replica -- ptr to a REPLICA struct
  1453. Return Value:
  1454. None.
  1455. --*/
  1456. {
  1457. #undef DEBSUB
  1458. #define DEBSUB "RcsOpenReplicaSetMember:"
  1459. ULONG WStatus;
  1460. PCOMMAND_PACKET Cmd = NULL;
  1461. Replica->FStatus = FrsErrorSuccess;
  1462. if (Replica->IsOpen) {
  1463. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Replica already open");
  1464. return;
  1465. }
  1466. //
  1467. // Submit an open
  1468. //
  1469. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  1470. Replica, // Replica,
  1471. CMD_OPEN_REPLICA_SET_MEMBER, // CmdRequest,
  1472. NULL, // TableCtx,
  1473. NULL, // CallContext,
  1474. 0, // TableType,
  1475. 0, // AccessRequest,
  1476. 0, // IndexType,
  1477. NULL, // KeyValue,
  1478. 0, // KeyValueLength,
  1479. FALSE); // Submit
  1480. //
  1481. // Don't free the packet when the command completes.
  1482. //
  1483. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  1484. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "Submit DB OPEN_REPLICA_SET_MEMBER");
  1485. //
  1486. // SUBMIT DB Cmd and wait for completion.
  1487. //
  1488. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  1489. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  1490. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, OPEN_REPLICA_SET_MEMBER return");
  1491. //
  1492. // If wait or database op failed
  1493. //
  1494. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  1495. //
  1496. // If wait / submit failed then let caller know cmd srv submit failed.
  1497. //
  1498. if (FRS_SUCCESS(Replica->FStatus)) {
  1499. Replica->FStatus = FrsErrorCmdSrvFailed;
  1500. }
  1501. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Open Replica failed;",
  1502. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  1503. DPRINT_WS(0, "ERROR: Open Replica DB Command failed", WStatus);
  1504. goto out;
  1505. }
  1506. Replica->IsOpen = FRS_SUCCESS(Replica->FStatus);
  1507. out:
  1508. if (Cmd) {
  1509. FrsFreeCommand(Cmd, NULL);
  1510. }
  1511. }
  1512. VOID
  1513. RcsInitOneReplicaSet(
  1514. IN PREPLICA Replica
  1515. )
  1516. /*++
  1517. Routine Description:
  1518. Open a replica set.
  1519. Arguments:
  1520. Replica -- ptr to a REPLICA struct
  1521. Return Value:
  1522. None.
  1523. --*/
  1524. {
  1525. #undef DEBSUB
  1526. #define DEBSUB "RcsInitOneReplicaSet:"
  1527. ULONG FStatus;
  1528. //
  1529. // Already journaling; done
  1530. //
  1531. if (Replica->IsJournaling) {
  1532. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, IsJournaling True");
  1533. return;
  1534. }
  1535. if (!Replica->IsOpen) {
  1536. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, IsOpen False");
  1537. return;
  1538. }
  1539. //
  1540. // Don't retry if in journal wrap error state error
  1541. //
  1542. if (Replica->ServiceState == REPLICA_STATE_JRNL_WRAP_ERROR) {
  1543. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, In Jrnl Wrap Error State");
  1544. return;
  1545. }
  1546. //
  1547. // Otherwise set it to the initializing state.
  1548. //
  1549. if (REPLICA_IN_ERROR_STATE(Replica->ServiceState)) {
  1550. JrnlSetReplicaState(Replica, REPLICA_STATE_INITIALIZING);
  1551. }
  1552. //
  1553. // Don't start journaling if the preinstall directory is unavailable
  1554. //
  1555. if (!HANDLE_IS_VALID(Replica->PreInstallHandle)) {
  1556. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, No PreInstallHandle");
  1557. return;
  1558. }
  1559. //
  1560. // Initialize the DB and Journal subsystems for this replica set.
  1561. //
  1562. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, DbsInitOneReplicaSet call");
  1563. FStatus = DbsInitOneReplicaSet(Replica);
  1564. REPLICA_STATE_TRACE(3, NULL, Replica, FStatus, "F, DbsInitOneReplicaSet return");
  1565. }
  1566. VOID
  1567. RcsJoiningAfterFlush(
  1568. IN PCOMMAND_PACKET Cmd
  1569. )
  1570. /*++
  1571. Routine Description:
  1572. A downstream partner (X) sent this JOINING request to us. We are its
  1573. inbound partner. We should have a corresponding outbound connection
  1574. for X. If we do and the replication schedule allows we activate the
  1575. outbound log partner and ack the Joining request with CMD_JOINED.
  1576. This command packet was first placed on the SndCs's queue by
  1577. RcsJoining() so that all of the old comm packets with the
  1578. old join guid have been discarded. This protocol is needed because
  1579. this function may REJOIN and revalidate the old join guid. Packets
  1580. still on the send queue would then be sent out of order.
  1581. NOTE:
  1582. Activating the OUTLOG partner before sending the JOINED cmd to the partner
  1583. can cause COs to be sent to the partner before it sees the JOINED cmd.
  1584. Since the JoinGuid matches in the sent change orders the partner accepts
  1585. them and queues them to the change order process queue. If this CO gets to
  1586. the head of the process queue the issue logic in ChgOrdAccept will
  1587. block the queue waiting for the connection to go to the JOINED state. When
  1588. the JOINED cmd arrives it is processed by RcsInboundJoined() which sets the
  1589. connection state to JOINED and unblocks the change order process queue.
  1590. We can't send the JOINED cmd first because the partner may then send back
  1591. a fetch request before we think it has joined. The JOINED cmd must always
  1592. be sent so the partner knows it can start sending fetch cmds because we
  1593. may have no outbound COs to send. In addtion the JOINED command contains
  1594. the new value for LastJoinedTime that is saved in the connection record
  1595. for the next join request.
  1596. NOTE:
  1597. Cxtion activation should always come from the downstream partner. Only they
  1598. know if a VVJoin is required because of a database re-init or restore.
  1599. Otherwise we will just continue sending from the last unacked CO in the log.
  1600. At best we can notify outbound partners we are now available to provide
  1601. change orders (via CMD_JOIN_RESEND)
  1602. Arguments:
  1603. Cmd
  1604. Return Value:
  1605. None.
  1606. --*/
  1607. {
  1608. #undef DEBSUB
  1609. #define DEBSUB "RcsJoiningAfterFlush:"
  1610. FILETIME FileTime;
  1611. ULONGLONG Now;
  1612. ULONGLONG Delta;
  1613. ULONG FStatus;
  1614. PREPLICA Replica;
  1615. PCXTION OutCxtion;
  1616. PCOMM_PACKET CPkt;
  1617. #define CXTION_STR_MAX 256
  1618. WCHAR CxtionStr[CXTION_STR_MAX];
  1619. WCHAR WSkew[15], WDelta[15];
  1620. PVOID Key;
  1621. PGEN_ENTRY Entry;
  1622. //
  1623. // Check the command packet
  1624. //
  1625. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK |
  1626. CHECK_CMD_REPLICA_VERSION_GUID |
  1627. CHECK_CMD_JOINTIME |
  1628. CHECK_CMD_NOT_EXPIRED)) {
  1629. return;
  1630. }
  1631. Replica = RsReplica(Cmd);
  1632. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsJoiningAfterFlush entry");
  1633. //
  1634. // Find and check the cxtion
  1635. //
  1636. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  1637. CHECK_CXTION_OUTBOUND |
  1638. CHECK_CXTION_PARTNER |
  1639. CHECK_CXTION_AUTH);
  1640. if (!OutCxtion) {
  1641. return;
  1642. }
  1643. //
  1644. // Shutting down; ignore join request
  1645. //
  1646. if (FrsIsShuttingDown) {
  1647. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, FrsIsShuttingDown");
  1648. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  1649. return;
  1650. }
  1651. //
  1652. // Do not join with a downstream partner if this replica is still
  1653. // seeding and is not online.
  1654. //
  1655. if ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  1656. Replica->IsSeeding) &&
  1657. !BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  1658. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Seeding and Offline");
  1659. FrsCompleteCommand(Cmd, ERROR_RETRY);
  1660. return;
  1661. }
  1662. //
  1663. // Already joined; should we rejoin?
  1664. //
  1665. if (CxtionStateIs(OutCxtion, CxtionStateJoined)) {
  1666. //
  1667. // Don't rejoin if this is a retry by our outbound partner
  1668. //
  1669. if (GUIDS_EQUAL(&OutCxtion->JoinGuid, RsJoinGuid(Cmd)) &&
  1670. CxtionFlagIs(OutCxtion, CXTION_FLAGS_JOIN_GUID_VALID)) {
  1671. //
  1672. // Tell our outbound partner that we have rejoined successfully
  1673. // Increment the Joins counter for
  1674. // both the replica set and connection objects
  1675. //
  1676. PM_INC_CTR_CXTION(OutCxtion, Joins, 1);
  1677. PM_INC_CTR_REPSET(Replica, Joins, 1);
  1678. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, REJOINED");
  1679. DPRINT1(0, ":X: ***** REJOINED "FORMAT_CXTION_PATH2"\n",
  1680. PRINT_CXTION_PATH2(Replica, OutCxtion));
  1681. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_JOINED, NULL, NULL, NULL);
  1682. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  1683. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1684. return;
  1685. }
  1686. //
  1687. // Unjoin and rejoin. Partner may have restarted.
  1688. // WARN: forcing an unjoin of an outbound cxtion works
  1689. // because outbound cxtions transition from Joined to
  1690. // Unjoined with no intervening states.
  1691. //
  1692. FStatus = RcsForceUnjoin(Replica, OutCxtion);
  1693. CXTION_STATE_TRACE(3, OutCxtion, Replica, FStatus, "F, RcsForceUnjoin return");
  1694. if (!FRS_SUCCESS(FStatus)) {
  1695. DPRINT_FS(0, ":X: ERROR - return from RcsForceUnjoin:", FStatus);
  1696. FrsCompleteCommand(Cmd, ERROR_REQUEST_ABORTED);
  1697. return;
  1698. }
  1699. }
  1700. //
  1701. // Machines can't join if their times are badly out of sync
  1702. // UNLESS this is a VOLATILE cxtion (I.e., sysvol seeding).
  1703. //
  1704. // Time in 100nsec tics since Jan 1, 1601
  1705. //
  1706. GetSystemTimeAsFileTime(&FileTime);
  1707. COPY_TIME(&Now, &FileTime);
  1708. if (Now > *RsJoinTime(Cmd)) {
  1709. Delta = Now - *RsJoinTime(Cmd);
  1710. } else {
  1711. Delta = *RsJoinTime(Cmd) - Now;
  1712. }
  1713. //
  1714. // Ignore out-of-sync times if this is a volatile cxtion. Volatile
  1715. // cxtions are only used for sysvol seeding where times don't matter.
  1716. //
  1717. if (!CxtionFlagIs(OutCxtion, CXTION_FLAGS_VOLATILE) &&
  1718. (Delta > MaxPartnerClockSkew)) {
  1719. Delta = Delta / CONVERT_FILETIME_TO_MINUTES;
  1720. DPRINT1(0, ":X: ERROR - Joining Now is %08x %08x\n", PRINTQUAD(Now));
  1721. Now = *RsJoinTime(Cmd);
  1722. DPRINT1(0, ":X: ERROR - Joining RsNow is %08x %08x\n", PRINTQUAD(Now));
  1723. _snwprintf(CxtionStr, CXTION_STR_MAX, FORMAT_CXTION_PATH2W,
  1724. PRINT_CXTION_PATH2(Replica, OutCxtion));
  1725. CxtionStr[CXTION_STR_MAX-1] = UNICODE_NULL;
  1726. _itow(PartnerClockSkew, WSkew, 10);
  1727. _itow((LONG)Delta, WDelta, 10);
  1728. EPRINT3(EVENT_FRS_JOIN_FAIL_TIME_SKEW, WSkew, CxtionStr, WDelta);
  1729. DPRINT2(0, ":X: ERROR - Cannot join (%ws) clocks are out of sync by %d minutes\n",
  1730. CxtionStr, (LONG)Delta);
  1731. DPRINT(0, ":X: Note: If this time difference is close to a multiple of 60 minutes then it\n");
  1732. DPRINT(0, ":X: is likely that either this computer or its partner computer was set to the\n");
  1733. DPRINT(0, ":X: incorrect time zone when the computer time was initially set. Check that both \n");
  1734. DPRINT(0, ":X: the time zones and the time is set correctly on both computers.\n");
  1735. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  1736. return;
  1737. }
  1738. //
  1739. // Grab the new version vector. Initialize an empty version vector
  1740. // if our outbound partner did not send a version vector. Our partner
  1741. // simply does not yet have any entries in his version vector.
  1742. //
  1743. OutCxtion->VVector = (RsVVector(Cmd) != NULL) ?
  1744. RsVVector(Cmd) : GTabAllocTable();
  1745. RsVVector(Cmd) = NULL;
  1746. //
  1747. // Grab the compression table from the outbound partner.
  1748. // This table is a list of guids 1 for each compression format that
  1749. // the partner supports.
  1750. //
  1751. OutCxtion->CompressionTable = (RsCompressionTable(Cmd) != NULL) ?
  1752. RsCompressionTable(Cmd) : GTabAllocTable();
  1753. DPRINT1(4, "Received following compression table from %ws.\n", OutCxtion->PartnerDnsName);
  1754. GTabLockTable(OutCxtion->CompressionTable);
  1755. Key = NULL;
  1756. while (Entry = GTabNextEntryNoLock(OutCxtion->CompressionTable, &Key)) {
  1757. FrsPrintGuid(Entry->Key1);
  1758. }
  1759. GTabUnLockTable(OutCxtion->CompressionTable);
  1760. RsCompressionTable(Cmd) = NULL;
  1761. //
  1762. // Assign the join guid and comm queue to this cxtion.
  1763. //
  1764. DPRINT1(4, ":X: %ws: Assigning join guid.\n", OutCxtion->Name->Name);
  1765. COPY_GUID(&OutCxtion->JoinGuid, RsJoinGuid(Cmd));
  1766. SetCxtionFlag(OutCxtion, CXTION_FLAGS_JOIN_GUID_VALID |
  1767. CXTION_FLAGS_UNJOIN_GUID_VALID);
  1768. //
  1769. // Assign a comm queue. A cxtion must use the same comm queue
  1770. // for a given session (join guid) to maintain packet order.
  1771. // Old packets have an invalid join guid and are either not
  1772. // sent or ignored on the receiving side.
  1773. //
  1774. OutCxtion->CommQueueIndex = SndCsAssignCommQueue();
  1775. VV_PRINT_OUTBOUND(4, OutCxtion->Partner->Name, OutCxtion->VVector);
  1776. //
  1777. // Check for match on last join time or we were already in vvjoin mode.
  1778. // If no match then either the database at our end or the database at
  1779. // the other end has changed. Force a VV join in this case.
  1780. //
  1781. if (RsLastJoinTime(Cmd) != OutCxtion->LastJoinTime) {
  1782. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, LastJoinTime Mismatch, force VVJoin");
  1783. SetCxtionFlag(OutCxtion, CXTION_FLAGS_PERFORM_VVJOIN);
  1784. }
  1785. //
  1786. // Our partner's replica version guid (aka originator guid) used
  1787. // for dampening requests to our partner.
  1788. //
  1789. COPY_GUID(&OutCxtion->ReplicaVersionGuid, RsReplicaVersionGuid(Cmd));
  1790. //
  1791. // REPLICA JOINED
  1792. //
  1793. SetCxtionState(OutCxtion, CxtionStateJoined);
  1794. //
  1795. // Inform the user that a long join has finally completed.
  1796. // The user receives no notification if a join occurs in a short time.
  1797. //
  1798. if (OutCxtion->JoinCmd &&
  1799. (LONG)RsTimeout(OutCxtion->JoinCmd) > (JOIN_RETRY_EVENT * MinJoinRetry)) {
  1800. if (OutCxtion->Inbound) {
  1801. EPRINT3(EVENT_FRS_LONG_JOIN_DONE,
  1802. OutCxtion->Partner->Name, ComputerName, Replica->Root);
  1803. } else {
  1804. EPRINT3(EVENT_FRS_LONG_JOIN_DONE,
  1805. ComputerName, OutCxtion->Partner->Name, Replica->Root);
  1806. }
  1807. }
  1808. //
  1809. // Tell the Outbound Log that this partner has joined. This call is synchronous.
  1810. //
  1811. #if DBG
  1812. //
  1813. // Always VvJoin
  1814. if (DebugInfo.ForceVvJoin) {
  1815. SetCxtionFlag(OutCxtion, CXTION_FLAGS_PERFORM_VVJOIN);
  1816. }
  1817. #endif DBG
  1818. FStatus = OutLogSubmit(Replica, OutCxtion, CMD_OUTLOG_ACTIVATE_PARTNER);
  1819. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, OUTLOG_ACTIVATE_PARTNER return");
  1820. if (!FRS_SUCCESS(FStatus)) {
  1821. //
  1822. // Could not enable outbound log processing for this cxtion
  1823. //
  1824. DPRINT_FS(0, "++ ERROR - return from CMD_OUTLOG_ACTIVATE_PARTNER:", FStatus);
  1825. RcsForceUnjoin(Replica, OutCxtion);
  1826. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  1827. return;
  1828. }
  1829. //
  1830. // OUTBOUND LOG PROCESSING HAS BEEN ENABLED
  1831. //
  1832. //
  1833. // Tell our outbound partner that we are ready to go.
  1834. //
  1835. // WARN: comm packets may have already been sent to our partner once we
  1836. // activated outlog processing above. In that case, our partner treated
  1837. // the packet as an implicit CMD_JOINED and completed the join. This
  1838. // packet is then ignored as an extraneous join request except that it
  1839. // causes our partner to update the last joined time to match ours.
  1840. //
  1841. // Increment the Joins counter for
  1842. // both the replica set and connection objects
  1843. //
  1844. PM_INC_CTR_CXTION(OutCxtion, Joins, 1);
  1845. PM_INC_CTR_REPSET(Replica, Joins, 1);
  1846. DPRINT1(0, ":X: ***** JOINED "FORMAT_CXTION_PATH2"\n",
  1847. PRINT_CXTION_PATH2(Replica, OutCxtion));
  1848. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, JOINED");
  1849. //
  1850. // Update the DB cxtion table record with the new Join Time.
  1851. //
  1852. // *NOTE* The following call is synchronous. If we have the Cxtion
  1853. // table lock then a hang is possible.
  1854. //
  1855. GetSystemTimeAsFileTime((PFILETIME)&OutCxtion->LastJoinTime);
  1856. InterlockedIncrement(&Replica->OutLogCxtionsJoined);
  1857. DPRINT1(4, "TEMP: OutLogCxtionsJoined %d\n", Replica->OutLogCxtionsJoined);
  1858. FStatus = OutLogSubmit(Replica, OutCxtion, CMD_OUTLOG_UPDATE_PARTNER);
  1859. CXTION_STATE_TRACE(3, OutCxtion, Replica, FStatus, "F, OUTLOG_UPDATE_PARTNER return");
  1860. if (!FRS_SUCCESS(FStatus)) {
  1861. DPRINT3(0, "++ WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  1862. OutCxtion->Name->Name, OutCxtion->Partner->Name, Replica->ReplicaName->Name);
  1863. }
  1864. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Cxtion JOINED, xmit resp");
  1865. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_JOINED, NULL, NULL, NULL);
  1866. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  1867. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1868. //
  1869. // Inject a end-of-join control co if this cxtion is using a trigger
  1870. // schedule. Note that the EndOfJoin Co may have been processed by
  1871. // the time this call returns.
  1872. //
  1873. if (CxtionFlagIs(OutCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  1874. OutLogAcquireLock(Replica);
  1875. if (OutCxtion->OLCtx &&
  1876. !InVVJoinMode(OutCxtion->OLCtx) &&
  1877. CxtionStateIs(OutCxtion, CxtionStateJoined)) {
  1878. ChgOrdInjectControlCo(Replica, OutCxtion, FCN_CO_END_OF_JOIN);
  1879. }
  1880. OutLogReleaseLock(Replica);
  1881. }
  1882. }
  1883. VOID
  1884. RcsJoining(
  1885. IN PCOMMAND_PACKET Cmd
  1886. )
  1887. /*++
  1888. Routine Description:
  1889. A downstream partner (X) sent this JOINING request to us. We are its
  1890. inbound partner. We should have a corresponding outbound connection
  1891. for X. If we do and the replication schedule allows we activate the
  1892. outbound log partner and ack the Joining request with CMD_JOINED.
  1893. This command packet is first put on the SndCs's(Send Command Server)
  1894. queue so that all of the old comm packets with the old join guid
  1895. will have been discarded. This protocol is needed because this
  1896. function may REJOIN and revalidate the old join guid. Packets
  1897. still on the send queue would then be sent out of order.
  1898. The command packet is sent to RcsJoiningAfterFlush() after
  1899. bubbling up to the top of the send queue.
  1900. Arguments:
  1901. Cmd
  1902. Return Value:
  1903. None.
  1904. --*/
  1905. {
  1906. #undef DEBSUB
  1907. #define DEBSUB "RcsJoining:"
  1908. FILETIME FileTime;
  1909. ULONGLONG Now;
  1910. ULONGLONG Delta;
  1911. ULONG FStatus;
  1912. PREPLICA Replica;
  1913. PCXTION OutCxtion;
  1914. PCOMM_PACKET CPkt;
  1915. //
  1916. // Check the command packet
  1917. //
  1918. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK |
  1919. CHECK_CMD_REPLICA_VERSION_GUID |
  1920. CHECK_CMD_JOINTIME |
  1921. CHECK_CMD_NOT_EXPIRED)) {
  1922. return;
  1923. }
  1924. Replica = RsReplica(Cmd);
  1925. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsJoining entry");
  1926. //
  1927. // Find and check the cxtion
  1928. //
  1929. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  1930. CHECK_CXTION_OUTBOUND |
  1931. CHECK_CXTION_PARTNER |
  1932. CHECK_CXTION_AUTH);
  1933. if (!OutCxtion) {
  1934. return;
  1935. }
  1936. //
  1937. // Increment the Join Notifications Received counter for
  1938. // both the replica set and connection objects
  1939. //
  1940. PM_INC_CTR_CXTION(OutCxtion, JoinNRcvd, 1);
  1941. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  1942. //
  1943. // Shutting down; ignore join request
  1944. //
  1945. if (FrsIsShuttingDown) {
  1946. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  1947. return;
  1948. }
  1949. //
  1950. // Do not join with a downstream partner if this replica is still
  1951. // seeding and is not online.
  1952. //
  1953. if ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  1954. Replica->IsSeeding) &&
  1955. !BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  1956. FrsCompleteCommand(Cmd, ERROR_RETRY);
  1957. return;
  1958. }
  1959. //
  1960. // Put this command packet at the end of this cxtion's send queue. Once it
  1961. // bubbles up to the top the command packet will be sent back to this
  1962. // command server with the ccommand CMD_JOINING_AFTER_FLUSH and will be
  1963. // given to RcsJoiningAfterFlush() for processing.
  1964. //
  1965. Cmd->Command = CMD_JOINING_AFTER_FLUSH;
  1966. SndCsSubmitCmd(Replica,
  1967. OutCxtion,
  1968. &ReplicaCmdServer,
  1969. Cmd,
  1970. OutCxtion->CommQueueIndex);
  1971. }
  1972. VOID
  1973. RcsNeedJoin(
  1974. IN PCOMMAND_PACKET Cmd
  1975. )
  1976. /*++
  1977. Routine Description:
  1978. Our outbound partner has sent this packet to see if we are alive.
  1979. Respond with a start-your-join packet.
  1980. Arguments:
  1981. Cmd
  1982. Return Value:
  1983. None.
  1984. --*/
  1985. {
  1986. #undef DEBSUB
  1987. #define DEBSUB "RcsNeedJoin:"
  1988. PREPLICA Replica;
  1989. PCXTION OutCxtion;
  1990. PCOMM_PACKET CPkt;
  1991. DWORD CQIndex;
  1992. //
  1993. // Check the command packet
  1994. //
  1995. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA |
  1996. CHECK_CMD_CXTION |
  1997. CHECK_CMD_NOT_EXPIRED)) {
  1998. return;
  1999. }
  2000. Replica = RsReplica(Cmd);
  2001. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsNeedJoin entry");
  2002. //
  2003. // Find and check the cxtion
  2004. //
  2005. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  2006. CHECK_CXTION_OUTBOUND |
  2007. CHECK_CXTION_PARTNER |
  2008. CHECK_CXTION_AUTH);
  2009. if (!OutCxtion) {
  2010. return;
  2011. }
  2012. //
  2013. // Increment the Join Notifications Received counter for
  2014. // both the replica set and connection objects
  2015. //
  2016. PM_INC_CTR_CXTION(OutCxtion, JoinNRcvd, 1);
  2017. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  2018. //
  2019. // Do not join with a downstream partner if this replica is still
  2020. // seeding and is not online.
  2021. //
  2022. if ((!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  2023. !Replica->IsSeeding) ||
  2024. BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  2025. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Xmit START_JOIN req");
  2026. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_START_JOIN, NULL, NULL, NULL);
  2027. CQIndex = OutCxtion->CommQueueIndex;
  2028. SndCsSubmitCommPkt(Replica, OutCxtion, NULL, NULL, FALSE, CPkt, CQIndex);
  2029. }
  2030. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2031. }
  2032. VOID
  2033. RcsStartJoin(
  2034. IN PCOMMAND_PACKET Cmd
  2035. )
  2036. /*++
  2037. Routine Description:
  2038. Our inbound partner has sent this packet to tell us it is alive
  2039. and that the join can be started.
  2040. Arguments:
  2041. Cmd
  2042. Return Value:
  2043. None.
  2044. --*/
  2045. {
  2046. #undef DEBSUB
  2047. #define DEBSUB "RcsStartJoin:"
  2048. PREPLICA Replica;
  2049. PCXTION InCxtion;
  2050. //
  2051. // Check the command packet
  2052. //
  2053. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA |
  2054. CHECK_CMD_CXTION |
  2055. CHECK_CMD_NOT_EXPIRED)) {
  2056. return;
  2057. }
  2058. Replica = RsReplica(Cmd);
  2059. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsStartJoin entry");
  2060. //
  2061. // Find and check the cxtion
  2062. //
  2063. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  2064. CHECK_CXTION_INBOUND |
  2065. CHECK_CXTION_PARTNER |
  2066. CHECK_CXTION_AUTH);
  2067. if (!InCxtion) {
  2068. return;
  2069. }
  2070. //
  2071. // Increment the Join Notifications Received counter for
  2072. // both the replica set and connection objects
  2073. //
  2074. PM_INC_CTR_CXTION(InCxtion, JoinNRcvd, 1);
  2075. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  2076. //
  2077. // If this replica set is in seeding state and this connection is in
  2078. // initial sync state then let the initial sync command server decide
  2079. // how to respond to this START_JOIN. It will respond to one START_JOIN
  2080. // at a time.
  2081. //
  2082. if (BooleanFlagOn(Replica->CnfFlags,CONFIG_FLAG_SEEDING) &&
  2083. CxtionFlagIs(InCxtion,CXTION_FLAGS_INIT_SYNC)) {
  2084. InitSyncCsSubmitTransfer(Cmd, CMD_INITSYNC_START_JOIN);
  2085. return;
  2086. }
  2087. LOCK_CXTION_TABLE(Replica);
  2088. //
  2089. // If we were waiting for our partner to respond or think we
  2090. // have already joined then either start the join process or
  2091. // resend our join info.
  2092. //
  2093. // Otherwise, let the normal join flow take over. If there are
  2094. // problems then the join will timeout and retry.
  2095. //
  2096. if (CxtionStateIs(InCxtion, CxtionStateUnjoined) ||
  2097. CxtionStateIs(InCxtion, CxtionStateJoined)) {
  2098. if (CxtionStateIs(InCxtion, CxtionStateUnjoined)) {
  2099. SetCxtionState(InCxtion, CxtionStateStart);
  2100. }
  2101. //
  2102. // Start the join process or resend the join info
  2103. //
  2104. UNLOCK_CXTION_TABLE(Replica);
  2105. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsJoinCxtion call");
  2106. RcsJoinCxtion(Cmd);
  2107. } else {
  2108. UNLOCK_CXTION_TABLE(Replica);
  2109. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Cannot start join");
  2110. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2111. }
  2112. }
  2113. VOID
  2114. RcsSubmitReplicaCxtionJoin(
  2115. IN PREPLICA Replica,
  2116. IN PCXTION Cxtion,
  2117. IN BOOL Later
  2118. )
  2119. /*++
  2120. Routine Description:
  2121. Submit a join command to a replica\cxtion.
  2122. Build cmd pkt with Cxtion GName and replica ptr. Submit to Replica cmd
  2123. server. Calls dispatch function and translates cxtion GName to cxtion ptr
  2124. SYNCHRONIZATION -- Only called from the context of the
  2125. Replica Command Server. No locks needed.
  2126. Arguments:
  2127. Replica - existing replica
  2128. Cxtion - existing cxtion
  2129. Later - Delayed submission
  2130. Return Value:
  2131. None.
  2132. --*/
  2133. {
  2134. #undef DEBSUB
  2135. #define DEBSUB "RcsSubmitReplicaCxtionJoin:"
  2136. PCOMMAND_PACKET Cmd;
  2137. //
  2138. // The cxtion already has a join command outstanding; don't flood the
  2139. // queue with extraneous requests.
  2140. //
  2141. if (Cxtion->JoinCmd) {
  2142. return;
  2143. }
  2144. //
  2145. // Not scheduled to run
  2146. //
  2147. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  2148. return;
  2149. }
  2150. //
  2151. // Already joined; done
  2152. //
  2153. if (CxtionStateIs(Cxtion, CxtionStateJoined) &&
  2154. !CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN)) {
  2155. return;
  2156. }
  2157. //
  2158. // Trigger schedules are managed by RcsCheckSchedules()
  2159. //
  2160. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  2161. return;
  2162. }
  2163. //
  2164. // Allocate a command packet
  2165. //
  2166. Cmd = FrsAllocCommand(Replica->Queue, CMD_JOIN_CXTION);
  2167. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  2168. //
  2169. // Address of replica set and new replica set
  2170. //
  2171. RsReplica(Cmd) = Replica;
  2172. RsCxtion(Cmd) = FrsDupGName(Cxtion->Name);
  2173. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, RcsSubmitReplicaCxtionJoin entry");
  2174. //
  2175. // Cxtion should have just one join command outstanding
  2176. //
  2177. if (Later) {
  2178. DPRINT5(4, "++ Submit LATER %08x for Cmd %08x %ws\\%ws\\%ws\n",
  2179. Cmd->Command, Cmd, Replica->SetName->Name,
  2180. Replica->MemberName->Name, Cxtion->Name->Name);
  2181. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, RcsJoinCxtionLater call");
  2182. RcsJoinCxtionLater(Replica, Cxtion, Cmd);
  2183. } else {
  2184. Cxtion->JoinCmd = Cmd;
  2185. DPRINT5(4, "++ Submit %08x for Cmd %08x %ws\\%ws\\%ws\n",
  2186. Cmd->Command, Cmd, Replica->SetName->Name,
  2187. Replica->MemberName->Name, Cxtion->Name->Name);
  2188. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Submit JOIN_CXTION req");
  2189. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  2190. }
  2191. }
  2192. ULONG
  2193. RcsDrainActiveCOsOnCxtion(
  2194. IN PREPLICA Replica,
  2195. IN PCXTION Cxtion
  2196. )
  2197. /*++
  2198. Routine Description:
  2199. Remove the active change orders from this connection and send them
  2200. thru retry.
  2201. Assumes: Caller has acquired the CXTION_TABLE lock.
  2202. Arguments:
  2203. Replica - ptr to replica struct for this replica set.
  2204. Cxtion - ptr to connection struct being unjoined.
  2205. Return Value:
  2206. FrsErrorStatus
  2207. --*/
  2208. {
  2209. #undef DEBSUB
  2210. #define DEBSUB "RcsDrainActiveCOsOnCxtion:"
  2211. PVOID Key;
  2212. PCHANGE_ORDER_ENTRY Coe;
  2213. ULONG FStatus = FrsErrorSuccess;
  2214. //
  2215. // Take idle change orders through retry
  2216. //
  2217. LOCK_CXTION_COE_TABLE(Replica, Cxtion);
  2218. Key = NULL;
  2219. while (Coe = GTabNextDatumNoLock(Cxtion->CoeTable, &Key)) {
  2220. Key = NULL;
  2221. GTabDeleteNoLock(Cxtion->CoeTable, &Coe->Cmd.ChangeOrderGuid, NULL, NULL);
  2222. SET_COE_FLAG(Coe, COE_FLAG_NO_INBOUND);
  2223. if (Cxtion->JrnlCxtion) {
  2224. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to stage gen retry");
  2225. ChgOrdInboundRetry(Coe, IBCO_STAGING_RETRY);
  2226. } else {
  2227. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to fetch retry");
  2228. ChgOrdInboundRetry(Coe, IBCO_FETCH_RETRY);
  2229. }
  2230. }
  2231. UNLOCK_CXTION_COE_TABLE(Replica, Cxtion);
  2232. //
  2233. // If there are no outstanding change orders that need to be taken through the
  2234. // retry path, unjoin complete. Otherwise, the unjoin will complete once
  2235. // the count reaches 0. Until then, further attempts to join will be
  2236. // ignored.
  2237. //
  2238. if (Cxtion->ChangeOrderCount == 0) {
  2239. SndCsDestroyCxtion(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID);
  2240. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2241. //
  2242. // Increment the Unjoins counter for
  2243. // both the replica set and connection objects
  2244. //
  2245. PM_INC_CTR_CXTION(Cxtion, Unjoins, 1);
  2246. PM_INC_CTR_REPSET(Replica, Unjoins, 1);
  2247. DPRINT1(0, ":X: ***** UNJOINED "FORMAT_CXTION_PATH2"\n",
  2248. PRINT_CXTION_PATH2(Replica, Cxtion));
  2249. //
  2250. // Deleted cxtion
  2251. //
  2252. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2253. SetCxtionState(Cxtion, CxtionStateDeleted);
  2254. //
  2255. // Rejoin if requested.
  2256. //
  2257. } else if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_JOIN)) {
  2258. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  2259. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, TRUE);
  2260. }
  2261. } else {
  2262. FStatus = FrsErrorUnjoining;
  2263. DPRINT2(0, ":X: ***** UNJOINING "FORMAT_CXTION_PATH2" (%d cos)\n",
  2264. PRINT_CXTION_PATH2(Replica, Cxtion), Cxtion->ChangeOrderCount);
  2265. }
  2266. return FStatus;
  2267. }
  2268. ULONG
  2269. RcsForceUnjoin(
  2270. IN PREPLICA Replica,
  2271. IN PCXTION Cxtion
  2272. )
  2273. /*++
  2274. Routine Description:
  2275. Unjoin this connection.
  2276. Arguments:
  2277. Replica - ptr to replica struct for this replica set.
  2278. Cxtion - ptr to connection struct being unjoined.
  2279. Return Value:
  2280. FrsErrorStatus
  2281. --*/
  2282. {
  2283. #undef DEBSUB
  2284. #define DEBSUB "RcsForceUnjoin:"
  2285. ULONG FStatus = FrsErrorSuccess;
  2286. CHAR GuidStr[GUID_CHAR_LEN + 1];
  2287. PFRS_QUEUE CoProcessQueue = NULL;
  2288. //
  2289. // Get the table lock to sync with change order accept and the
  2290. // inbound log scanner. The outbound log process uses different
  2291. // state to control its own processing.
  2292. //
  2293. LOCK_CXTION_TABLE(Replica);
  2294. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->Flags, "Flags, RcsForceUnjoin entry");
  2295. switch (GetCxtionState(Cxtion)) {
  2296. case CxtionStateInit:
  2297. //
  2298. // ?
  2299. //
  2300. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2301. //
  2302. // Deleted cxtion
  2303. //
  2304. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2305. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2306. SetCxtionState(Cxtion, CxtionStateDeleted);
  2307. }
  2308. break;
  2309. case CxtionStateUnjoined:
  2310. //
  2311. // Unidle the change order process queue if it is blocked.
  2312. //
  2313. CoProcessQueue = Cxtion->CoProcessQueue;
  2314. Cxtion->CoProcessQueue = NULL;
  2315. //
  2316. // Unjoined; nothing to do
  2317. //
  2318. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2319. //
  2320. // Deleted cxtion
  2321. //
  2322. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2323. SetCxtionState(Cxtion, CxtionStateDeleted);
  2324. }
  2325. break;
  2326. case CxtionStateStart:
  2327. //
  2328. // Unidle the change order process queue if it is blocked.
  2329. //
  2330. CoProcessQueue = Cxtion->CoProcessQueue;
  2331. Cxtion->CoProcessQueue = NULL;
  2332. //
  2333. // Haven't had a chance to start; nothing to do
  2334. //
  2335. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2336. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2337. //
  2338. // Deleted cxtion
  2339. //
  2340. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2341. SetCxtionState(Cxtion, CxtionStateDeleted);
  2342. }
  2343. break;
  2344. case CxtionStateUnjoining:
  2345. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2346. //
  2347. // Take idle change orders through retry
  2348. //
  2349. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->ChangeOrderCount,
  2350. "COs, A-Send Idle COs to retry");
  2351. //
  2352. // Unidle the change order process queue if it is blocked.
  2353. //
  2354. CoProcessQueue = Cxtion->CoProcessQueue;
  2355. Cxtion->CoProcessQueue = NULL;
  2356. RcsDrainActiveCOsOnCxtion(Replica, Cxtion);
  2357. break;
  2358. case CxtionStateStarting:
  2359. case CxtionStateScanning:
  2360. //
  2361. // Wait for the inbound scan to finish. The change order retry
  2362. // thread or the change order accept thread will eventually unjoin us.
  2363. //
  2364. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2365. FStatus = FrsErrorUnjoining;
  2366. break;
  2367. case CxtionStateSendJoin:
  2368. case CxtionStateWaitJoin:
  2369. case CxtionStateJoined:
  2370. //
  2371. // Once we destroy our join guid, future remote change
  2372. // orders will be discarded by the replica command server
  2373. // before they show up on the change order process queue.
  2374. //
  2375. // This works because the replica command server is
  2376. // single threaded per replica; any packets received during
  2377. // this function have been enqueued for later processing.
  2378. //
  2379. // The outlog process may attempt to send change orders
  2380. // if this is an outbound cxtion but they will bounce
  2381. // because the join guid is incorrect.
  2382. //
  2383. //
  2384. // Invalidate our join guid
  2385. //
  2386. SndCsDestroyCxtion(Cxtion, 0);
  2387. SetCxtionState(Cxtion, CxtionStateUnjoining);
  2388. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2389. if (Cxtion->Inbound) {
  2390. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->ChangeOrderCount,
  2391. "COs, B-Send Idle COs to retry");
  2392. //
  2393. // Unidle the change order process queue if it is blocked.
  2394. //
  2395. CoProcessQueue = Cxtion->CoProcessQueue;
  2396. Cxtion->CoProcessQueue = NULL;
  2397. RcsDrainActiveCOsOnCxtion(Replica, Cxtion);
  2398. } else {
  2399. //
  2400. // Tell the vvjoin command server to stop
  2401. // Tell outlog process to Unjoin from this partner.
  2402. // The call is synchronous so drop the lock around the call.
  2403. //
  2404. if (Cxtion->OLCtx != NULL) {
  2405. UNLOCK_CXTION_TABLE(Replica);
  2406. SubmitVvJoinSync(Replica, Cxtion, CMD_VVJOIN_DONE_UNJOIN);
  2407. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_DEACTIVATE_PARTNER);
  2408. if (!FRS_SUCCESS(FStatus)) {
  2409. DPRINT1_FS(0, ":X: ERROR - %ws: Can't deactivate at unjoin;",
  2410. Cxtion->Name->Name, FStatus);
  2411. }
  2412. LOCK_CXTION_TABLE(Replica);
  2413. }
  2414. //
  2415. // Free the outbound version vector, if present
  2416. //
  2417. Cxtion->VVector = VVFreeOutbound(Cxtion->VVector);
  2418. //
  2419. // Invalidate the un/join guid
  2420. //
  2421. SndCsDestroyCxtion(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID);
  2422. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2423. //
  2424. // Increment the Unjoins counter for
  2425. // both the replica set and connection objects
  2426. //
  2427. PM_INC_CTR_CXTION(Cxtion, Unjoins, 1);
  2428. PM_INC_CTR_REPSET(Replica, Unjoins, 1);
  2429. DPRINT1(0, ":X: ***** UNJOINED "FORMAT_CXTION_PATH2"\n",
  2430. PRINT_CXTION_PATH2(Replica, Cxtion));
  2431. //
  2432. // :SP1: Volatile connection cleanup.
  2433. //
  2434. // Deleted cxtion or outbound volatile connection. Volatile
  2435. // connection gets deleted after the first time it UNJOINS.
  2436. //
  2437. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE) ||
  2438. VOLATILE_OUTBOUND_CXTION(Cxtion)) {
  2439. SetCxtionState(Cxtion, CxtionStateDeleted);
  2440. //
  2441. // Rejoin
  2442. //
  2443. } else if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_JOIN)) {
  2444. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  2445. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, TRUE);
  2446. }
  2447. }
  2448. break;
  2449. case CxtionStateDeleted:
  2450. //
  2451. // Unidle the change order process queue if it is blocked.
  2452. //
  2453. CoProcessQueue = Cxtion->CoProcessQueue;
  2454. Cxtion->CoProcessQueue = NULL;
  2455. //
  2456. // Deleted; nothing to do
  2457. //
  2458. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2459. break;
  2460. default:
  2461. //
  2462. // ?
  2463. //
  2464. DPRINT2(0, ":X: ERROR - bad state %d for "FORMAT_CXTION_PATH2"\n",
  2465. GetCxtionState(Cxtion), PRINT_CXTION_PATH2(Replica, Cxtion));
  2466. break;
  2467. }
  2468. UNLOCK_CXTION_TABLE(Replica);
  2469. //
  2470. // The process queue should be unidled here after releasing the cxtion
  2471. // lock to prevent deadlock. Never lock the process queue when you have the
  2472. // cxtion lock.
  2473. //
  2474. UNIDLE_CO_PROCESS_QUEUE(Replica, Cxtion, CoProcessQueue);
  2475. return FStatus;
  2476. }
  2477. BOOL
  2478. RcsSetSysvolReady(
  2479. IN DWORD NewSysvolReady
  2480. )
  2481. /*++
  2482. Routine Description:
  2483. Set the registry value for ...\netlogon\parameters\SysvolReady to
  2484. the specified value. Do nothing if the SysvolReady value is
  2485. set accordingly.
  2486. Arguments:
  2487. None.
  2488. Return Value:
  2489. TRUE - SysvolReady is set to TRUE
  2490. FALSE - State of SysvolReady is unknown
  2491. --*/
  2492. {
  2493. #undef DEBSUB
  2494. #define DEBSUB "RcsSetSysvolReady:"
  2495. DWORD WStatus;
  2496. DPRINT1(4, ":S: Setting SysvolReady to %d\n", NewSysvolReady);
  2497. //
  2498. // Restrict values to 0 or 1
  2499. //
  2500. if (NewSysvolReady) {
  2501. NewSysvolReady = 1;
  2502. }
  2503. if (CurrentSysvolReadyIsValid &&
  2504. CurrentSysvolReady == NewSysvolReady) {
  2505. DPRINT1(4, ":S: SysvolReady is already set to %d\n", NewSysvolReady);
  2506. return TRUE;
  2507. }
  2508. //
  2509. // Access the netlogon\parameters key to tell NetLogon to share the sysvol
  2510. //
  2511. WStatus = CfgRegWriteDWord(FKC_SYSVOL_READY, NULL, 0, NewSysvolReady);
  2512. CLEANUP3_WS(0, "++ ERROR - writing %ws\\%ws to %d;",
  2513. NETLOGON_SECTION, SYSVOL_READY, NewSysvolReady, WStatus, RETURN_ERROR);
  2514. CurrentSysvolReady = NewSysvolReady;
  2515. CurrentSysvolReadyIsValid = TRUE;
  2516. DPRINT1(3, ":S: SysvolReady is set to %d\n", NewSysvolReady);
  2517. //
  2518. // Report event if transitioning from 0 to 1
  2519. //
  2520. if (NewSysvolReady) {
  2521. EPRINT1(EVENT_FRS_SYSVOL_READY, ComputerName);
  2522. }
  2523. return TRUE;
  2524. RETURN_ERROR:
  2525. return FALSE;
  2526. }
  2527. VOID
  2528. RcsVvJoinDoneUnJoin(
  2529. IN PCOMMAND_PACKET Cmd
  2530. )
  2531. /*++
  2532. Routine Description:
  2533. From: Myself
  2534. The VvJoin hack has declared victory and told our inbound partner
  2535. to unjoin from us. That was VVJOIN_HACK_TIMEOUT seconds ago. By
  2536. now, our inbound partner should have unjoined from us and we can
  2537. tell dcpromo that the sysvol has been promoted.
  2538. Arguments:
  2539. Cmd
  2540. Return Value:
  2541. None.
  2542. --*/
  2543. {
  2544. #undef DEBSUB
  2545. #define DEBSUB "RcsVvJoinDoneUnJoin:"
  2546. PREPLICA Replica;
  2547. PCXTION InCxtion;
  2548. //
  2549. // Check the command packet
  2550. //
  2551. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK )) {
  2552. return;
  2553. }
  2554. Replica = RsReplica(Cmd);
  2555. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, ReplicaVvJoinDoneUnjoin entry");
  2556. //
  2557. // Find and check the cxtion
  2558. //
  2559. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2560. CHECK_CXTION_INBOUND);
  2561. if (!InCxtion) {
  2562. return;
  2563. }
  2564. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  2565. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2566. }
  2567. VOID
  2568. RcsCheckPromotion(
  2569. IN PCOMMAND_PACKET Cmd
  2570. )
  2571. /*++
  2572. Routine Description:
  2573. From: Delayed command server
  2574. Check on the process of the sysvol promotion. If there has been
  2575. no activity since the last time we checked, set the replica's
  2576. promotion state to "done with error".
  2577. Arguments:
  2578. Cmd
  2579. Return Value:
  2580. None.
  2581. --*/
  2582. {
  2583. #undef DEBSUB
  2584. #define DEBSUB "RcsCheckPromotion:"
  2585. PREPLICA Replica;
  2586. PCXTION InCxtion;
  2587. ULONG Timeout;
  2588. //
  2589. // Check the command packet
  2590. //
  2591. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  2592. return;
  2593. }
  2594. Replica = RsReplica(Cmd);
  2595. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsCheckPromotion entry");
  2596. //
  2597. // Promotion is done; ignore
  2598. //
  2599. if (Replica->NtFrsApi_ServiceState != NTFRSAPI_SERVICE_PROMOTING) {
  2600. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not promoting");
  2601. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2602. return;
  2603. }
  2604. //
  2605. // No activity in awhile, declare failure
  2606. //
  2607. if (Replica->NtFrsApi_HackCount == RsTimeout(Cmd)) {
  2608. REPLICA_STATE_TRACE(3, Cmd, Replica, FRS_ERR_SYSVOL_POPULATE_TIMEOUT,
  2609. "W, Replica promotion timed out");
  2610. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE_TIMEOUT;
  2611. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  2612. FrsCompleteCommand(Cmd, ERROR_SERVICE_SPECIFIC_ERROR);
  2613. return;
  2614. }
  2615. //
  2616. // There has been activity. Wait awhile and check again
  2617. //
  2618. CfgRegReadDWord(FKC_PROMOTION_TIMEOUT, NULL, 0, &Timeout);
  2619. RsTimeout(Cmd) = Replica->NtFrsApi_HackCount;
  2620. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, Timeout);
  2621. }
  2622. #ifndef NOVVJOINHACK
  2623. #define VVJOIN_HACK_TIMEOUT (5 * 1000)
  2624. #endif NOVVJOINHACK
  2625. VOID
  2626. RcsVvJoinDone(
  2627. IN PCOMMAND_PACKET Cmd
  2628. )
  2629. /*++
  2630. Routine Description:
  2631. From: Inbound partner
  2632. The VvJoin thread has initiated all of the change orders. This doesn't
  2633. mean that the change orders have been installed, or even received.
  2634. At this second, we are trying to get sysvols to work; we
  2635. don't really care if the vvjoin is done or not except in
  2636. the case of sysvols. Hence, the hack below.
  2637. Use the sysvol seeding hack to initiate the deleting of empty
  2638. directories in the preexisting directory.
  2639. Arguments:
  2640. Cmd
  2641. Return Value:
  2642. None.
  2643. --*/
  2644. {
  2645. #undef DEBSUB
  2646. #define DEBSUB "RcsVvJoinDone:"
  2647. PREPLICA Replica;
  2648. PCXTION InCxtion;
  2649. ULONG FStatus;
  2650. //
  2651. // Check the command packet
  2652. //
  2653. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2654. return;
  2655. }
  2656. Replica = RsReplica(Cmd);
  2657. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsVvJoinDone entry");
  2658. //
  2659. // Find and check the cxtion
  2660. //
  2661. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2662. CHECK_CXTION_INBOUND);
  2663. if (!InCxtion) {
  2664. return;
  2665. }
  2666. //
  2667. // Seeding has pretty much completed. We go ahead and hammer
  2668. // the configrecord in the DB in the hopes we don't lose this
  2669. // once-in-replica-lifetime state transition. The state is lost
  2670. // if this service restarts and none of the upstream partners
  2671. // vvjoins again.
  2672. //
  2673. // Set the incore BOOL that lets this code know the replica
  2674. // set is still seeding even though the CONFIG_FLAG_SEEDING
  2675. // bit is off. And yes, this is by design. The incore flag
  2676. // is enabled iff the DB state was updated successfully.
  2677. //
  2678. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  2679. ClearCxtionFlag(InCxtion, CXTION_FLAGS_INIT_SYNC);
  2680. FStatus = OutLogSubmit(Replica, InCxtion, CMD_OUTLOG_UPDATE_PARTNER);
  2681. CXTION_STATE_TRACE(3, InCxtion, Replica, FStatus, "F, OUTLOG_UPDATE_PARTNER return");
  2682. if (!FRS_SUCCESS(FStatus)) {
  2683. DPRINT3(0, "++ WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  2684. InCxtion->Name->Name, InCxtion->Partner->Name, Replica->ReplicaName->Name);
  2685. }
  2686. }
  2687. //
  2688. // First time; wait a bit and retry
  2689. //
  2690. #ifndef NOVVJOINHACK
  2691. if (!RsTimeout(Cmd)) {
  2692. Replica->NtFrsApi_HackCount++; // != 0
  2693. RsTimeout(Cmd) = Replica->NtFrsApi_HackCount;
  2694. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, VVJOIN_HACK_TIMEOUT);
  2695. return;
  2696. }
  2697. //
  2698. // There as been no activity on this cxtion for awhile after the
  2699. // vvjoin done was received. Declare success. Tell our upstream
  2700. // partner to discard the volatile cxtion. Update the database
  2701. // if it hasn't already been updated. If updated successfully,
  2702. // inform NetLogon that it is time to share the sysvol.
  2703. //
  2704. if (RsTimeout(Cmd) == Replica->NtFrsApi_HackCount) {
  2705. //
  2706. // VVJOIN DONE
  2707. //
  2708. //
  2709. // Send this command to the initial sync command server for further
  2710. // processing if we are in seeding state.
  2711. //
  2712. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  2713. InitSyncCsSubmitTransfer(Cmd, CMD_INITSYNC_VVJOIN_DONE);
  2714. } else {
  2715. Cmd->Command = CMD_VVJOIN_DONE_UNJOIN;
  2716. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  2717. }
  2718. } else {
  2719. //
  2720. // VVJOIN IN PROGRESS
  2721. //
  2722. RsTimeout(Cmd) = Replica->NtFrsApi_HackCount;
  2723. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, VVJOIN_HACK_TIMEOUT);
  2724. }
  2725. #endif NOVVJOINHACK
  2726. }
  2727. VOID
  2728. RcsVvJoinSuccess(
  2729. IN PCOMMAND_PACKET Cmd
  2730. )
  2731. /*++
  2732. Routine Description:
  2733. Type: Local
  2734. From: VvJoin Thread
  2735. Change the state of the oubound cxtion from VVJOINING to JOINED and
  2736. tell the outbound partner that the vvjoin thread is done.
  2737. Arguments:
  2738. Cmd
  2739. Return Value:
  2740. None.
  2741. --*/
  2742. {
  2743. #undef DEBSUB
  2744. #define DEBSUB "RcsVvJoinSuccess:"
  2745. PREPLICA Replica;
  2746. PCXTION OutCxtion;
  2747. PCOMM_PACKET CPkt;
  2748. //
  2749. // Check the command packet
  2750. //
  2751. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2752. return;
  2753. }
  2754. Replica = RsReplica(Cmd);
  2755. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsVvJoinSuccess entry");
  2756. //
  2757. // Find and check the cxtion
  2758. //
  2759. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2760. CHECK_CXTION_OUTBOUND);
  2761. if (!OutCxtion) {
  2762. return;
  2763. }
  2764. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_VVJOIN_DONE, NULL, NULL, NULL);
  2765. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  2766. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2767. }
  2768. VOID
  2769. RcsHungCxtion(
  2770. IN PCOMMAND_PACKET Cmd
  2771. )
  2772. /*++
  2773. Routine Description:
  2774. From: Local OutLog Command Server
  2775. The outlog command server has detected a wrapped ack vector. This
  2776. may have been caused by a lost ack. In any case, check the progress
  2777. of the change orders by examining the the ack vector, the trailing
  2778. index, and the count of comm packets.
  2779. A cxtion is hung if it is wrapped and both the trailing index and
  2780. the number of comm packets received remains unchanged for
  2781. CommTimeoutInMilliSeconds (~5 minutes). In that case, the cxtion
  2782. is unjoined.
  2783. If the trailing index remains unchanged but comm packets are
  2784. being received then the timeout is reset to another
  2785. CommTimeoutInMilliSeconds interval.
  2786. If the cxtion appears un-hung, the command packet is completed.
  2787. Arguments:
  2788. Cmd
  2789. Return Value:
  2790. None.
  2791. --*/
  2792. {
  2793. #undef DEBSUB
  2794. #define DEBSUB "RcsHungCxtion:"
  2795. PREPLICA Replica;
  2796. PCXTION OutCxtion;
  2797. //
  2798. // Check the command packet
  2799. //
  2800. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2801. return;
  2802. }
  2803. Replica = RsReplica(Cmd);
  2804. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsHungCxtion entry");
  2805. //
  2806. // Find and check the cxtion
  2807. //
  2808. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2809. CHECK_CXTION_OUTBOUND);
  2810. if (!OutCxtion) {
  2811. return;
  2812. }
  2813. DPRINT1(4, ":X: Check Hung Cxtion for "FORMAT_CXTION_PATH2"\n",
  2814. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2815. //
  2816. // No out log context; can't be hung
  2817. //
  2818. if (!OutCxtion->OLCtx) {
  2819. DPRINT1(4, "++ No partner context for "FORMAT_CXTION_PATH2"\n",
  2820. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2821. FrsCompleteCommand(Cmd, ERROR_INVALID_PARAMETER);
  2822. return;
  2823. }
  2824. //
  2825. // No longer wrapped; not hung
  2826. //
  2827. if (!AVWrapped(OutCxtion->OLCtx)) {
  2828. DPRINT1(4, "++ No longer wrapped for "FORMAT_CXTION_PATH2"\n",
  2829. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2830. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2831. return;
  2832. }
  2833. //
  2834. // AV is not wrapped at the same trailing index; not hung
  2835. //
  2836. if (OutCxtion->OLCtx->COTx != RsCOTx(Cmd)) {
  2837. DPRINT3(4, "++ COTx is %d; not %d for "FORMAT_CXTION_PATH2"\n",
  2838. OutCxtion->OLCtx->COTx,
  2839. RsCOTx(Cmd), PRINT_CXTION_PATH2(Replica, OutCxtion));
  2840. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2841. return;
  2842. }
  2843. //
  2844. // Some comm pkts have shown up from the downstream partner,
  2845. // may not be hung. Check again later.
  2846. //
  2847. if (OutCxtion->CommPkts != RsCommPkts(Cmd)) {
  2848. DPRINT3(4, "++ CommPkts is %d; not %d for "FORMAT_CXTION_PATH2"\n",
  2849. OutCxtion->CommPkts,
  2850. RsCommPkts(Cmd), PRINT_CXTION_PATH2(Replica, OutCxtion));
  2851. RsCommPkts(Cmd) = OutCxtion->CommPkts;
  2852. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CommTimeoutInMilliSeconds);
  2853. } else {
  2854. DPRINT1(4, "++ WARN - Unjoin; cxtion is hung "FORMAT_CXTION_PATH2"\n",
  2855. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2856. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  2857. }
  2858. return;
  2859. }
  2860. VOID
  2861. RcsDeleteCxtionFromReplica(
  2862. IN PREPLICA Replica,
  2863. IN PCXTION Cxtion
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. Common subroutine that synchronously deletes the cxtion from the
  2868. database and then removes it from the replica's table of cxtions.
  2869. The caller is responsible for insuring that this operation is
  2870. appropriate (cxtion exists, appropriate locks are held, ...)
  2871. Arguments:
  2872. Replica
  2873. Cxtion
  2874. Return Value:
  2875. TRUE - replica set was altered
  2876. FALSE - replica is unaltered
  2877. --*/
  2878. {
  2879. #undef DEBSUB
  2880. #define DEBSUB "RcsDeleteCxtionFromReplica:"
  2881. ULONG FStatus;
  2882. //
  2883. // Delete the cxtion from the database and then remove it from
  2884. // the replica's table of cxtions. Keep it in the table of
  2885. // deleted cxtions because change orders may contain the address
  2886. // of this cxtion.
  2887. //
  2888. DPRINT1(4, ":X: Deleting cxtion from Db: "FORMAT_CXTION_PATH2"\n",
  2889. PRINT_CXTION_PATH2(Replica, Cxtion));
  2890. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Deleting cxtion from Db");
  2891. //
  2892. // Must be in the deleted state to be deleted
  2893. //
  2894. if (!CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  2895. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, ERROR Cxtion state not deleted");
  2896. return;
  2897. }
  2898. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_REMOVE_PARTNER);
  2899. if (!FRS_SUCCESS(FStatus)) {
  2900. CXTION_STATE_TRACE(0, Cxtion, Replica, FStatus, "F, Warn: Del cxtion failed");
  2901. DPRINT1(0, "++ WARN Could not delete cxtion: "FORMAT_CXTION_PATH2"\n",
  2902. PRINT_CXTION_PATH2(Replica, Cxtion));
  2903. }
  2904. if (FRS_SUCCESS(FStatus)) {
  2905. DPRINT1(4, "++ Deleting cxtion from table: "FORMAT_CXTION_PATH2"\n",
  2906. PRINT_CXTION_PATH2(Replica, Cxtion));
  2907. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Deleting cxtion GenTab");
  2908. GTabDelete(Replica->Cxtions, Cxtion->Name->Guid, NULL, NULL);
  2909. //
  2910. // Remove the connection from the perfmon tables so we stop returning
  2911. // data and allow a new connection with the same name to be established.
  2912. //
  2913. DeletePerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData);
  2914. GTabInsertEntry(DeletedCxtions, Cxtion, Cxtion->Name->Guid, NULL);
  2915. }
  2916. }
  2917. VOID
  2918. RcsUnJoinCxtion(
  2919. IN PCOMMAND_PACKET Cmd,
  2920. IN BOOL RemoteUnJoin
  2921. )
  2922. /*++
  2923. Routine Description:
  2924. A comm pkt could not be sent to a cxtion's partner. Unjoin the
  2925. cxtion and periodically retry the join unless the cxtion is
  2926. joined and volatile. In that case, delete the cxtion because
  2927. our partner is unlikely to be able to rejoin with us (volatile
  2928. cxtions are lost at restart).
  2929. Arguments:
  2930. Cmd
  2931. RemoteUnJoin - Check authentication if remote
  2932. Return Value:
  2933. None.
  2934. --*/
  2935. {
  2936. #undef DEBSUB
  2937. #define DEBSUB "RcsUnJoinCxtion:"
  2938. ULONG FStatus;
  2939. PREPLICA Replica;
  2940. PCXTION Cxtion;
  2941. BOOL CxtionWasJoined;
  2942. //
  2943. // Check the command packet
  2944. //
  2945. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2946. return;
  2947. }
  2948. Replica = RsReplica(Cmd);
  2949. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsUnJoinCxtion entry");
  2950. //
  2951. // Abort promotion; if any
  2952. //
  2953. // We no longer seed during dcpromo so a unjoin during seeding means that the
  2954. // volatile connection has timed out (on upstream) because of no activity for
  2955. // some time (default 30 minutes). The vvjoin will finish over the new connection
  2956. // or the volatile connection will be re-established when the seeding downstream
  2957. // partner comes back up.
  2958. //
  2959. if (Replica->NtFrsApi_ServiceState == NTFRSAPI_SERVICE_PROMOTING) {
  2960. DPRINT1(4, ":X: Promotion aborted: unjoin for %ws.\n", Replica->SetName->Name);
  2961. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE;
  2962. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  2963. }
  2964. //
  2965. // Find and check the cxtion
  2966. //
  2967. Cxtion = RcsCheckCxtion(Cmd, DEBSUB,
  2968. CHECK_CXTION_EXISTS |
  2969. CHECK_CXTION_UNJOINGUID |
  2970. ((RemoteUnJoin) ? CHECK_CXTION_AUTH : 0) |
  2971. ((RemoteUnJoin) ? CHECK_CXTION_PARTNER : 0));
  2972. if (!Cxtion) {
  2973. return;
  2974. }
  2975. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->Flags, "Flags, RcsUnJoinCxtion entry");
  2976. //
  2977. // The call to RcsForceUnjoin may alter the cxtion state.
  2978. // Retry the join later. Don't retry if the cxtion isn't
  2979. // joined because there are other retry mechanisms covering
  2980. // that case.
  2981. //
  2982. LOCK_CXTION_TABLE(Replica);
  2983. CxtionWasJoined = CxtionStateIs(Cxtion, CxtionStateJoined);
  2984. if (!FrsIsShuttingDown &&
  2985. CxtionWasJoined &&
  2986. !CxtionFlagIs(Cxtion, CXTION_FLAGS_VOLATILE) &&
  2987. !CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) &&
  2988. !RemoteUnJoin &&
  2989. IS_TIME_ZERO(Replica->MembershipExpires)) {
  2990. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  2991. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Cxtion is DEFERRED_JOIN");
  2992. }
  2993. UNLOCK_CXTION_TABLE(Replica);
  2994. FStatus = RcsForceUnjoin(Replica, Cxtion);
  2995. CXTION_STATE_TRACE(3, Cxtion, Replica, FStatus, "F, RcsForceUnjoin return");
  2996. if (!FRS_SUCCESS(FStatus)) {
  2997. FrsCompleteCommand(Cmd, ERROR_REQUEST_ABORTED);
  2998. return;
  2999. }
  3000. //
  3001. // Delete the volatile cxtion if it was previously joined because
  3002. // there is no recovery for a failed sysvol seeding operation. Or
  3003. // if our downstream partner requested the unjoin.
  3004. //
  3005. if (!FrsIsShuttingDown &&
  3006. CxtionFlagIs(Cxtion, CXTION_FLAGS_VOLATILE) &&
  3007. (CxtionWasJoined || RemoteUnJoin)) {
  3008. RcsDeleteCxtionFromReplica(Replica, Cxtion);
  3009. }
  3010. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3011. }
  3012. VOID
  3013. RcsInboundJoined(
  3014. IN PCOMMAND_PACKET Cmd
  3015. )
  3016. /*++
  3017. Routine Description:
  3018. An inbound partner sent a JOINED command as a response to our join request.
  3019. JoinGuid may not match because we are seeing an old response after a timeout
  3020. on our end caused us to retry the join request (so the Guid changed).
  3021. The cxtion state should be JOINING but it could be JOINED if this is a
  3022. duplicate response. If we timed out and gave up and/or restarted the
  3023. entire Join sequence from the REQUEST_START state when a join response
  3024. finally arrives the JoinGuid won't match and the response is ignored.
  3025. Arguments:
  3026. Cmd
  3027. Return Value:
  3028. None.
  3029. --*/
  3030. {
  3031. #undef DEBSUB
  3032. #define DEBSUB "RcsInboundJoined:"
  3033. PCXTION InCxtion;
  3034. ULONG FStatus;
  3035. PREPLICA Replica;
  3036. PFRS_QUEUE CoProcessQueue = NULL;
  3037. //
  3038. // Check the command packet
  3039. //
  3040. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  3041. return;
  3042. }
  3043. Replica = RsReplica(Cmd);
  3044. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsInboundJoined entry");
  3045. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3046. CHECK_CXTION_INBOUND |
  3047. CHECK_CXTION_AUTH |
  3048. CHECK_CXTION_PARTNER |
  3049. CHECK_CXTION_JOINGUID);
  3050. if (!InCxtion) {
  3051. return;
  3052. }
  3053. //
  3054. // Shutting down; ignore join request
  3055. //
  3056. if (FrsIsShuttingDown) {
  3057. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, FrsIsShuttingDown");
  3058. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  3059. return;
  3060. }
  3061. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsInboundJoined entry");
  3062. //
  3063. // Increment the Join Notifications Received counter for
  3064. // both the replica set and connection objects
  3065. //
  3066. PM_INC_CTR_CXTION(InCxtion, JoinNRcvd, 1);
  3067. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  3068. //
  3069. // Update the LastJoinedTime in our connection record for use in the next
  3070. // Join request. The following call is synchronous. Can't hold the
  3071. // cxtion table lock across this call.
  3072. //
  3073. if (RsLastJoinTime(Cmd) != InCxtion->LastJoinTime) {
  3074. InCxtion->LastJoinTime = RsLastJoinTime(Cmd);
  3075. FStatus = OutLogSubmit(Replica, InCxtion, CMD_OUTLOG_UPDATE_PARTNER);
  3076. if (!FRS_SUCCESS(FStatus)) {
  3077. DPRINT3(0, ":X: WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  3078. InCxtion->Name->Name,
  3079. InCxtion->Partner->Name, Replica->ReplicaName->Name);
  3080. }
  3081. }
  3082. //
  3083. // Join complete; unidle the change order process queue
  3084. //
  3085. if (CxtionStateIs(InCxtion, CxtionStateWaitJoin)) {
  3086. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, JOINED");
  3087. LOCK_CXTION_TABLE(Replica);
  3088. SET_JOINED(Replica, InCxtion, "JOINED ");
  3089. CoProcessQueue = InCxtion->CoProcessQueue;
  3090. InCxtion->CoProcessQueue = NULL;
  3091. SET_UNJOIN_TRIGGER(InCxtion);
  3092. UNLOCK_CXTION_TABLE(Replica);
  3093. //
  3094. // The process queue should be unidled here after releasing the cxtion
  3095. // lock to prevent deadlock. Never lock the process queue when you have the
  3096. // cxtion lock.
  3097. //
  3098. UNIDLE_CO_PROCESS_QUEUE(Replica, InCxtion, CoProcessQueue);
  3099. } else {
  3100. //
  3101. // Increment the Joins counter for both the replica set and cxtion objects
  3102. //
  3103. PM_INC_CTR_CXTION(InCxtion, Joins, 1);
  3104. PM_INC_CTR_REPSET(Replica, Joins, 1);
  3105. DPRINT1(0, ":X: ***** REJOINED "FORMAT_CXTION_PATH2"\n",
  3106. PRINT_CXTION_PATH2(Replica, InCxtion));
  3107. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, REJOINED");
  3108. }
  3109. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3110. }
  3111. VOID
  3112. RcsRemoteCoDoneRvcd(
  3113. IN PCOMMAND_PACKET Cmd
  3114. )
  3115. /*++
  3116. Routine Description:
  3117. Our outbound partner has completed processing this change order.
  3118. Arguments:
  3119. Cmd
  3120. Return Value:
  3121. None.
  3122. --*/
  3123. {
  3124. #undef DEBSUB
  3125. #define DEBSUB "RcsRemoteCoDoneRvcd:"
  3126. ULONGLONG AckVersion;
  3127. PREPLICA Replica;
  3128. PCXTION OutCxtion;
  3129. POUT_LOG_PARTNER OutLogPartner;
  3130. //
  3131. // Check the command packet
  3132. //
  3133. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_PARTNERCOC)) {
  3134. return;
  3135. }
  3136. Replica = RsReplica(Cmd);
  3137. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRemoteCoDoneRvcd entry");
  3138. CHANGE_ORDER_COMMAND_TRACE(3, RsPartnerCoc(Cmd), "Command Remote CO Done");
  3139. //
  3140. // Find and check the cxtion
  3141. //
  3142. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3143. CHECK_CXTION_OUTBOUND |
  3144. CHECK_CXTION_JOINED |
  3145. CHECK_CXTION_JOINGUID |
  3146. CHECK_CXTION_AUTH);
  3147. if (!OutCxtion) {
  3148. return;
  3149. }
  3150. FRS_CO_COMM_PROGRESS(3, RsPartnerCoc(Cmd), RsCoSn(Cmd),
  3151. OutCxtion->PartSrvName, "Remote Co Done");
  3152. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Remote Co Done");
  3153. //
  3154. // Update the outbound cxtion's version vector with the
  3155. // version (guid, vsn) supplied by the outbound partner
  3156. //
  3157. VVUpdateOutbound(OutCxtion->VVector, RsGVsn(Cmd));
  3158. RsGVsn(Cmd) = NULL;
  3159. //
  3160. // Check if this Ack is for a previous generation of the the Ack Vector
  3161. // and if it is just ignore it. Test for zero means that this is an old
  3162. // rev CO that was not sent with an AckVersion so skip the test.
  3163. // If we accept an ACK for a CO sent out with an old version of the Ack
  3164. // vector the effect will be to either accept an Ack for the wrong CO or
  3165. // mark the ack vector for a CO that has not yet been sent. The latter
  3166. // can later lead to an assert if the connection is now out of the
  3167. // VVJoin state.
  3168. //
  3169. OutLogPartner = OutCxtion->OLCtx;
  3170. AckVersion = RsPartnerCoc(Cmd)->AckVersion;
  3171. if ((AckVersion != 0) && (AckVersion != OutLogPartner->AckVersion)) {
  3172. CHANGE_ORDER_COMMAND_TRACE(3, RsPartnerCoc(Cmd), "Stale AckVersion - ignore");
  3173. return;
  3174. }
  3175. //
  3176. // Tell Outbound Log this CO for this connection is retired.
  3177. //
  3178. OutLogRetireCo(Replica, RsCoSn(Cmd), OutCxtion);
  3179. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3180. }
  3181. VOID
  3182. RcsSendRemoteCoDone(
  3183. IN PREPLICA Replica,
  3184. IN PCHANGE_ORDER_COMMAND Coc
  3185. )
  3186. /*++
  3187. Routine Description:
  3188. Tell our inbound partner that the change order is done
  3189. Arguments:
  3190. Replica
  3191. Coc
  3192. Return Value:
  3193. None.
  3194. --*/
  3195. {
  3196. #undef DEBSUB
  3197. #define DEBSUB "RcsSendRemoteCoDone:"
  3198. PCOMMAND_PACKET Cmd;
  3199. PCXTION InCxtion;
  3200. PCOMM_PACKET CPkt;
  3201. #ifndef NOVVJOINHACK
  3202. Replica->NtFrsApi_HackCount++;
  3203. #endif NOVVJOINHACK
  3204. //
  3205. // Return the (guid,vsn) and the co guid for this change order
  3206. //
  3207. Cmd = FrsAllocCommand(NULL, CMD_REMOTE_CO_DONE);
  3208. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  3209. RsGVsn(Cmd) = VVGetGVsn(Replica->VVector, &Coc->OriginatorGuid);
  3210. RsCoGuid(Cmd) = FrsDupGuid(&Coc->ChangeOrderGuid);
  3211. RsCoSn(Cmd) = Coc->PartnerAckSeqNumber;
  3212. //
  3213. // Find and check the cxtion
  3214. //
  3215. RsReplica(Cmd) = Replica;
  3216. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coc->CxtionGuid), NULL);
  3217. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3218. CHECK_CXTION_INBOUND |
  3219. CHECK_CXTION_JOINED);
  3220. if (!InCxtion) {
  3221. return;
  3222. }
  3223. //
  3224. // Only needed for the call to RcsCheckCxtion above.
  3225. //
  3226. RsCxtion(Cmd) = FrsFreeGName(RsCxtion(Cmd));
  3227. RsReplica(Cmd) = NULL;
  3228. //
  3229. // Tell our inbound partner that the remote CO is done
  3230. //
  3231. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Send REMOTE_CO_DONE");
  3232. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_REMOTE_CO_DONE, NULL, Cmd, Coc);
  3233. SndCsSubmitCommPkt2(Replica, InCxtion, NULL, FALSE, CPkt);
  3234. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3235. }
  3236. VOID
  3237. RcsInboundCommitOk(
  3238. IN PREPLICA Replica,
  3239. IN PCHANGE_ORDER_ENTRY Coe
  3240. )
  3241. /*++
  3242. Routine Description:
  3243. The change order has been retired; inform our inbound partner
  3244. Arguments:
  3245. Replica
  3246. Coe
  3247. Return Value:
  3248. None.
  3249. --*/
  3250. {
  3251. #undef DEBSUB
  3252. #define DEBSUB "RcsInboundCommitOk:"
  3253. PCHANGE_ORDER_COMMAND Coc = &Coe->Cmd;
  3254. #ifndef NOVVJOINHACK
  3255. Replica->NtFrsApi_HackCount++;
  3256. #endif NOVVJOINHACK
  3257. DPRINT2(4, "++ Commit the retire on %s co for %ws\n",
  3258. CO_FLAG_ON(Coe, CO_FLAG_LOCALCO) ? "Local" : "Remote", Coc->FileName);
  3259. //
  3260. // Tell our inbound partner that we are done with the change order
  3261. //
  3262. if (!CO_FLAG_ON(Coe, CO_FLAG_LOCALCO)) {
  3263. RcsSendRemoteCoDone(Replica, Coc);
  3264. }
  3265. }
  3266. BOOL
  3267. RcsSendCoToOneOutbound(
  3268. IN PREPLICA Replica,
  3269. IN PCXTION Cxtion,
  3270. IN PCHANGE_ORDER_COMMAND Coc
  3271. )
  3272. /*++
  3273. Routine Description:
  3274. Send the change order to one outbound cxtion
  3275. Arguments:
  3276. Replica
  3277. Cxtion
  3278. Coc
  3279. Return Value:
  3280. None.
  3281. --*/
  3282. {
  3283. #undef DEBSUB
  3284. #define DEBSUB "RcsSendCoToOneOutbound:"
  3285. ULONG OrigFlags;
  3286. PCOMM_PACKET CPkt;
  3287. BOOL RestoreOldParent = FALSE;
  3288. BOOL RestoreNewParent = FALSE;
  3289. //
  3290. // Must be a joined, outbound cxtion
  3291. //
  3292. FRS_ASSERT(!Cxtion->Inbound);
  3293. //
  3294. // Don't send a change order our outbound partner has seen
  3295. //
  3296. if (VVHasVsn(Cxtion->VVector, Coc)) {
  3297. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Dampen Send VV");
  3298. return FALSE;
  3299. }
  3300. //
  3301. // Don't send a change order to its originator unless
  3302. // this is a vvjoin change order that isn't in the
  3303. // originator's version vector.
  3304. //
  3305. if ((!COC_FLAG_ON(Coc, CO_FLAG_VVJOIN_TO_ORIG)) &&
  3306. GUIDS_EQUAL(&Cxtion->ReplicaVersionGuid, &Coc->OriginatorGuid)) {
  3307. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Dampen Send Originator");
  3308. return FALSE;
  3309. }
  3310. //
  3311. // Send the change order to our outbound partner
  3312. //
  3313. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Sending");
  3314. //
  3315. // We don't know the value of our partner's root guid. Instead,
  3316. // we substitute the value of our partner's guid. Our partner
  3317. // will substitute the correct value for its root guid when
  3318. // our partner detects our substitution.
  3319. //
  3320. if (GUIDS_EQUAL(&Coc->OldParentGuid, Replica->ReplicaRootGuid)) {
  3321. RestoreOldParent = TRUE;
  3322. COPY_GUID(&Coc->OldParentGuid, Cxtion->Partner->Guid);
  3323. }
  3324. if (GUIDS_EQUAL(&Coc->NewParentGuid, Replica->ReplicaRootGuid)) {
  3325. RestoreNewParent = TRUE;
  3326. COPY_GUID(&Coc->NewParentGuid, Cxtion->Partner->Guid);
  3327. }
  3328. //
  3329. // A change order can be directed to only one outbound cxtion. Once
  3330. // the change order goes across the wire it is no longer "directed"
  3331. // to an outbound cxtion. So, turn off the flag before it is sent.
  3332. //
  3333. OrigFlags = Coc->Flags;
  3334. CLEAR_COC_FLAG(Coc, CO_FLAG_DIRECTED_CO);
  3335. CPkt = CommBuildCommPkt(Replica, Cxtion, CMD_REMOTE_CO, NULL, NULL, Coc);
  3336. //
  3337. // Restore the root guids substituted above
  3338. //
  3339. if (RestoreOldParent) {
  3340. COPY_GUID(&Coc->OldParentGuid, Replica->ReplicaRootGuid);
  3341. }
  3342. if (RestoreNewParent) {
  3343. COPY_GUID(&Coc->NewParentGuid, Replica->ReplicaRootGuid);
  3344. }
  3345. //
  3346. // Restore the flags
  3347. //
  3348. SET_COC_FLAG(Coc, OrigFlags);
  3349. SndCsSubmitCommPkt2(Replica, Cxtion, NULL, FALSE, CPkt);
  3350. return TRUE;
  3351. }
  3352. VOID
  3353. RcsReceivedStageFile(
  3354. IN PCOMMAND_PACKET Cmd,
  3355. IN ULONG AdditionalCxtionChecks
  3356. )
  3357. /*++
  3358. Routine Description:
  3359. An outbound partner is sending a staging file to this inbound cxtion.
  3360. Request more if needed.
  3361. Arguments:
  3362. Cmd
  3363. AdditionalReplicaChecks
  3364. Return Value:
  3365. None.
  3366. --*/
  3367. {
  3368. #undef DEBSUB
  3369. #define DEBSUB "RcsReceivedStageFile:"
  3370. PCXTION InCxtion;
  3371. PREPLICA Replica;
  3372. PCHANGE_ORDER_ENTRY Coe;
  3373. PCHANGE_ORDER_COMMAND Coc;
  3374. PCOMM_PACKET CPkt;
  3375. ULONG Flags;
  3376. ULONG WStatus;
  3377. //
  3378. // Check the command packet
  3379. //
  3380. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_COE)) {
  3381. return;
  3382. }
  3383. Replica = RsReplica(Cmd);
  3384. Coe = RsCoe(Cmd);
  3385. Coc = RsCoc(Cmd);
  3386. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsReceivedStageFile entry");
  3387. CHANGE_ORDER_TRACEXP(3, Coe, "Replica received stage", Cmd);
  3388. #ifndef NOVVJOINHACK
  3389. Replica->NtFrsApi_HackCount++;
  3390. #endif NOVVJOINHACK
  3391. //
  3392. // *Note*
  3393. // Perf: Clean this up when the whole RCS, FETCS, STAGE_GEN_CS design is redone - Davidor.
  3394. //
  3395. // This bypass is needed because some of the callers want to make an
  3396. // authentication check on the received data fetch packet. In the case of an
  3397. // MD5 match where the MD5 checksum is supplied with the Change Order
  3398. // there is no authentication info to check so this check fails and causes
  3399. // the connection to unjoin and sends the CO thru retry. This makes the
  3400. // VVJoin real slow. This also skips over the perfmon fetch counters which
  3401. // is good since there was no fetch.
  3402. //
  3403. if (COE_FLAG_ON(Coe, COE_FLAG_PRE_EXIST_MD5_MATCH)) {
  3404. CHANGE_ORDER_TRACE(3, Coe, "MD5 Match Bypass");
  3405. //
  3406. // We can't skip the below because we need to check the staging
  3407. // file flags for STAGE_FLAG_DATA_PRESENT. If that is clear we need
  3408. // to pass this friggen cmd pkt to the FetchCs to do the final stage file
  3409. // reanme. So instead clear the CHECK_CXTION_AUTH flag to avoid bogus
  3410. // cxtion unjoins. This stinks.
  3411. //
  3412. ClearFlag(AdditionalCxtionChecks, CHECK_CXTION_AUTH);
  3413. // goto FETCH_IS_DONE;
  3414. }
  3415. //
  3416. // Find and check the cxtion
  3417. //
  3418. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3419. CHECK_CXTION_INBOUND |
  3420. AdditionalCxtionChecks);
  3421. if (!InCxtion) {
  3422. return;
  3423. }
  3424. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsReceivedStageFile entry");
  3425. //
  3426. // If there is more staging file to fetch, go fetch it!
  3427. //
  3428. if (RsFileOffset(Cmd).QuadPart < RsFileSize(Cmd).QuadPart) {
  3429. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Send more stage");
  3430. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_SEND_STAGE, NULL, Cmd, Coc);
  3431. SndCsSubmitCommPkt2(Replica, InCxtion, Coe, TRUE, CPkt);
  3432. RsCoe(Cmd) = NULL;
  3433. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3434. return;
  3435. } else {
  3436. if (FrsDoesCoNeedStage(Coc)) {
  3437. //
  3438. // Even though all the data has been delivered the staging file rename
  3439. // may not have completed. E.g. a sharing violation on final rename.
  3440. // If so then send the cmd back to the Fetch CS to finish up.
  3441. //
  3442. Flags = STAGE_FLAG_EXCLUSIVE;
  3443. WStatus = StageAcquire(&Coc->ChangeOrderGuid,
  3444. Coc->FileName,
  3445. Coc->FileSize,
  3446. &Flags,
  3447. NULL);
  3448. if (WIN_RETRY_FETCH(WStatus)) {
  3449. //
  3450. // Retriable problem
  3451. //
  3452. CHANGE_ORDER_TRACEW(3, Coe, "Send to Fetch Retry", WStatus);
  3453. FrsFetchCsSubmitTransfer(Cmd, CMD_RETRY_FETCH);
  3454. return;
  3455. }
  3456. if (!WIN_SUCCESS(WStatus)) {
  3457. //
  3458. // Unrecoverable error; abort
  3459. //
  3460. CHANGE_ORDER_TRACEW(0, Coe, "Send to fetch abort", WStatus);
  3461. FrsFetchCsSubmitTransfer(Cmd, CMD_ABORT_FETCH);
  3462. return;
  3463. }
  3464. StageRelease(&Coc->ChangeOrderGuid, Coc->FileName, 0, NULL, NULL);
  3465. //
  3466. // Now check if we still need to finish the rename.
  3467. //
  3468. if (!(Flags & STAGE_FLAG_DATA_PRESENT)) {
  3469. FrsFetchCsSubmitTransfer(Cmd, CMD_RECEIVING_STAGE);
  3470. return;
  3471. }
  3472. }
  3473. //
  3474. // Increment the staging files fetched counter for the replica set.
  3475. //
  3476. PM_INC_CTR_REPSET(Replica, SFFetched, 1);
  3477. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Stage fetch complete");
  3478. }
  3479. //
  3480. // Increment the Fetch Requests Files Received counter for
  3481. // both the replica set and connection objects
  3482. //
  3483. PM_INC_CTR_CXTION(InCxtion, FetRReceived, 1);
  3484. PM_INC_CTR_REPSET(Replica, FetRReceived, 1);
  3485. //
  3486. // Display info for dcpromo during sysvol seeding.
  3487. // We don't seed during dcpromo anymore so we don't need to
  3488. // display any progress information.
  3489. //
  3490. // if (!Replica->NtFrsApi_ServiceDisplay) {
  3491. // Replica->NtFrsApi_ServiceDisplay = FrsWcsDup(Coc->FileName);
  3492. // }
  3493. // FETCH_IS_DONE:
  3494. //
  3495. // Installing the fetched staging file
  3496. //
  3497. SET_CHANGE_ORDER_STATE(Coe, IBCO_FETCH_COMPLETE);
  3498. SET_CHANGE_ORDER_STATE(Coe, IBCO_INSTALL_INITIATED);
  3499. //
  3500. // Install the staging file.
  3501. //
  3502. FrsInstallCsSubmitTransfer(Cmd, CMD_INSTALL_STAGE);
  3503. }
  3504. VOID
  3505. RcsRetryFetch(
  3506. IN PCOMMAND_PACKET Cmd
  3507. )
  3508. /*++
  3509. Routine Description:
  3510. Our inbound partner has requested that we retry fetching the staging
  3511. file at a later time.
  3512. Arguments:
  3513. Cmd
  3514. Return Value:
  3515. None.
  3516. --*/
  3517. {
  3518. #undef DEBSUB
  3519. #define DEBSUB "RcsRetryFetch:"
  3520. PCXTION InCxtion;
  3521. PREPLICA Replica;
  3522. //
  3523. // Check the command packet
  3524. //
  3525. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK | CHECK_CMD_COE)) {
  3526. return;
  3527. }
  3528. Replica = RsReplica(Cmd);
  3529. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRetryFetch entry");
  3530. CHANGE_ORDER_TRACEXP(3, RsCoe(Cmd), "Replica retry fetch", Cmd);
  3531. #ifndef NOVVJOINHACK
  3532. RsReplica(Cmd)->NtFrsApi_HackCount++;
  3533. #endif NOVVJOINHACK
  3534. //
  3535. // Find and check the cxtion
  3536. //
  3537. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3538. CHECK_CXTION_INBOUND |
  3539. CHECK_CXTION_AUTH);
  3540. if (!InCxtion) {
  3541. return;
  3542. }
  3543. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_RETRY_FETCH");
  3544. FrsFetchCsSubmitTransfer(Cmd, CMD_RETRY_FETCH);
  3545. }
  3546. VOID
  3547. RcsAbortFetch(
  3548. IN PCOMMAND_PACKET Cmd
  3549. )
  3550. /*++
  3551. Routine Description:
  3552. Our inbound partner has requested that we abort the fetch.
  3553. It could be out of disk space, out of disk quota or it may
  3554. not have the original file to create the staging file.
  3555. Arguments:
  3556. Cmd
  3557. Return Value:
  3558. None.
  3559. --*/
  3560. {
  3561. #undef DEBSUB
  3562. #define DEBSUB "RcsAbortFetch:"
  3563. PCXTION InCxtion;
  3564. PREPLICA Replica;
  3565. PCHANGE_ORDER_ENTRY Coe;
  3566. //
  3567. // Check the command packet
  3568. //
  3569. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK | CHECK_CMD_COE)) {
  3570. return;
  3571. }
  3572. Replica = RsReplica(Cmd);
  3573. Coe = RsCoe(Cmd);
  3574. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsAbortFetch entry");
  3575. CHANGE_ORDER_TRACEXP(3, Coe, "Replica abort fetch", Cmd);
  3576. //
  3577. // Abort promotion; if any
  3578. //
  3579. //
  3580. // We no longer seed during dcpromo so aborting a fetch during seeding is same as
  3581. // aborting it at any other time. If we abort a dir create then it will trigger a unjoin
  3582. // of the volatile connection. The vvjoin will finish over the new connection
  3583. // or the volatile connection will be re-established when the seeding downstream
  3584. // partner comes back up.
  3585. //
  3586. if (Replica->NtFrsApi_ServiceState == NTFRSAPI_SERVICE_PROMOTING) {
  3587. DPRINT1(4, "++ Promotion aborted: abort fetch for %ws.\n",
  3588. Replica->SetName->Name);
  3589. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE;
  3590. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  3591. }
  3592. //
  3593. // Find and check the cxtion
  3594. //
  3595. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3596. CHECK_CXTION_INBOUND |
  3597. CHECK_CXTION_AUTH);
  3598. if (!InCxtion) {
  3599. //
  3600. // Note: Can we come thru here on any retryable cases?
  3601. // If we can then we should do the following instead of aborting the CO.
  3602. //
  3603. // SET_COE_FLAG(Coe, COE_FLAG_NO_INBOUND);
  3604. // CHANGE_ORDER_TRACE(3, Coe, "Submit CO to fetch retry");
  3605. // ChgOrdInboundRetry(Coe, IBCO_FETCH_RETRY);
  3606. //
  3607. // Aborting a DIR create will trigger a unjoin on the connection.
  3608. //
  3609. SET_COE_FLAG(Coe, COE_FLAG_STAGE_ABORTED);
  3610. CHANGE_ORDER_TRACE(0, Coe, "Aborting fetch");
  3611. ChgOrdInboundRetired(Coe);
  3612. RsCoe(Cmd) = NULL;
  3613. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  3614. return;
  3615. }
  3616. FrsFetchCsSubmitTransfer(Cmd, CMD_ABORT_FETCH);
  3617. }
  3618. VOID
  3619. RcsReceivingStageFile(
  3620. IN PCOMMAND_PACKET Cmd
  3621. )
  3622. /*++
  3623. Routine Description:
  3624. Received this data from our inbound partner. Give it to the fetcher
  3625. so he can put it into the staging file.
  3626. Arguments:
  3627. Cmd
  3628. Return Value:
  3629. None.
  3630. --*/
  3631. {
  3632. #undef DEBSUB
  3633. #define DEBSUB "RcsReceivingStageFile:"
  3634. PREPLICA Replica;
  3635. PCXTION InCxtion;
  3636. //
  3637. // Check the command packet
  3638. //
  3639. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK | CHECK_CMD_COE)) {
  3640. return;
  3641. }
  3642. Replica = RsReplica(Cmd);
  3643. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsReceivingStageFile entry");
  3644. CHANGE_ORDER_TRACEXP(3, RsCoe(Cmd), "Replica receiving stage", Cmd);
  3645. #ifndef NOVVJOINHACK
  3646. RsReplica(Cmd)->NtFrsApi_HackCount++;
  3647. #endif NOVVJOINHACK
  3648. //
  3649. // Find and check the cxtion
  3650. //
  3651. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3652. CHECK_CXTION_INBOUND |
  3653. CHECK_CXTION_AUTH);
  3654. if (!InCxtion) {
  3655. //
  3656. // Note: If auth check fails we might consider aborting the CO instead.
  3657. // Need to first try it and see if the CO would be aborted
  3658. // elsewhere first.
  3659. //
  3660. return;
  3661. }
  3662. //
  3663. // Display info for dcpromo during sysvol seeding
  3664. // We don't seed during dcpromo anymore so we don't need to
  3665. // display any progress information.
  3666. //
  3667. // if (!Replica->NtFrsApi_ServiceDisplay) {
  3668. // Replica->NtFrsApi_ServiceDisplay = FrsWcsDup(RsCoc(Cmd)->FileName);
  3669. // }
  3670. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_RECEIVING_STAGE");
  3671. //
  3672. // Increment the Fetch Requests Bytes Received counter for
  3673. // both the replica set and connection objects
  3674. //
  3675. PM_INC_CTR_CXTION(InCxtion, FetBRcvd, 1);
  3676. PM_INC_CTR_REPSET(Replica, FetBRcvd, 1);
  3677. PM_INC_CTR_CXTION(InCxtion, FetBRcvdBytes, RsBlockSize(Cmd));
  3678. PM_INC_CTR_REPSET(Replica, FetBRcvdBytes, RsBlockSize(Cmd));
  3679. FrsFetchCsSubmitTransfer(Cmd, CMD_RECEIVING_STAGE);
  3680. }
  3681. VOID
  3682. RcsSendRetryFetch(
  3683. IN PCOMMAND_PACKET Cmd
  3684. )
  3685. /*++
  3686. Routine Description:
  3687. Received from the local staging file fetcher. Tell our
  3688. outbound partner to retry the fetch at a later time.
  3689. Arguments:
  3690. Cmd
  3691. Return Value:
  3692. None.
  3693. --*/
  3694. {
  3695. #undef DEBSUB
  3696. #define DEBSUB "RcsSendRetryFetch:"
  3697. PREPLICA Replica;
  3698. PCXTION OutCxtion;
  3699. PCOMM_PACKET CPkt;
  3700. //
  3701. // Check the command packet
  3702. //
  3703. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK)) {
  3704. return;
  3705. }
  3706. Replica = RsReplica(Cmd);
  3707. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendRetryFetch entry");
  3708. #ifndef NOVVJOINHACK
  3709. RsReplica(Cmd)->NtFrsApi_HackCount++;
  3710. #endif NOVVJOINHACK
  3711. //
  3712. // Find and check the cxtion
  3713. //
  3714. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3715. CHECK_CXTION_OUTBOUND);
  3716. if (!OutCxtion) {
  3717. return;
  3718. }
  3719. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_RETRY_FETCH");
  3720. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_RETRY_FETCH, NULL, Cmd, NULL);
  3721. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  3722. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3723. }
  3724. VOID
  3725. RcsSendAbortFetch(
  3726. IN PCOMMAND_PACKET Cmd
  3727. )
  3728. /*++
  3729. Routine Description:
  3730. Received from the local staging file fetcher. Tell our
  3731. outbound partner to abort the fetch.
  3732. Arguments:
  3733. Cmd
  3734. Return Value:
  3735. None.
  3736. --*/
  3737. {
  3738. #undef DEBSUB
  3739. #define DEBSUB "RcsSendAbortFetch:"
  3740. PREPLICA Replica;
  3741. PCXTION OutCxtion;
  3742. PCOMM_PACKET CPkt;
  3743. //
  3744. // Check the command packet
  3745. //
  3746. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK)) {
  3747. return;
  3748. }
  3749. Replica = RsReplica(Cmd);
  3750. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendAbortFetch entry");
  3751. //
  3752. // Find and check the cxtion
  3753. //
  3754. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3755. CHECK_CXTION_OUTBOUND);
  3756. if (!OutCxtion) {
  3757. return;
  3758. }
  3759. //
  3760. // Tell our outbound partner that the file has been sent
  3761. //
  3762. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_ABORT_FETCH");
  3763. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_ABORT_FETCH, NULL, Cmd, NULL);
  3764. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  3765. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3766. }
  3767. VOID
  3768. RcsSendingStageFile(
  3769. IN PCOMMAND_PACKET Cmd
  3770. )
  3771. /*++
  3772. Routine Description:
  3773. Received from the local staging file fetcher. Push this data to
  3774. our outbound partner.
  3775. Arguments:
  3776. Cmd
  3777. Return Value:
  3778. None.
  3779. --*/
  3780. {
  3781. #undef DEBSUB
  3782. #define DEBSUB "RcsSendingStageFile:"
  3783. PREPLICA Replica;
  3784. PCXTION OutCxtion;
  3785. PCOMM_PACKET CPkt;
  3786. //
  3787. // Check the command packet
  3788. //
  3789. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK)) {
  3790. return;
  3791. }
  3792. Replica = RsReplica(Cmd);
  3793. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendingStageFile entry");
  3794. //
  3795. // Find and check the cxtion
  3796. //
  3797. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3798. CHECK_CXTION_OUTBOUND);
  3799. if (!OutCxtion) {
  3800. return;
  3801. }
  3802. //
  3803. // Increment the Fetch Blocks sent and Fetch Bytes sent counter for
  3804. // both the replica set and connection objects
  3805. //
  3806. PM_INC_CTR_CXTION(OutCxtion, FetBSent, 1);
  3807. PM_INC_CTR_REPSET(Replica, FetBSent, 1);
  3808. PM_INC_CTR_CXTION(OutCxtion, FetBSentBytes, RsBlockSize(Cmd));
  3809. PM_INC_CTR_REPSET(Replica, FetBSentBytes, RsBlockSize(Cmd));
  3810. //
  3811. // Send the next block of the file to the outbound partner.
  3812. //
  3813. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_RECEIVING_STAGE");
  3814. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_RECEIVING_STAGE, NULL, Cmd, NULL);
  3815. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  3816. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3817. }
  3818. VOID
  3819. RcsSendStageFile(
  3820. IN PCOMMAND_PACKET Cmd
  3821. )
  3822. /*++
  3823. Routine Description:
  3824. Received a request to send the staging control file to our
  3825. outbound partner. Tell the staging fetcher to send it on.
  3826. Arguments:
  3827. Cmd
  3828. Return Value:
  3829. None.
  3830. --*/
  3831. {
  3832. #undef DEBSUB
  3833. #define DEBSUB "RcsSendStageFile:"
  3834. PCXTION OutCxtion;
  3835. PREPLICA Replica;
  3836. //
  3837. // Check the command packet
  3838. //
  3839. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK |
  3840. CHECK_CMD_PARTNERCOC )) {
  3841. return;
  3842. }
  3843. Replica = RsReplica(Cmd);
  3844. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendStageFile entry");
  3845. CHANGE_ORDER_COMMAND_TRACE(3, RsPartnerCoc(Cmd), "Command send stage");
  3846. //
  3847. // Find and check the cxtion
  3848. //
  3849. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3850. CHECK_CXTION_OUTBOUND);
  3851. if (!OutCxtion) {
  3852. return;
  3853. }
  3854. //
  3855. // Tell the staging file generator to send the file
  3856. //
  3857. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_SEND_STAGE");
  3858. FrsFetchCsSubmitTransfer(Cmd, CMD_SEND_STAGE);
  3859. }
  3860. VOID
  3861. RcsRemoteCoAccepted(
  3862. IN PCOMMAND_PACKET Cmd
  3863. )
  3864. /*++
  3865. Routine Description:
  3866. We have accepted the remote change order, fetch the staging file
  3867. Arguments:
  3868. Cmd
  3869. Return Value:
  3870. None.
  3871. --*/
  3872. {
  3873. #undef DEBSUB
  3874. #define DEBSUB "RcsRemoteCoAccepted:"
  3875. DWORD WStatus;
  3876. DWORD Flags;
  3877. PREPLICA Replica;
  3878. PCXTION InCxtion;
  3879. PCHANGE_ORDER_ENTRY Coe;
  3880. PCHANGE_ORDER_COMMAND Coc;
  3881. PCOMM_PACKET CPkt;
  3882. //
  3883. // Check the command packet
  3884. //
  3885. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_COE)) {
  3886. return;
  3887. }
  3888. Replica = RsReplica(Cmd);
  3889. Coe = RsCoe(Cmd);
  3890. Coc = RsCoc(Cmd);
  3891. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRemoteCoAccepted entry");
  3892. CHANGE_ORDER_TRACEXP(3, Coe, "Replica remote co accepted", Cmd);
  3893. #ifndef NOVVJOINHACK
  3894. Replica->NtFrsApi_HackCount++;
  3895. #endif NOVVJOINHACK
  3896. //
  3897. // Find and check the cxtion
  3898. //
  3899. // We don't need auth check here because this cmd hasn't arrived
  3900. // from a partner. It is submitted by RcsSubmitRemoteCoAccepted()
  3901. //
  3902. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3903. CHECK_CXTION_INBOUND |
  3904. CHECK_CXTION_JOINED);
  3905. if (!InCxtion) {
  3906. return;
  3907. }
  3908. FRS_CO_COMM_PROGRESS(3, Coc, (ULONG)(Coc->SequenceNumber),
  3909. InCxtion->PartSrvName, "Remote Co Accepted");
  3910. //
  3911. // MACRO MAY RETURN!!!
  3912. //
  3913. PULL_UNJOIN_TRIGGER(InCxtion, Cmd);
  3914. if (VVHasVsn(Replica->VVector, Coc)) {
  3915. CHANGE_ORDER_TRACE(3, Coe, "Dampen Accepted Remote Co");
  3916. }
  3917. //
  3918. // Don't fetch a non-existent staging file
  3919. //
  3920. if (!FrsDoesCoNeedStage(Coc)) {
  3921. //
  3922. // Allocate or update the Join Guid.
  3923. //
  3924. if (RsJoinGuid(Cmd) == NULL) {
  3925. RsJoinGuid(Cmd) = FrsDupGuid(&InCxtion->JoinGuid);
  3926. } else {
  3927. COPY_GUID(RsJoinGuid(Cmd), &InCxtion->JoinGuid);
  3928. }
  3929. RcsReceivedStageFile(Cmd, 0);
  3930. return;
  3931. }
  3932. //
  3933. // Don't refetch a recovered staging file
  3934. //
  3935. Flags = 0;
  3936. WStatus = StageAcquire(&Coc->ChangeOrderGuid, Coc->FileName, QUADZERO, &Flags, NULL);
  3937. if (WIN_SUCCESS(WStatus)) {
  3938. StageRelease(&Coc->ChangeOrderGuid, Coc->FileName, Flags, NULL, NULL);
  3939. if (Flags & STAGE_FLAG_CREATED) {
  3940. //
  3941. // File has been fetched
  3942. //
  3943. RsFileOffset(Cmd).QuadPart = RsFileSize(Cmd).QuadPart;
  3944. //
  3945. // Allocate or update the Join Guid.
  3946. //
  3947. if (RsJoinGuid(Cmd) == NULL) {
  3948. RsJoinGuid(Cmd) = FrsDupGuid(&InCxtion->JoinGuid);
  3949. } else {
  3950. COPY_GUID(RsJoinGuid(Cmd), &InCxtion->JoinGuid);
  3951. }
  3952. RcsReceivedStageFile(Cmd, 0);
  3953. return;
  3954. }
  3955. }
  3956. //
  3957. // Attempt to use a preexisting file if this is the first block of the
  3958. // staging file, is a vvjoin co, and there is a preinstall file.
  3959. //
  3960. if (InCxtion->PartnerMinor >= NTFRS_COMM_MINOR_1 &&
  3961. (RsFileOffset(Cmd).QuadPart == QUADZERO) &&
  3962. CO_FLAG_ON(Coe, CO_FLAG_VVJOIN_TO_ORIG) &&
  3963. COE_FLAG_ON(Coe, COE_FLAG_PREINSTALL_CRE)) {
  3964. FrsStageCsSubmitTransfer(Cmd, CMD_CREATE_EXISTING);
  3965. return;
  3966. }
  3967. //
  3968. // fetching the staging file
  3969. //
  3970. SET_CHANGE_ORDER_STATE(RsCoe(Cmd), IBCO_FETCH_INITIATED);
  3971. //
  3972. // Increment the Fetch Requests Files Requested counter for
  3973. // both the replica set and connection objects
  3974. //
  3975. PM_INC_CTR_CXTION(InCxtion, FetRSent, 1);
  3976. PM_INC_CTR_REPSET(Replica, FetRSent, 1);
  3977. //
  3978. // Tell our inbound partner to send the staging file
  3979. //
  3980. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_SEND_STAGE");
  3981. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_SEND_STAGE, NULL, Cmd, Coc);
  3982. SndCsSubmitCommPkt2(Replica, InCxtion, RsCoe(Cmd), TRUE, CPkt);
  3983. RsCoe(Cmd) = NULL;
  3984. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3985. }
  3986. VOID
  3987. RcsSendStageFileRequest(
  3988. IN PCOMMAND_PACKET Cmd
  3989. )
  3990. /*++
  3991. Routine Description:
  3992. Generated staging file (maybe) from preexisting file.
  3993. Request stage file from upstream partner. If MD5Digest matches
  3994. on Upstream partner's stage file then our pre-existing stage file (if any)
  3995. is good.
  3996. Arguments:
  3997. Cmd
  3998. Return Value:
  3999. None.
  4000. --*/
  4001. {
  4002. #undef DEBSUB
  4003. #define DEBSUB "RcsSendStageFileRequest:"
  4004. PREPLICA Replica;
  4005. PCXTION InCxtion;
  4006. PCHANGE_ORDER_ENTRY Coe;
  4007. PCHANGE_ORDER_COMMAND Coc;
  4008. PCOMM_PACKET CPkt;
  4009. //
  4010. // Check the command packet
  4011. //
  4012. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_COE)) {
  4013. return;
  4014. }
  4015. Replica = RsReplica(Cmd);
  4016. Coe = RsCoe(Cmd);
  4017. Coc = RsCoc(Cmd);
  4018. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendStageFileRequest entry");
  4019. CHANGE_ORDER_TRACEXP(3, Coe, "Replica created existing", Cmd);
  4020. #ifndef NOVVJOINHACK
  4021. Replica->NtFrsApi_HackCount++;
  4022. #endif NOVVJOINHACK
  4023. if (RsMd5Digest(Cmd)) {
  4024. PDATA_EXTENSION_CHECKSUM CocDataChkSum;
  4025. //
  4026. // We have an existing file and the checksum has been created.
  4027. // See if we have a checksum in the changeorder from our inbound
  4028. // partner. If so and they match then we can move on to the install.
  4029. //
  4030. CHANGE_ORDER_TRACE(3, Coe, "Created Existing");
  4031. CocDataChkSum = DbsDataExtensionFind(Coc->Extension, DataExtend_MD5_CheckSum);
  4032. if ((CocDataChkSum != NULL) &&
  4033. !IS_MD5_CHKSUM_ZERO(CocDataChkSum->Data) &&
  4034. MD5_EQUAL(CocDataChkSum->Data, RsMd5Digest(Cmd))) {
  4035. //
  4036. // MD5 digest from CO matches so our file is good and we can
  4037. // avoid having the inbound partner recompute the checksum.
  4038. //
  4039. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Md5 matches preexisting, no fetch");
  4040. SET_COE_FLAG(Coe, COE_FLAG_PRE_EXIST_MD5_MATCH);
  4041. DPRINT1(4, "++ RsFileSize(Cmd).QuadPart: %08x %08x\n",
  4042. PRINTQUAD(RsFileSize(Cmd).QuadPart));
  4043. DPRINT1(4, "++ Coc->FileSize: %08x %08x\n",
  4044. PRINTQUAD(Coc->FileSize));
  4045. //
  4046. // Even if the file is 0 bytes in length, the staging file will
  4047. // always have at least the header. There are some retry paths
  4048. // that will incorrectly think the staging file has been fetched
  4049. // if RsFileSize(Cmd) is 0. So make sure it isn't.
  4050. //
  4051. if (RsFileSize(Cmd).QuadPart == QUADZERO) {
  4052. RsFileSize(Cmd).QuadPart = Coc->FileSize;
  4053. if (RsFileSize(Cmd).QuadPart == QUADZERO) {
  4054. RsFileSize(Cmd).QuadPart = sizeof(STAGE_HEADER);
  4055. }
  4056. }
  4057. DPRINT1(4, "++ RsFileSize(Cmd).QuadPart: %08x %08x\n",
  4058. PRINTQUAD(RsFileSize(Cmd).QuadPart));
  4059. //
  4060. // Set the offset to the size of the stage file so we don't request
  4061. // any data.
  4062. //
  4063. RsFileOffset(Cmd).QuadPart = RsFileSize(Cmd).QuadPart;
  4064. RsBlockSize(Cmd) = QUADZERO;
  4065. //
  4066. // Find and check the cxtion
  4067. //
  4068. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4069. CHECK_CXTION_INBOUND |
  4070. CHECK_CXTION_JOINED);
  4071. if (!InCxtion) {
  4072. return;
  4073. }
  4074. //
  4075. // Allocate or update the Join Guid.
  4076. //
  4077. if (RsJoinGuid(Cmd) == NULL) {
  4078. RsJoinGuid(Cmd) = FrsDupGuid(&InCxtion->JoinGuid);
  4079. } else {
  4080. COPY_GUID(RsJoinGuid(Cmd), &InCxtion->JoinGuid);
  4081. }
  4082. RcsReceivedStageFile(Cmd, 0);
  4083. //RcsSubmitTransferToRcs(Cmd, CMD_RECEIVED_STAGE);
  4084. return;
  4085. }
  4086. } else {
  4087. CHANGE_ORDER_TRACE(3, Coe, "Could not create existing");
  4088. }
  4089. //
  4090. // Find and check the cxtion
  4091. //
  4092. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4093. CHECK_CXTION_INBOUND |
  4094. CHECK_CXTION_JOINED);
  4095. if (!InCxtion) {
  4096. return;
  4097. }
  4098. //
  4099. // Tell our inbound partner to send the staging file
  4100. //
  4101. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_SEND_STAGE");
  4102. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_SEND_STAGE, NULL, Cmd, Coc);
  4103. SndCsSubmitCommPkt2(Replica, InCxtion, RsCoe(Cmd), TRUE, CPkt);
  4104. RsCoe(Cmd) = NULL;
  4105. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4106. }
  4107. VOID
  4108. RcsRemoteCoReceived(
  4109. IN PCOMMAND_PACKET Cmd
  4110. )
  4111. /*++
  4112. Routine Description:
  4113. Remote CO has arrived.
  4114. Translate guid of our root dir if necc.
  4115. Attach the Change Order extension if provided.
  4116. Check version vector dampening and provide immediate Ack if we have
  4117. already seen this CO.
  4118. Finally, pass the change order on to the change order subsystem.
  4119. Arguments:
  4120. Cmd
  4121. Return Value:
  4122. None.
  4123. --*/
  4124. {
  4125. #undef DEBSUB
  4126. #define DEBSUB "RcsRemoteCoReceived:"
  4127. PCXTION InCxtion;
  4128. PREPLICA Replica;
  4129. PULONG pULong;
  4130. PCHANGE_ORDER_COMMAND Coc;
  4131. PCHANGE_ORDER_RECORD_EXTENSION CocExt;
  4132. //
  4133. // Check the command packet
  4134. //
  4135. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_PARTNERCOC )) {
  4136. return;
  4137. }
  4138. Replica = RsReplica(Cmd);
  4139. Coc = RsPartnerCoc(Cmd);
  4140. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRemoteCoReceived entry");
  4141. #ifndef NOVVJOINHACK
  4142. RsReplica(Cmd)->NtFrsApi_HackCount++;
  4143. #endif NOVVJOINHACK
  4144. //
  4145. // Find and check the cxtion
  4146. //
  4147. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  4148. CHECK_CXTION_INBOUND |
  4149. CHECK_CXTION_AUTH |
  4150. CHECK_CXTION_FIXJOINED);
  4151. if (!InCxtion) {
  4152. return;
  4153. }
  4154. //
  4155. // Remember which cxtion this change order was directed at
  4156. //
  4157. COPY_GUID(&Coc->CxtionGuid, RsCxtion(Cmd)->Guid);
  4158. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Replica Received Remote Co");
  4159. //
  4160. // Our partner doesn't know the correct value for our root guid and
  4161. // so substituted our ReplicaName->Guid (its Cxtion->Partner->Guid)
  4162. // for its own root guids when sending the change order to us.
  4163. // We substitute our own root guids once we receive the change order
  4164. // and detect the substitution.
  4165. //
  4166. if (GUIDS_EQUAL(&Coc->OldParentGuid, RsReplica(Cmd)->ReplicaName->Guid)) {
  4167. COPY_GUID(&Coc->OldParentGuid, RsReplica(Cmd)->ReplicaRootGuid);
  4168. }
  4169. if (GUIDS_EQUAL(&Coc->NewParentGuid, RsReplica(Cmd)->ReplicaName->Guid)) {
  4170. COPY_GUID(&Coc->NewParentGuid, RsReplica(Cmd)->ReplicaRootGuid);
  4171. }
  4172. //
  4173. // Init the Coc pointer to the CO Data Extension. Down Rev partners
  4174. // won't have one so supply an empty field. Do this here in case VV
  4175. // Dampening short circuits the CO and sends back the RemoteCoDone ACK here.
  4176. //
  4177. CocExt = RsPartnerCocExt(Cmd);
  4178. if (CocExt == NULL) {
  4179. CocExt = FrsAlloc(sizeof(CHANGE_ORDER_RECORD_EXTENSION));
  4180. DbsDataInitCocExtension(CocExt);
  4181. DPRINT(4, "Allocating initial Coc Extension\n");
  4182. }
  4183. Coc->Extension = CocExt;
  4184. pULong = (PULONG) CocExt;
  4185. DPRINT5(5, "Extension Buffer: (%08x) %08x %08x %08x %08x\n",
  4186. pULong, *(pULong+0), *(pULong+1), *(pULong+2), *(pULong+3));
  4187. DPRINT5(5, "Extension Buffer: (%08x) %08x %08x %08x %08x\n",
  4188. (PCHAR)pULong+16, *(pULong+4), *(pULong+5), *(pULong+6), *(pULong+7));
  4189. //
  4190. // Don't redo a change order
  4191. //
  4192. if (VVHasVsn(RsReplica(Cmd)->VVector, Coc)) {
  4193. //
  4194. // Increment the Inbound CO dampned counter for
  4195. // both the replica set and connection objects
  4196. //
  4197. PM_INC_CTR_CXTION(InCxtion, InCODampned, 1);
  4198. PM_INC_CTR_REPSET(RsReplica(Cmd), InCODampned, 1);
  4199. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Dampen Received Remote Co");
  4200. RcsSendRemoteCoDone(RsReplica(Cmd), Coc);
  4201. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4202. return;
  4203. }
  4204. //
  4205. // Put the change order on the inbound queue for this replica.
  4206. //
  4207. ChgOrdInsertRemoteCo(Cmd, InCxtion);
  4208. //
  4209. // Done
  4210. //
  4211. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4212. }
  4213. VOID
  4214. RcsRetryStageFileCreate(
  4215. IN PCOMMAND_PACKET Cmd
  4216. )
  4217. /*++
  4218. Routine Description:
  4219. Retry generating the staging file.
  4220. Arguments:
  4221. Cmd
  4222. Return Value:
  4223. None.
  4224. --*/
  4225. {
  4226. #undef DEBSUB
  4227. #define DEBSUB "RcsRetryStageFileCreate:"
  4228. PREPLICA Replica;
  4229. PCXTION OutCxtion;
  4230. PCXTION InCxtion;
  4231. PVOID Key;
  4232. PCHANGE_ORDER_ENTRY Coe;
  4233. //
  4234. // Check the command packet
  4235. //
  4236. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA | CHECK_CMD_COE)) {
  4237. return;
  4238. }
  4239. Replica = RsReplica(Cmd);
  4240. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRetryStageFileCreate entry");
  4241. CHANGE_ORDER_TRACEXP(3, RsCoe(Cmd), "Replica retry stage", Cmd);
  4242. //
  4243. // Find and check the cxtion
  4244. //
  4245. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4246. CHECK_CXTION_INBOUND |
  4247. CHECK_CXTION_JRNLCXTION |
  4248. CHECK_CXTION_JOINED);
  4249. if (!InCxtion) {
  4250. return;
  4251. }
  4252. //
  4253. // Ignore local change order if there are no outbound cxtions
  4254. //
  4255. Key = NULL;
  4256. while (OutCxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  4257. if (!OutCxtion->Inbound) {
  4258. break;
  4259. }
  4260. }
  4261. if (OutCxtion == NULL) {
  4262. //
  4263. // Make sure a user hasn't altered our object id on the file
  4264. // and then retire the change order without propagating to the
  4265. // outbound log. The stager is responsible for hammering the
  4266. // object id because it knows how to handle sharing violations
  4267. // and file-not-found errors.
  4268. //
  4269. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CHECK_OID");
  4270. FrsStageCsSubmitTransfer(Cmd, CMD_CHECK_OID);
  4271. } else {
  4272. //
  4273. // Generate the staging file
  4274. //
  4275. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CREATE_STAGE");
  4276. FrsStageCsSubmitTransfer(Cmd, CMD_CREATE_STAGE);
  4277. }
  4278. }
  4279. VOID
  4280. RcsLocalCoAccepted(
  4281. IN PCOMMAND_PACKET Cmd
  4282. )
  4283. /*++
  4284. Routine Description:
  4285. Process the accepted, local change order. Either retire it if there
  4286. are no outbound cxtions or send it own to the staging file generator.
  4287. Arguments:
  4288. Cmd
  4289. Return Value:
  4290. None.
  4291. --*/
  4292. {
  4293. #undef DEBSUB
  4294. #define DEBSUB "RcsLocalCoAccepted:"
  4295. PREPLICA Replica;
  4296. PCXTION OutCxtion;
  4297. PCXTION InCxtion;
  4298. PVOID Key;
  4299. PCHANGE_ORDER_ENTRY Coe;
  4300. //
  4301. // Check the command packet
  4302. //
  4303. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA | CHECK_CMD_COE)) {
  4304. return;
  4305. }
  4306. Replica = RsReplica(Cmd);
  4307. Coe = RsCoe(Cmd);
  4308. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsLocalCoAccepted entry");
  4309. CHANGE_ORDER_TRACEXP(3, Coe, "Replica local co accepted", Cmd);
  4310. //
  4311. // Find and check the cxtion
  4312. //
  4313. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4314. CHECK_CXTION_INBOUND |
  4315. CHECK_CXTION_JRNLCXTION |
  4316. CHECK_CXTION_JOINED);
  4317. if (!InCxtion) {
  4318. return;
  4319. }
  4320. FRS_CO_COMM_PROGRESS(3, &Coe->Cmd, Coe->Cmd.SequenceNumber,
  4321. InCxtion->PartSrvName, "Local Co Accepted");
  4322. //
  4323. // Ignore local change order if there are no outbound cxtions
  4324. //
  4325. Key = NULL;
  4326. while (OutCxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  4327. if (!OutCxtion->Inbound) {
  4328. break;
  4329. }
  4330. }
  4331. if (OutCxtion == NULL) {
  4332. //
  4333. // Make sure a user hasn't altered our object id on the file
  4334. // and then retire the change order without propagating to the
  4335. // outbound log. The stager is responsible for hammering the
  4336. // object id because it knows how to handle sharing violations
  4337. // and file-not-found errors.
  4338. //
  4339. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CHECK_OID");
  4340. FrsStageCsSubmitTransfer(Cmd, CMD_CHECK_OID);
  4341. } else {
  4342. //
  4343. // Generate the staging file
  4344. //
  4345. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CREATE_STAGE");
  4346. FrsStageCsSubmitTransfer(Cmd, CMD_CREATE_STAGE);
  4347. }
  4348. }
  4349. VOID
  4350. RcsBeginMergeWithDs(
  4351. VOID
  4352. )
  4353. /*++
  4354. Routine Description:
  4355. The DS has been polled and now has replicas to merge into the
  4356. active replicas initially retrieved from the database or merged
  4357. into the active replicas by a previous poll.
  4358. Each active replica is marked as "not merged with ds". Any
  4359. replica that remains in this state after the merge is done
  4360. is a deleted replica. See RcsEndMergeWithDs().
  4361. Arguments:
  4362. None.
  4363. Return Value:
  4364. TRUE - Continue with merge
  4365. FALSE - Abort merge
  4366. --*/
  4367. {
  4368. #undef DEBSUB
  4369. #define DEBSUB "RcsBeginMergeWithDs:"
  4370. PVOID Key;
  4371. PREPLICA Replica;
  4372. extern CRITICAL_SECTION MergingReplicasWithDs;
  4373. //
  4374. // Wait for the replica command server to start up. The shutdown
  4375. // code will set this event so we don't sleep forever.
  4376. //
  4377. WaitForSingleObject(ReplicaEvent, INFINITE);
  4378. //
  4379. // Synchronize with sysvol seeding
  4380. //
  4381. EnterCriticalSection(&MergingReplicasWithDs);
  4382. //
  4383. // Snapshot a copy of the replica table. Anything left in the table
  4384. // after the merge should be deleted because a corresponding entry
  4385. // no longer exists in the DS. This code is not multithread!
  4386. //
  4387. FRS_ASSERT(ReplicasNotInTheDs == NULL);
  4388. ReplicasNotInTheDs = GTabAllocTable();
  4389. Key = NULL;
  4390. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  4391. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Insert ReplicasNotInTheDs");
  4392. GTabInsertEntry(ReplicasNotInTheDs, Replica, Replica->ReplicaName->Guid, NULL);
  4393. }
  4394. }
  4395. VOID
  4396. RcsSubmitReplica(
  4397. IN PREPLICA Replica,
  4398. IN PREPLICA NewReplica, OPTIONAL
  4399. IN USHORT Command
  4400. )
  4401. /*++
  4402. Routine Description:
  4403. Submit a command to a replica.
  4404. Arguments:
  4405. Replica - existing replica
  4406. NewReplica - Changes to Replica (may be NULL)
  4407. Command
  4408. Return Value:
  4409. None.
  4410. --*/
  4411. {
  4412. #undef DEBSUB
  4413. #define DEBSUB "RcsSubmitReplica:"
  4414. PCOMMAND_PACKET Cmd;
  4415. //
  4416. // Allocate a command packet
  4417. //
  4418. Cmd = FrsAllocCommand(Replica->Queue, Command);
  4419. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  4420. //
  4421. // Address of replica set and new replica set
  4422. //
  4423. RsReplica(Cmd) = Replica;
  4424. RsNewReplica(Cmd) = NewReplica;
  4425. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSubmitReplica cmd");
  4426. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  4427. }
  4428. VOID
  4429. RcsSubmitReplicaCxtion(
  4430. IN PREPLICA Replica,
  4431. IN PCXTION Cxtion,
  4432. IN USHORT Command
  4433. )
  4434. /*++
  4435. Routine Description:
  4436. Submit a command to a replica\cxtion.
  4437. Build cmd pkt with Cxtion GName, replica ptr, Join Guid and supplied command.
  4438. Submit to Replica cmd server.
  4439. Calls dispatch function and translates cxtion GName to cxtion ptr
  4440. Builds Comm pkt for cxtion and calls SndCsSubmit() to send it.
  4441. Arguments:
  4442. Replica - existing replica
  4443. Cxtion - existing cxtion
  4444. Command
  4445. Return Value:
  4446. None.
  4447. --*/
  4448. {
  4449. #undef DEBSUB
  4450. #define DEBSUB "RcsSubmitReplicaCxtion:"
  4451. PCOMMAND_PACKET Cmd;
  4452. //
  4453. // Allocate a command packet
  4454. //
  4455. Cmd = FrsAllocCommand(Replica->Queue, Command);
  4456. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  4457. //
  4458. // Address of replica set and new replica set
  4459. //
  4460. RsReplica(Cmd) = Replica;
  4461. RsCxtion(Cmd) = FrsDupGName(Cxtion->Name);
  4462. RsJoinGuid(Cmd) = FrsDupGuid(&Cxtion->JoinGuid);
  4463. //
  4464. // OLCtx and CommPkts are used for CMD_HUNG_CXTION.
  4465. // They are used to detect a hung outbound cxtion that
  4466. // is probably hung because of a dropped ack.
  4467. //
  4468. if (Cxtion->OLCtx) {
  4469. RsCOTx(Cmd) = Cxtion->OLCtx->COTx;
  4470. }
  4471. RsCommPkts(Cmd) = Cxtion->CommPkts - 1;
  4472. DPRINT5(5, "Submit %08x for Cmd %08x %ws\\%ws\\%ws\n",
  4473. Cmd->Command, Cmd, Replica->SetName->Name, Replica->MemberName->Name,
  4474. Cxtion->Name->Name);
  4475. CXTION_STATE_TRACE(5, Cxtion, Replica, 0, "F, RcsSubmitReplicaCxtion cmd");
  4476. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  4477. }
  4478. DWORD
  4479. RcsSubmitReplicaSync(
  4480. IN PREPLICA Replica,
  4481. IN PREPLICA NewReplica,
  4482. IN PCXTION VolatileCxtion,
  4483. IN USHORT Command
  4484. )
  4485. /*++
  4486. Routine Description:
  4487. Submit a command to a replica and wait for it to finish.
  4488. Arguments:
  4489. Replica - existing replica
  4490. NewReplica - Changes to Replica (may be NULL)
  4491. VolatileCxtion - New cxtion (currently used for seeding sysvols)
  4492. Command
  4493. Return Value:
  4494. None.
  4495. --*/
  4496. {
  4497. #undef DEBSUB
  4498. #define DEBSUB "RcsSubmitReplicaSync:"
  4499. DWORD WStatus;
  4500. PCOMMAND_PACKET Cmd;
  4501. //
  4502. // Allocate a command packet
  4503. //
  4504. Cmd = FrsAllocCommand(Replica->Queue, Command);
  4505. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  4506. //
  4507. // Address of replica set and new replica set
  4508. //
  4509. RsReplica(Cmd) = Replica;
  4510. RsNewReplica(Cmd) = NewReplica;
  4511. RsNewCxtion(Cmd) = VolatileCxtion;
  4512. RsCompletionEvent(Cmd) = FrsCreateEvent(TRUE, FALSE);
  4513. DPRINT3(5, "Submit Sync %08x for Cmd %08x %ws\n",
  4514. Cmd->Command, Cmd, RsReplica(Cmd)->ReplicaName->Name);
  4515. CXTION_STATE_TRACE(5, VolatileCxtion, Replica, 0, "F, RcsSubmitReplicaSync cmd");
  4516. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  4517. //
  4518. // Wait for the command to finish
  4519. //
  4520. WaitForSingleObject(RsCompletionEvent(Cmd), INFINITE);
  4521. FRS_CLOSE(RsCompletionEvent(Cmd));
  4522. WStatus = Cmd->ErrorStatus;
  4523. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  4524. return WStatus;
  4525. }
  4526. VOID
  4527. RcsEndMergeWithDs(
  4528. VOID
  4529. )
  4530. /*++
  4531. Routine Description:
  4532. The DS has been polled and the replicas have been merged into the
  4533. active replicas.
  4534. Each active replica was initially included in a temporary table.
  4535. Any replica still left in the table is a deleted replica because
  4536. its corresponding entry in the DS was not found.
  4537. Arguments:
  4538. None.
  4539. Return Value:
  4540. None.
  4541. --*/
  4542. {
  4543. #undef DEBSUB
  4544. #define DEBSUB "RcsEndMergeWithDs:"
  4545. PVOID Key;
  4546. PREPLICA Replica;
  4547. DWORD ReplicaSetsDeleted;
  4548. extern BOOL DsIsShuttingDown;
  4549. extern CRITICAL_SECTION MergingReplicasWithDs;
  4550. extern ULONG DsPollingInterval;
  4551. extern ULONG DsPollingShortInterval;
  4552. //
  4553. // Any replica that is in the state "not merged" should be deleted
  4554. // unless the Ds is shutting down; in which case do not process
  4555. // deletes because a sysvol seeding operation may be in progress.
  4556. // We do not want to delete the sysvol we are currently trying to
  4557. // create.
  4558. //
  4559. Key = NULL;
  4560. while (!DsIsShuttingDown &&
  4561. (Replica = GTabNextDatum(ReplicasNotInTheDs, &Key))) {
  4562. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, submit replica CMD_DELETE");
  4563. RcsSubmitReplica(Replica, NULL, CMD_DELETE);
  4564. }
  4565. DbsProcessReplicaFaultList(&ReplicaSetsDeleted);
  4566. //
  4567. // If any replica sets were deleted while processing the fault list then we should
  4568. // trigger the next poll sooner so we can start the non-auth restore on the
  4569. // deleted replica sets.
  4570. //
  4571. if (ReplicaSetsDeleted) {
  4572. DsPollingInterval = DsPollingShortInterval;
  4573. }
  4574. GTabFreeTable(ReplicasNotInTheDs, NULL);
  4575. ReplicasNotInTheDs = NULL;
  4576. //
  4577. // Synchronize with sysvol seeding
  4578. //
  4579. LeaveCriticalSection(&MergingReplicasWithDs);
  4580. }
  4581. VOID
  4582. RcsReplicaSetRegistry(
  4583. IN PREPLICA Replica
  4584. )
  4585. /*++
  4586. Routine Description:
  4587. This function stores information about the replica set
  4588. into the registry for use by ntfrsupg /restore
  4589. (non-authoritative restore).
  4590. Arguments:
  4591. Replica
  4592. Return Value:
  4593. None.
  4594. --*/
  4595. {
  4596. #undef DEBSUB
  4597. #define DEBSUB "RcsReplicaSetRegistry:"
  4598. DWORD WStatus;
  4599. PWCHAR ReplicaSetTypeW;
  4600. DWORD NumberOfPartners;
  4601. DWORD BurFlags;
  4602. DWORD ReplicaSetTombstoned;
  4603. HKEY HSeedingsKey = 0;
  4604. WCHAR GuidW[GUID_CHAR_LEN + 1];
  4605. //
  4606. // Sanity check
  4607. //
  4608. if (!Replica ||
  4609. !Replica->SetName || !Replica->SetName->Name ||
  4610. !Replica->MemberName || !Replica->MemberName->Guid) {
  4611. DPRINT(4, ":S: WARN - Partial replica set ignored\n");
  4612. return;
  4613. }
  4614. //
  4615. // Working path to jet Database dir.
  4616. //
  4617. CfgRegWriteString(FKC_SETS_JET_PATH, NULL, FRS_RKF_CREATE_KEY, JetPath);
  4618. //
  4619. // Create the subkey for this set
  4620. //
  4621. GuidToStrW(Replica->MemberName->Guid, GuidW);
  4622. //
  4623. // Replica set name
  4624. // Replica set root path
  4625. // Replica set stage path
  4626. //
  4627. CfgRegWriteString(FKC_SET_N_REPLICA_SET_NAME,
  4628. GuidW,
  4629. FRS_RKF_CREATE_KEY,
  4630. Replica->SetName->Name);
  4631. CfgRegWriteString(FKC_SET_N_REPLICA_SET_ROOT,
  4632. GuidW,
  4633. FRS_RKF_CREATE_KEY,
  4634. Replica->Root);
  4635. CfgRegWriteString(FKC_SET_N_REPLICA_SET_STAGE,
  4636. GuidW,
  4637. FRS_RKF_CREATE_KEY,
  4638. Replica->Stage);
  4639. //
  4640. // Replica set type
  4641. //
  4642. switch (Replica->ReplicaSetType) {
  4643. case FRS_RSTYPE_ENTERPRISE_SYSVOL:
  4644. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE;
  4645. break;
  4646. case FRS_RSTYPE_DOMAIN_SYSVOL:
  4647. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_DOMAIN;
  4648. break;
  4649. case FRS_RSTYPE_DFS:
  4650. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_DFS;
  4651. break;
  4652. default:
  4653. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_OTHER;
  4654. break;
  4655. }
  4656. CfgRegWriteString(FKC_SET_N_REPLICA_SET_TYPE,
  4657. GuidW,
  4658. FRS_RKF_CREATE_KEY,
  4659. ReplicaSetTypeW);
  4660. //
  4661. // Replica Set Tombstoned
  4662. //
  4663. ReplicaSetTombstoned = (!IS_TIME_ZERO(Replica->MembershipExpires)) ? 1 : 0;
  4664. CfgRegWriteDWord(FKC_SET_N_REPLICA_SET_TOMBSTONED,
  4665. GuidW,
  4666. FRS_RKF_CREATE_KEY,
  4667. ReplicaSetTombstoned);
  4668. //
  4669. // Update the registry state under Cumulative Replica Sets for this set.
  4670. //
  4671. NumberOfPartners = GTabNumberInTable(Replica->Cxtions);
  4672. //
  4673. // If NumberOfPartners is non zero, subtract the Journal
  4674. // Cxtion entry since its not a real connection
  4675. //
  4676. if (NumberOfPartners > 0) {
  4677. NumberOfPartners -= 1;
  4678. }
  4679. CfgRegWriteDWord(FKC_CUMSET_N_NUMBER_OF_PARTNERS,
  4680. GuidW,
  4681. FRS_RKF_CREATE_KEY,
  4682. NumberOfPartners);
  4683. //
  4684. // Init Backup / Restore flags.
  4685. //
  4686. BurFlags = NTFRSAPI_BUR_FLAGS_NONE;
  4687. CfgRegWriteDWord(FKC_CUMSET_N_BURFLAGS, GuidW, FRS_RKF_CREATE_KEY, BurFlags);
  4688. //
  4689. // If done seeding then cleanup the sysvol seeding key.
  4690. //
  4691. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  4692. WStatus = CfgRegOpenKey(FKC_SYSVOL_SEEDING_SECTION_KEY,
  4693. NULL,
  4694. FRS_RKF_CREATE_KEY,
  4695. &HSeedingsKey);
  4696. CLEANUP1_WS(4, ":S: WARN - Cannot create sysvol seedings key for %ws;",
  4697. Replica->SetName->Name, WStatus, CLEANUP);
  4698. //
  4699. // Seeding is over so delete sysvol seeding key using replica set Name.
  4700. //
  4701. WStatus = RegDeleteKey(HSeedingsKey, Replica->ReplicaName->Name);
  4702. DPRINT1_WS(4, ":S: WARN - Cannot delete seeding key for %ws;",
  4703. Replica->SetName->Name, WStatus);
  4704. }
  4705. CLEANUP:
  4706. if (HSeedingsKey) {
  4707. RegCloseKey(HSeedingsKey);
  4708. }
  4709. }
  4710. BOOL
  4711. RcsReplicaIsRestored(
  4712. IN PREPLICA Replica
  4713. )
  4714. /*++
  4715. Routine Description:
  4716. Check if the replica set should be deleted because it has been
  4717. restored. Only called from RcsInitKnownReplicaSetMembers() at startup. The
  4718. BurFlags will be wiped after the replica set is recreated (if ever).
  4719. Arguments:
  4720. Replica
  4721. Return Value:
  4722. None.
  4723. --*/
  4724. {
  4725. #undef DEBSUB
  4726. #define DEBSUB "RcsReplicaIsRestored:"
  4727. DWORD WStatus;
  4728. DWORD BurFlags;
  4729. BOOL IsRestored = FALSE;
  4730. WCHAR GuidW[GUID_CHAR_LEN + 1];
  4731. //
  4732. // Sanity check
  4733. //
  4734. if (!Replica ||
  4735. !Replica->MemberName || !Replica->MemberName->Guid) {
  4736. DPRINT(0, ":S: WARN - Partial replica set ignored\n");
  4737. return IsRestored;
  4738. }
  4739. //
  4740. // Get BurFlags
  4741. // FRS_CONFIG_SECTION\Cumulative Replica Sets\Replica Sets\<guid>\BurFlags
  4742. //
  4743. GuidToStrW(Replica->MemberName->Guid, GuidW);
  4744. WStatus = CfgRegReadDWord(FKC_CUMSET_N_BURFLAGS, GuidW, FRS_RKF_CREATE_KEY, &BurFlags);
  4745. CLEANUP_WS(0, ":S: ERROR - Can't read FKC_CUMSET_N_BURFLAGS;", WStatus, CLEANUP);
  4746. if ((BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE) &&
  4747. (BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY) &&
  4748. (BurFlags & (NTFRSAPI_BUR_FLAGS_PRIMARY |
  4749. NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE))) {
  4750. //
  4751. // SUCCESS
  4752. //
  4753. IsRestored = TRUE;
  4754. DPRINT1(4, ":S: %ws has been restored\n", Replica->SetName->Name);
  4755. } else {
  4756. //
  4757. // FAILURE
  4758. //
  4759. DPRINT1(4, ":S: %ws has not been restored\n", Replica->SetName->Name);
  4760. }
  4761. CLEANUP:
  4762. // if (HCumuKey) {
  4763. // RegCloseKey(HCumuKey);
  4764. // }
  4765. // FrsFree(CumuPath);
  4766. return IsRestored;
  4767. }
  4768. VOID
  4769. RcsReplicaDeleteRegistry (
  4770. IN PREPLICA Replica
  4771. )
  4772. /*++
  4773. Routine Description:
  4774. This function deletes the information about the replica set
  4775. from the registry.
  4776. Arguments:
  4777. Replica
  4778. Return Value:
  4779. None.
  4780. --*/
  4781. {
  4782. #undef DEBSUB
  4783. #define DEBSUB "RcsReplicaDeleteRegistry:"
  4784. DWORD WStatus;
  4785. HKEY HKey = 0;
  4786. HKEY HAllSetsKey = 0;
  4787. HKEY HCumusKey = 0;
  4788. WCHAR GuidW[GUID_CHAR_LEN + 1];
  4789. //
  4790. // Sanity check
  4791. //
  4792. if (!Replica ||
  4793. !Replica->SetName || !Replica->SetName->Name ||
  4794. !Replica->MemberName || !Replica->MemberName->Guid) {
  4795. DPRINT(0, ":S: WARN - Partial replica set ignored\n");
  4796. return;
  4797. }
  4798. //
  4799. // Delete old state from the registry
  4800. //
  4801. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4802. FRS_CONFIG_SECTION,
  4803. 0,
  4804. KEY_ALL_ACCESS,
  4805. &HKey);
  4806. CLEANUP1_WS(0, ":S: WARN - Cannot open parameters for %ws;",
  4807. Replica->SetName->Name, WStatus, CLEANUP);
  4808. //
  4809. // Create the subkey for all sets
  4810. //
  4811. WStatus = RegCreateKey(HKey, FRS_SETS_KEY, &HAllSetsKey);
  4812. CLEANUP1_WS(0, ":S: WARN - Cannot create sets key for %ws;",
  4813. Replica->SetName->Name, WStatus, CLEANUP);
  4814. //
  4815. // Delete the subkey for this set
  4816. //
  4817. GuidToStrW(Replica->MemberName->Guid, GuidW);
  4818. WStatus = RegDeleteKey(HAllSetsKey, GuidW);
  4819. CLEANUP1_WS(0, ":S: WARN - Cannot delete set key for %ws;",
  4820. Replica->SetName->Name, WStatus, CLEANUP);
  4821. //
  4822. // Cumulative Replica Sets
  4823. //
  4824. //
  4825. // Create the subkey for all sets
  4826. //
  4827. WStatus = RegCreateKey(HKey, FRS_CUMULATIVE_SETS_KEY, &HCumusKey);
  4828. CLEANUP1_WS(0, ":S: WARN - Cannot create cumulative sets key for %ws;",
  4829. Replica->SetName->Name, WStatus, CLEANUP);
  4830. //
  4831. // Delete the subkey for this set
  4832. //
  4833. WStatus = RegDeleteKey(HCumusKey, GuidW);
  4834. CLEANUP1_WS(0, ":S: WARN - Cannot delete cumulative key for %ws;",
  4835. Replica->SetName->Name, WStatus, CLEANUP);
  4836. CLEANUP:
  4837. if (HKey) {
  4838. RegCloseKey(HKey);
  4839. }
  4840. if (HAllSetsKey) {
  4841. RegCloseKey(HAllSetsKey);
  4842. }
  4843. if (HCumusKey) {
  4844. RegCloseKey(HCumusKey);
  4845. }
  4846. }
  4847. VOID
  4848. RcsReplicaClearRegistry(
  4849. VOID
  4850. )
  4851. /*++
  4852. Routine Description:
  4853. This function deletes all of the replica set information in the registry.
  4854. This function should only be called after enumerating the configrecords.
  4855. Arguments:
  4856. None.
  4857. Return Value:
  4858. None.
  4859. --*/
  4860. {
  4861. #undef DEBSUB
  4862. #define DEBSUB "RcsReplicaClearRegistry:"
  4863. DWORD WStatus;
  4864. HKEY HKey = 0;
  4865. HKEY HAllSetsKey = 0;
  4866. WCHAR KeyBuf[MAX_PATH + 1];
  4867. //
  4868. // Empty the replica set info out of the registry
  4869. //
  4870. //
  4871. // Set new state in the registry
  4872. //
  4873. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4874. FRS_CONFIG_SECTION,
  4875. 0,
  4876. KEY_ALL_ACCESS,
  4877. &HKey);
  4878. CLEANUP_WS(0, "WARN - Cannot open parameters for delete sets", WStatus, CLEANUP);
  4879. //
  4880. // Create the subkey for all sets
  4881. //
  4882. WStatus = RegCreateKey(HKey, FRS_SETS_KEY, &HAllSetsKey);
  4883. CLEANUP_WS(0, "WARN - Cannot create sets key for delete sets", WStatus, CLEANUP);
  4884. //
  4885. // Delete the subkeys
  4886. //
  4887. do {
  4888. WStatus = RegEnumKey(HAllSetsKey, 0, KeyBuf, MAX_PATH + 1);
  4889. if (WIN_SUCCESS(WStatus)) {
  4890. WStatus = RegDeleteKey(HAllSetsKey, KeyBuf);
  4891. }
  4892. } while (WIN_SUCCESS(WStatus));
  4893. if (WStatus != ERROR_NO_MORE_ITEMS) {
  4894. CLEANUP_WS(0, "WARN - Cannot delete all keys", WStatus, CLEANUP);
  4895. }
  4896. CLEANUP:
  4897. if (HKey) {
  4898. RegCloseKey(HKey);
  4899. }
  4900. if (HAllSetsKey) {
  4901. RegCloseKey(HAllSetsKey);
  4902. }
  4903. }
  4904. DWORD
  4905. RcsCreateReplicaSetMember(
  4906. IN PREPLICA Replica
  4907. )
  4908. /*++
  4909. Routine Description:
  4910. Create a database record for Replica.
  4911. Arguments:
  4912. Replica
  4913. Return Value:
  4914. An Frs Error status
  4915. --*/
  4916. {
  4917. #undef DEBSUB
  4918. #define DEBSUB "RcsCreateReplicaSetMember:"
  4919. ULONG Status;
  4920. ULONG FStatus;
  4921. ULONG WStatus;
  4922. ULONG RootLen;
  4923. ULONG i, Rest;
  4924. PVOID Key;
  4925. PCXTION Cxtion;
  4926. PCOMMAND_PACKET Cmd = NULL;
  4927. PTABLE_CTX TableCtx = NULL;
  4928. PWCHAR WStatusUStr, FStatusUStr;
  4929. #define CXTION_EVENT_RPT_MAX 8
  4930. PWCHAR InWStr, OutWStr, WStrArray[CXTION_EVENT_RPT_MAX];
  4931. #define CXTION_STR_MAX 256
  4932. WCHAR CxtionStr[CXTION_STR_MAX];
  4933. extern ULONGLONG ActiveChange;
  4934. Replica->FStatus = FrsErrorSuccess;
  4935. //
  4936. // We are creating a new replica set member. Set the Cnf flag to CONFIG_FLAG_SEEDING.
  4937. // This will trigger a serialvvjoin for this replica set.
  4938. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_PRIMARY)) {
  4939. SetFlag(Replica->CnfFlags, CONFIG_FLAG_SEEDING);
  4940. }
  4941. //
  4942. // Table context?
  4943. //
  4944. TableCtx = DbsCreateTableContext(ConfigTablex);
  4945. //
  4946. // Submitted to the db command server
  4947. //
  4948. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  4949. Replica, // Replica,
  4950. CMD_CREATE_REPLICA_SET_MEMBER, // CmdRequest,
  4951. TableCtx, // TableCtx,
  4952. NULL, // CallContext,
  4953. 0, // TableType,
  4954. 0, // AccessRequest,
  4955. 0, // IndexType,
  4956. NULL, // KeyValue,
  4957. 0, // KeyValueLength,
  4958. FALSE); // Submit
  4959. //
  4960. // Don't free the packet when the command completes.
  4961. //
  4962. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  4963. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_CREATE_REPLICA_SET_MEMBER");
  4964. //
  4965. // SUBMIT DB Cmd and wait for completion.
  4966. //
  4967. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  4968. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  4969. //
  4970. // If wait or database op failed
  4971. //
  4972. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  4973. //
  4974. // If wait / submit failed then let caller know cmd srv submit failed.
  4975. //
  4976. if (FRS_SUCCESS(Replica->FStatus)) {
  4977. Replica->FStatus = FrsErrorCmdSrvFailed;
  4978. }
  4979. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Create Replica failed;",
  4980. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  4981. DPRINT_WS(0, "ERROR: Create Replica DB Command failed", WStatus);
  4982. //
  4983. // Post the failure in the event log.
  4984. //
  4985. WStatusUStr = FrsAtoW(ErrLabelW32(WStatus));
  4986. FStatusUStr = FrsAtoW(ErrLabelFrs(Replica->FStatus));
  4987. EPRINT8(EVENT_FRS_REPLICA_SET_CREATE_FAIL,
  4988. Replica->SetName->Name,
  4989. ComputerDnsName,
  4990. Replica->MemberName->Name,
  4991. Replica->Root,
  4992. Replica->Stage,
  4993. JetPath,
  4994. WStatusUStr,
  4995. FStatusUStr);
  4996. FrsFree(WStatusUStr);
  4997. FrsFree(FStatusUStr);
  4998. goto out;
  4999. }
  5000. //
  5001. // Post the success in the event log.
  5002. //
  5003. EPRINT6(EVENT_FRS_REPLICA_SET_CREATE_OK,
  5004. Replica->SetName->Name,
  5005. ComputerDnsName,
  5006. Replica->MemberName->Name,
  5007. Replica->Root,
  5008. Replica->Stage,
  5009. JetPath);
  5010. //
  5011. // Increment the Replica Sets Created Counter
  5012. //
  5013. PM_INC_CTR_SERVICE(PMTotalInst, RSCreated, 1);
  5014. InWStr = FrsGetResourceStr(IDS_INBOUND);
  5015. OutWStr = FrsGetResourceStr(IDS_OUTBOUND);
  5016. i = 0;
  5017. //
  5018. // Create the cxtions
  5019. //
  5020. Key = NULL;
  5021. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  5022. Key = NULL;
  5023. //
  5024. // Skip inconsistent cxtions and journal cxtions
  5025. //
  5026. if ((!Cxtion->JrnlCxtion) &&
  5027. CxtionFlagIs(Cxtion, CXTION_FLAGS_CONSISTENT)) {
  5028. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, submit cmd CMD_OUTLOG_ADD_NEW_PARTNER");
  5029. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_ADD_NEW_PARTNER);
  5030. CXTION_STATE_TRACE(3, Cxtion, Replica, FStatus, "F, CMD_OUTLOG_ADD_NEW_PARTNER return");
  5031. //
  5032. // Build a string for the event log.
  5033. //
  5034. if (Cxtion->PartnerDnsName != NULL) {
  5035. _snwprintf(CxtionStr, CXTION_STR_MAX, L"%ws \"%ws\"",
  5036. Cxtion->Inbound ? InWStr : OutWStr,
  5037. Cxtion->PartnerDnsName);
  5038. CxtionStr[CXTION_STR_MAX-1] = UNICODE_NULL;
  5039. WStrArray[i++] = FrsWcsDup(CxtionStr);
  5040. if (i == CXTION_EVENT_RPT_MAX) {
  5041. EPRINT9(EVENT_FRS_REPLICA_SET_CXTIONS, Replica->SetName->Name,
  5042. WStrArray[0], WStrArray[1], WStrArray[2], WStrArray[3],
  5043. WStrArray[4], WStrArray[5], WStrArray[6], WStrArray[7]);
  5044. for (i = 0; i < CXTION_EVENT_RPT_MAX; i++) {
  5045. WStrArray[i] = FrsFree(WStrArray[i]);
  5046. }
  5047. i = 0;
  5048. }
  5049. }
  5050. }
  5051. //
  5052. // Done with this cxtion
  5053. //
  5054. GTabDelete(Replica->Cxtions, Cxtion->Name->Guid, NULL, FrsFreeType);
  5055. }
  5056. if (i > 0) {
  5057. //
  5058. // print any left over.
  5059. //
  5060. Rest = i;
  5061. for (i = Rest; i < CXTION_EVENT_RPT_MAX; i++) {
  5062. WStrArray[i] = L" ";
  5063. }
  5064. EPRINT9(EVENT_FRS_REPLICA_SET_CXTIONS, Replica->SetName->Name,
  5065. WStrArray[0], WStrArray[1], WStrArray[2], WStrArray[3],
  5066. WStrArray[4], WStrArray[5], WStrArray[6], WStrArray[7]);
  5067. for (i = 0; i < Rest; i++) {
  5068. WStrArray[i] = FrsFree(WStrArray[i]);
  5069. }
  5070. }
  5071. FrsFree(InWStr);
  5072. FrsFree(OutWStr);
  5073. //
  5074. // Set the OID data structure which is a part of the
  5075. // counter data structure stored in the hash table
  5076. // Add ReplicaSet Instance to the registry
  5077. //
  5078. if (Replica->Root != NULL) {
  5079. DPRINT(5, "PERFMON:Adding Set:REPLICA.C:1\n");
  5080. AddPerfmonInstance(REPLICASET, Replica->PerfRepSetData, Replica->Root);
  5081. }
  5082. //
  5083. // Add to the replica tables (by guid and by number)
  5084. //
  5085. Replica->Queue = FrsAlloc(sizeof(FRS_QUEUE));
  5086. FrsInitializeQueue(Replica->Queue, &ReplicaCmdServer.Control);
  5087. GTabInsertEntry(ReplicasByGuid, Replica, Replica->ReplicaName->Guid, NULL);
  5088. GTabInsertEntry(ReplicasByNumber, Replica, &Replica->ReplicaNumber, NULL);
  5089. //
  5090. // WARNING: NO Failure return is allowed after this point because the
  5091. // Replica struct is pointed at by a number of other data structs like the
  5092. // Three above. A Failure return here causes our caller to free the replica
  5093. // struct but of course it does that without first pulling it out of any of
  5094. // the above or calling the DB Service to tell it that the replica struct is
  5095. // going away This is unfortunate but its 7/8/99 and too late to clean this up.
  5096. //
  5097. //
  5098. // Set registry value "FilesNotToBackup"
  5099. //
  5100. CfgFilesNotToBackup(ReplicasByGuid);
  5101. //
  5102. // Open the replica set
  5103. //
  5104. RcsOpenReplicaSetMember(Replica);
  5105. //
  5106. // See comment above.
  5107. //
  5108. Replica->FStatus = FrsErrorSuccess;
  5109. //if (Replica->FStatus != FrsErrorSuccess) {
  5110. // goto out;
  5111. //}
  5112. //
  5113. // Insert replica information into the registry
  5114. //
  5115. RcsReplicaSetRegistry(Replica);
  5116. out:
  5117. if (Cmd) {
  5118. FrsFreeCommand(Cmd, NULL);
  5119. }
  5120. if (TableCtx) {
  5121. DbsFreeTableContext(TableCtx, 0);
  5122. }
  5123. if (!FRS_SUCCESS(Replica->FStatus)) {
  5124. //
  5125. // Ds poll thread will restart the replica during the next
  5126. // polling cycle if ActiveChange is set to 0.
  5127. //
  5128. ActiveChange = 0;
  5129. }
  5130. return Replica->FStatus;
  5131. }
  5132. BOOL
  5133. RcsReplicaHasExpired(
  5134. IN PREPLICA Replica
  5135. )
  5136. /*++
  5137. Routine Description:
  5138. Has this replica's tombstone expired?
  5139. Arguments:
  5140. Replica
  5141. Return Value:
  5142. TRUE - Tombstone has expired.
  5143. FALSE - Not tombstoned or tombstone has not expired.
  5144. --*/
  5145. {
  5146. #undef DEBSUB
  5147. #define DEBSUB "RcsReplicaHasExpired:"
  5148. FILETIME FileTime;
  5149. ULONGLONG Now;
  5150. //
  5151. // Is it tombstoned?
  5152. //
  5153. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  5154. GetSystemTimeAsFileTime(&FileTime);
  5155. COPY_TIME(&Now, &FileTime);
  5156. //
  5157. // Has it expired?
  5158. //
  5159. if (Now > Replica->MembershipExpires) {
  5160. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Replica has expired");
  5161. return TRUE;
  5162. }
  5163. }
  5164. //
  5165. // Not expired
  5166. //
  5167. return FALSE;
  5168. }
  5169. PREPLICA
  5170. RcsFindSysVolByType(
  5171. IN DWORD ReplicaSetType
  5172. )
  5173. /*++
  5174. Routine Description:
  5175. Find the sysvol with the indicated type.
  5176. Arguments:
  5177. ReplicaSetType
  5178. Return Value:
  5179. None.
  5180. --*/
  5181. {
  5182. #undef DEBSUB
  5183. #define DEBSUB "RcsFindSysVolByType:"
  5184. PREPLICA Replica;
  5185. PVOID Key;
  5186. //
  5187. // Find a match for the sysvol by name
  5188. //
  5189. Key = NULL;
  5190. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  5191. if (!FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType)) {
  5192. continue;
  5193. }
  5194. //
  5195. // SysVol types match
  5196. //
  5197. if (Replica->ReplicaSetType == ReplicaSetType) {
  5198. //
  5199. // Don't return expired replicas
  5200. //
  5201. if (RcsReplicaHasExpired(Replica)) {
  5202. DPRINT2(4, ":S: %ws\\%ws: IGNORING, tombstoned expired.\n",
  5203. Replica->SetName->Name, Replica->MemberName->Name);
  5204. continue;
  5205. }
  5206. return Replica;
  5207. }
  5208. }
  5209. return NULL;
  5210. }
  5211. PREPLICA
  5212. RcsFindSysVolByName(
  5213. IN PWCHAR ReplicaSetName
  5214. )
  5215. /*++
  5216. Routine Description:
  5217. The replica set from the Ds could not be located by its Ds-object guid.
  5218. This may be a sysvol that has been seeded but hasn't picked up its
  5219. guids from its Ds objects. Try to find the sysvol by name.
  5220. Arguments:
  5221. ReplicaSetName
  5222. Return Value:
  5223. None.
  5224. --*/
  5225. {
  5226. #undef DEBSUB
  5227. #define DEBSUB "RcsFindSysVolByName:"
  5228. PREPLICA Replica;
  5229. PVOID Key;
  5230. FILETIME FileTime;
  5231. ULONGLONG Now;
  5232. //
  5233. // Find a match for the sysvol by name
  5234. //
  5235. Key = NULL;
  5236. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  5237. if (!FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType)) {
  5238. continue;
  5239. }
  5240. if (WSTR_EQ(ReplicaSetName, Replica->ReplicaName->Name)) {
  5241. //
  5242. // Don't return expired replicas
  5243. //
  5244. if (RcsReplicaHasExpired(Replica)) {
  5245. DPRINT2(4, ":S: %ws\\%ws: IGNORING, tombstoned expired.\n",
  5246. Replica->SetName->Name, Replica->MemberName->Name);
  5247. continue;
  5248. }
  5249. return Replica;
  5250. }
  5251. }
  5252. return NULL;
  5253. }
  5254. PREPLICA
  5255. RcsFindNextReplica(
  5256. IN PVOID *Key
  5257. )
  5258. /*++
  5259. Routine Description:
  5260. Return the next replica in the active replication subsystem.
  5261. Arguments:
  5262. Key
  5263. Return Value:
  5264. Replica or NULL.
  5265. --*/
  5266. {
  5267. #undef DEBSUB
  5268. #define DEBSUB "RcsFindNextReplica:"
  5269. //
  5270. // Next replica
  5271. //
  5272. return GTabNextDatum(ReplicasByGuid, Key);
  5273. }
  5274. VOID
  5275. RcsMergeReplicaFromDs(
  5276. IN PREPLICA DsReplica
  5277. )
  5278. /*++
  5279. Routine Description:
  5280. Merge this replica from the DS with the active replicas.
  5281. Arguments:
  5282. DsReplica
  5283. Return Value:
  5284. None.
  5285. --*/
  5286. {
  5287. #undef DEBSUB
  5288. #define DEBSUB "RcsMergeReplicaFromDs:"
  5289. PVOID Key;
  5290. PREPLICA Replica;
  5291. DPRINT(4, ":S: Merge Replica from the DS\n");
  5292. FRS_PRINT_TYPE(4, DsReplica);
  5293. //
  5294. // If the replica is not in the table, create it
  5295. //
  5296. Replica = GTabLookup(ReplicasByGuid, DsReplica->ReplicaName->Guid, NULL);
  5297. if (Replica && REPLICA_STATE_NEEDS_RESTORE(Replica->ServiceState)) {
  5298. //
  5299. // This replica is on the fault list and will be deleted at the end
  5300. // of poll when we process the fault list. We should not try to
  5301. // do anything with this replica. Just remove it from ReplicasNotInTheDs
  5302. // table and free the DsReplica structure.
  5303. //
  5304. GTabDelete(ReplicasNotInTheDs, Replica->ReplicaName->Guid, NULL, NULL);
  5305. FrsFreeType(DsReplica);
  5306. return;
  5307. }
  5308. //
  5309. // Might be a sysvol that has been seeded but hasn't picked up
  5310. // its final guids from its Ds objects. Try to find it by name.
  5311. //
  5312. if (!Replica &&
  5313. FRS_RSTYPE_IS_SYSVOL(DsReplica->ReplicaSetType)) {
  5314. //
  5315. // Pretend there isn't a match if the replica has already
  5316. // been merged with the info in the DS. We only want to merge once.
  5317. // We deduce that the merge hasn't occured if the replica set
  5318. // guid and the root guid are the same. They should be different
  5319. // since the replica set guid wasn't available when the root
  5320. // guid was created.
  5321. //
  5322. // Otherwise, we could end up with a sysvol replica that
  5323. // claims its root path is an old sysvol root instead of a new
  5324. // sysvol root (assuming ntfrsupg was run twice).
  5325. //
  5326. // The old sysvol will be tombstoned and will eventually
  5327. // be deleted.
  5328. //
  5329. // Note: seeding during dcpromo is now broken since root guid
  5330. // is created when set is created in the db and so
  5331. // never matches the set guid. fix if seeding during
  5332. // dcpromo is resurrected (with CnfFlag)
  5333. //
  5334. Replica = RcsFindSysVolByName(DsReplica->ReplicaName->Name);
  5335. if (Replica && !GUIDS_EQUAL(Replica->SetName->Guid,
  5336. Replica->ReplicaRootGuid)) {
  5337. Replica = NULL;
  5338. }
  5339. }
  5340. if (Replica) {
  5341. //
  5342. // Replica still exists in the DS; don't delete it
  5343. //
  5344. GTabDelete(ReplicasNotInTheDs, Replica->ReplicaName->Guid, NULL, NULL);
  5345. //
  5346. // Tell the replica to merge with the information from the DS
  5347. // and to retry any failed or new startup operations like
  5348. // starting the journal and joining new connections.
  5349. //
  5350. if (DsReplica->Consistent) {
  5351. (VOID) RcsSubmitReplicaSync(Replica, DsReplica, NULL, CMD_START);
  5352. } else {
  5353. //
  5354. // WARN: it looks like it gets freed here but still lives in the
  5355. // ReplicasByGuid table --- AV later if table enumed.
  5356. // RcsBeginMergeWithDs() does an enum of this table.
  5357. //
  5358. FrsFreeType(DsReplica);
  5359. }
  5360. } else {
  5361. //
  5362. // Insert the replica into the database and add it to the table
  5363. // of active replicas. Comm packets will continue to be discarded
  5364. // because the replica is not yet "accepting" remote change orders
  5365. //
  5366. // Replica sets for sysvols must exist in the database prior to
  5367. // the entries in the Ds. If the opposite is true then the entry
  5368. // in the Ds is bogus; probably the result of the Ds polling thread
  5369. // being unabled to delete the Ds objects after a dcdemote. In
  5370. // any case, ignore the Ds.
  5371. //
  5372. if (DsReplica->Consistent &&
  5373. FRS_SUCCESS(RcsCreateReplicaSetMember(DsReplica))) {
  5374. RcsSubmitReplicaSync(DsReplica, NULL, NULL, CMD_START);
  5375. } else {
  5376. //
  5377. // WARN: The above could happen here too if Consistent is false
  5378. // and DsReplica is in a table.
  5379. // Also happens if RcsCreateReplicaSetMember() fails.
  5380. // since it can fail after DsReplica is added to.
  5381. // the ReplicasByGuid and ReplicasByNumber tables. Sigh.
  5382. //
  5383. FrsFreeType(DsReplica);
  5384. }
  5385. }
  5386. }
  5387. VOID
  5388. RcsMergeReplicaGName(
  5389. IN PREPLICA Replica,
  5390. IN PWCHAR Tag,
  5391. IN PGNAME GName,
  5392. IN PGNAME NewGName
  5393. )
  5394. /*++
  5395. Routine Description:
  5396. Update the Replica with new information from NewReplica.
  5397. Arguments:
  5398. Replica
  5399. GName
  5400. NewGName
  5401. Return Value:
  5402. None.
  5403. --*/
  5404. {
  5405. #undef DEBSUB
  5406. #define DEBSUB "RcsMergeReplicaGName:"
  5407. //
  5408. // Name
  5409. //
  5410. if (WSTR_NE(GName->Name, NewGName->Name)) {
  5411. DPRINT5(0, "++ %ws\\%ws - Changing %ws name from %ws to %ws.\n",
  5412. Replica->ReplicaName->Name, Replica->MemberName->Name, Tag,
  5413. GName->Name, NewGName->Name);
  5414. FrsDsSwapPtrs(&GName->Name, &NewGName->Name);
  5415. Replica->NeedsUpdate = TRUE;
  5416. }
  5417. //
  5418. // Guid
  5419. //
  5420. if (!GUIDS_EQUAL(GName->Guid, NewGName->Guid)) {
  5421. DPRINT3(0, "++ %ws\\%ws - Changing guid for %ws.\n",
  5422. Replica->ReplicaName->Name, Replica->MemberName->Name, Tag);
  5423. FrsDsSwapPtrs(&GName->Guid, &NewGName->Guid);
  5424. Replica->NeedsUpdate = TRUE;
  5425. }
  5426. }
  5427. VOID
  5428. RcsMergeReplicaFields(
  5429. IN PREPLICA Replica,
  5430. IN PREPLICA NewReplica
  5431. )
  5432. /*++
  5433. Routine Description:
  5434. Update the Replica with new information from NewReplica.
  5435. Arguments:
  5436. Replica - active replica
  5437. NewReplica
  5438. Return Value:
  5439. None.
  5440. --*/
  5441. {
  5442. #undef DEBSUB
  5443. #define DEBSUB "RcsMergeReplicaFields:"
  5444. BOOL IsSysVol;
  5445. PWCHAR DirFilterList;
  5446. PWCHAR TmpList;
  5447. UNICODE_STRING TempUStr;
  5448. if (NewReplica == NULL) {
  5449. return;
  5450. }
  5451. //
  5452. // CHECK FIELDS THAT CAN'T CHANGE
  5453. //
  5454. //
  5455. // Replica type
  5456. //
  5457. if (Replica->ReplicaSetType != NewReplica->ReplicaSetType) {
  5458. DPRINT4(0, "++ ERROR - %ws\\%ws - Changing replica type from %d to %d is not allowed.\n",
  5459. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5460. Replica->ReplicaSetType, NewReplica->ReplicaSetType);
  5461. NewReplica->Consistent = FALSE;
  5462. return;
  5463. }
  5464. //
  5465. // ReplicaName Guid
  5466. //
  5467. IsSysVol = FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType);
  5468. if (!GUIDS_EQUAL(Replica->ReplicaName->Guid, NewReplica->ReplicaName->Guid)) {
  5469. if (!IsSysVol) {
  5470. DPRINT2(0, "++ ERROR - %ws\\%ws - Changing replica guid is not allowed.\n",
  5471. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5472. return;
  5473. }
  5474. }
  5475. //
  5476. // Set Guid
  5477. //
  5478. if (!GUIDS_EQUAL(Replica->SetName->Guid, NewReplica->SetName->Guid)) {
  5479. if (!IsSysVol) {
  5480. DPRINT2(0, "++ ERROR - %ws\\%ws - Changing set guid is not allowed.\n",
  5481. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5482. return;
  5483. }
  5484. }
  5485. //
  5486. // Root Guid
  5487. // Cannot be changed because it is created whenever the set
  5488. // is created in the DB. The root guid from the DS is always
  5489. // ignored.
  5490. //
  5491. // if (!GUIDS_EQUAL(Replica->ReplicaRootGuid, NewReplica->ReplicaRootGuid)) {
  5492. // if (!IsSysVol) {
  5493. // DPRINT2(0, "++ ERROR - %ws\\%ws - Changing root guid "
  5494. // "is not allowed.\n",
  5495. // Replica->ReplicaName->Name,
  5496. // Replica->MemberName->Name);
  5497. // return;
  5498. // }
  5499. // }
  5500. //
  5501. // Stage Path.
  5502. //
  5503. if (WSTR_NE(Replica->Stage, NewReplica->Stage)) {
  5504. DPRINT3(3, "The staging path for the replica set (%ws) has changed from (%ws) to (%ws).\n",
  5505. Replica->SetName->Name, Replica->Stage, NewReplica->Stage);
  5506. EPRINT3(EVENT_FRS_STAGE_HAS_CHANGED, Replica->SetName->Name, Replica->Stage,
  5507. NewReplica->Stage);
  5508. FrsFree(Replica->NewStage);
  5509. Replica->NewStage = FrsWcsDup(NewReplica->Stage);
  5510. Replica->NeedsUpdate = TRUE;
  5511. }
  5512. //
  5513. // Updating the replica's guid is tricky since the guid is
  5514. // used by the other subsystems, like RPC, to find a replica
  5515. // set. Both the old and new guid are temporarily in the
  5516. // lookup table. Once the guid is updated, the old entry is
  5517. // deleted.
  5518. //
  5519. if (!GUIDS_EQUAL(Replica->ReplicaName->Guid, NewReplica->ReplicaName->Guid)) {
  5520. DPRINT2(0, "++ %ws\\%ws - Changing guid for Replica.\n",
  5521. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5522. GTabInsertEntry(ReplicasByGuid, Replica, NewReplica->ReplicaName->Guid, NULL);
  5523. FrsDsSwapPtrs(&Replica->ReplicaName->Guid, &NewReplica->ReplicaName->Guid);
  5524. GTabDelete(ReplicasByGuid, NewReplica->ReplicaName->Guid, NULL, NULL);
  5525. COPY_GUID(NewReplica->ReplicaName->Guid, Replica->ReplicaName->Guid);
  5526. Replica->NeedsUpdate = TRUE;
  5527. }
  5528. //
  5529. // FIELDS THAT CAN CHANGE
  5530. //
  5531. //
  5532. // ReplicaName (note that the guid was handled above)
  5533. //
  5534. RcsMergeReplicaGName(Replica, L"Replica", Replica->ReplicaName, NewReplica->ReplicaName);
  5535. //
  5536. // MemberName
  5537. //
  5538. RcsMergeReplicaGName(Replica, L"Member", Replica->MemberName, NewReplica->MemberName);
  5539. //
  5540. // SetName
  5541. //
  5542. RcsMergeReplicaGName(Replica, L"Set", Replica->SetName, NewReplica->SetName);
  5543. //
  5544. // Schedule
  5545. //
  5546. if (Replica->Schedule || NewReplica->Schedule) {
  5547. if ((Replica->Schedule && !NewReplica->Schedule) ||
  5548. (!Replica->Schedule && NewReplica->Schedule) ||
  5549. (Replica->Schedule->Size != NewReplica->Schedule->Size) ||
  5550. (memcmp(Replica->Schedule,
  5551. NewReplica->Schedule,
  5552. Replica->Schedule->Size))) {
  5553. DPRINT2(0, "++ %ws\\%ws - Changing replica schedule.\n",
  5554. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5555. FrsDsSwapPtrs(&Replica->Schedule, &NewReplica->Schedule);
  5556. Replica->NeedsUpdate = TRUE;
  5557. }
  5558. }
  5559. //
  5560. // File Exclusion Filter
  5561. //
  5562. if (Replica->FileFilterList || NewReplica->FileFilterList) {
  5563. if ((Replica->FileFilterList && !NewReplica->FileFilterList) ||
  5564. (!Replica->FileFilterList && NewReplica->FileFilterList) ||
  5565. WSTR_NE(Replica->FileFilterList, NewReplica->FileFilterList)) {
  5566. DPRINT4(0, "++ %ws\\%ws - Changing file filter from %ws to %ws.\n",
  5567. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5568. Replica->FileFilterList, NewReplica->FileFilterList);
  5569. FrsDsSwapPtrs(&Replica->FileFilterList, &NewReplica->FileFilterList);
  5570. if (!Replica->FileFilterList) {
  5571. Replica->FileFilterList = FRS_DS_COMPOSE_FILTER_LIST(
  5572. NULL,
  5573. RegistryFileExclFilterList,
  5574. DEFAULT_FILE_FILTER_LIST);
  5575. }
  5576. RtlInitUnicodeString(&TempUStr, Replica->FileFilterList);
  5577. LOCK_REPLICA(Replica);
  5578. FrsLoadNameFilter(&TempUStr, &Replica->FileNameFilterHead);
  5579. UNLOCK_REPLICA(Replica);
  5580. Replica->NeedsUpdate = TRUE;
  5581. }
  5582. }
  5583. //
  5584. // File Inclusion Filter (Registry only)
  5585. //
  5586. if (Replica->FileInclFilterList || NewReplica->FileInclFilterList) {
  5587. if ((Replica->FileInclFilterList && !NewReplica->FileInclFilterList) ||
  5588. (!Replica->FileInclFilterList && NewReplica->FileInclFilterList) ||
  5589. WSTR_NE(Replica->FileInclFilterList, NewReplica->FileInclFilterList)) {
  5590. DPRINT4(0, "++ %ws\\%ws - Changing file Inclusion filter from %ws to %ws.\n",
  5591. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5592. Replica->FileInclFilterList, NewReplica->FileInclFilterList);
  5593. FrsDsSwapPtrs(&Replica->FileInclFilterList, &NewReplica->FileInclFilterList);
  5594. RtlInitUnicodeString(&TempUStr, Replica->FileInclFilterList);
  5595. LOCK_REPLICA(Replica);
  5596. FrsLoadNameFilter(&TempUStr, &Replica->FileNameInclFilterHead);
  5597. UNLOCK_REPLICA(Replica);
  5598. Replica->NeedsUpdate = TRUE;
  5599. }
  5600. }
  5601. //
  5602. // Directory Filter
  5603. //
  5604. if (Replica->DirFilterList || NewReplica->DirFilterList) {
  5605. if ((Replica->DirFilterList && !NewReplica->DirFilterList) ||
  5606. (!Replica->DirFilterList && NewReplica->DirFilterList) ||
  5607. WSTR_NE(Replica->DirFilterList, NewReplica->DirFilterList)) {
  5608. DPRINT4(0, "++ %ws\\%ws - Changing dir filter from %ws to %ws.\n",
  5609. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5610. Replica->DirFilterList, NewReplica->DirFilterList);
  5611. FrsDsSwapPtrs(&Replica->DirFilterList, &NewReplica->DirFilterList);
  5612. if (!Replica->DirFilterList) {
  5613. Replica->DirFilterList = FRS_DS_COMPOSE_FILTER_LIST(
  5614. NULL,
  5615. RegistryDirExclFilterList,
  5616. DEFAULT_DIR_FILTER_LIST);
  5617. }
  5618. //
  5619. // Add the pre-install dir, the pre-existing dir and the
  5620. // replication suppression prefix name to the dir filter list.
  5621. //
  5622. DirFilterList = FrsWcsCat3(NTFRS_PREINSTALL_DIRECTORY,
  5623. L",",
  5624. Replica->DirFilterList);
  5625. TmpList = FrsWcsCat3(NTFRS_PREEXISTING_DIRECTORY, L",", DirFilterList);
  5626. FrsFree(DirFilterList);
  5627. DirFilterList = TmpList;
  5628. #if 0
  5629. //
  5630. // This workaround did not solve the DFS dir create problem because the
  5631. // later rename of the dir to the final target name is treated like
  5632. // a movein operation so the dir replicates which was what we were trying
  5633. // to avoid since that led to name morph collisions on other DFS alternates
  5634. // which were doing the same thing.
  5635. //
  5636. TmpList = FrsWcsCat3(NTFRS_REPL_SUPPRESS_PREFIX, L"*,", DirFilterList);
  5637. FrsFree(DirFilterList);
  5638. DirFilterList = TmpList;
  5639. #endif
  5640. DPRINT3(0, "++ %ws\\%ws - New dir filter: %ws\n",
  5641. Replica->ReplicaName->Name, Replica->MemberName->Name, DirFilterList);
  5642. RtlInitUnicodeString(&TempUStr, DirFilterList);
  5643. LOCK_REPLICA(Replica);
  5644. FrsLoadNameFilter(&TempUStr, &Replica->DirNameFilterHead);
  5645. UNLOCK_REPLICA(Replica);
  5646. FrsFree(DirFilterList);
  5647. Replica->NeedsUpdate = TRUE;
  5648. }
  5649. }
  5650. //
  5651. // Directory Inclusion Filter (Registry only)
  5652. //
  5653. if (Replica->DirInclFilterList || NewReplica->DirInclFilterList) {
  5654. if ((Replica->DirInclFilterList && !NewReplica->DirInclFilterList) ||
  5655. (!Replica->DirInclFilterList && NewReplica->DirInclFilterList) ||
  5656. WSTR_NE(Replica->DirInclFilterList, NewReplica->DirInclFilterList)) {
  5657. DPRINT4(0, "++ %ws\\%ws - Changing dir inclusion filter from %ws to %ws.\n",
  5658. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5659. Replica->DirInclFilterList, NewReplica->DirInclFilterList);
  5660. FrsDsSwapPtrs(&Replica->DirInclFilterList, &NewReplica->DirInclFilterList);
  5661. RtlInitUnicodeString(&TempUStr, Replica->DirInclFilterList);
  5662. LOCK_REPLICA(Replica);
  5663. FrsLoadNameFilter(&TempUStr, &Replica->DirNameInclFilterHead);
  5664. UNLOCK_REPLICA(Replica);
  5665. Replica->NeedsUpdate = TRUE;
  5666. }
  5667. }
  5668. //
  5669. // The Replica->CnfFlags are only valid when the replica is created.
  5670. // They are ignored thereafter.
  5671. //
  5672. }
  5673. PCXTION
  5674. RcsCreateSeedingCxtion(
  5675. IN PREPLICA Replica,
  5676. IN PCXTION SeedingCxtion
  5677. )
  5678. /*++
  5679. Routine Description:
  5680. Create a seeding cxtion if needed.
  5681. This function may open and read the registry.
  5682. This function may RPC to another computer.
  5683. Arguments:
  5684. Replica - active replica
  5685. SeedingCxtion - seeding cxtion
  5686. Return Value:
  5687. NULL - no seeding cxtion needed (or possible)
  5688. Otherwise, a seeding cxtion with a matching cxtion on
  5689. another computer (specified by the registry).
  5690. --*/
  5691. {
  5692. #undef DEBSUB
  5693. #define DEBSUB "RcsCreateSeedingCxtion:"
  5694. DWORD WStatus;
  5695. PVOID Key;
  5696. ULONG ParentAuthLevel;
  5697. PWCHAR KeyName = NULL;
  5698. PWCHAR ParentComputer = NULL;
  5699. PWCHAR ParentPrincName = NULL;
  5700. PWCHAR ParentNT4Name = NULL;
  5701. handle_t ParentHandle = NULL;
  5702. PWCHAR LocalServerName = NULL;
  5703. GUID SeedingGuid;
  5704. GUID ParentGuid;
  5705. extern ULONGLONG ActiveChange;
  5706. //
  5707. // This operation is non-critical. The sysvol will eventually seed
  5708. // after the FRS and KCC information converges on the appropriate
  5709. // DCs. Hence, trap exceptions and ignore them.
  5710. //
  5711. try {
  5712. //
  5713. // Already created. Seeding during dcpromo.
  5714. //
  5715. if (SeedingCxtion) {
  5716. goto CLEANUP_OK;
  5717. }
  5718. //
  5719. // No seeding cxtion is needed
  5720. //
  5721. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  5722. goto CLEANUP_OK;
  5723. }
  5724. //
  5725. // Do not create another seeding cxtion. The sysvol will eventually
  5726. // be seeded from a KCC generated cxtion (from the DS). But it may
  5727. // take awhile because both the FRS objects and the KCC must converge
  5728. // after the KCC has run. And then the FRS service has to notice the
  5729. // convergence.
  5730. //
  5731. Key = NULL;
  5732. while (SeedingCxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  5733. if (CxtionFlagIs(SeedingCxtion, CXTION_FLAGS_VOLATILE)) {
  5734. break;
  5735. }
  5736. }
  5737. if (SeedingCxtion) {
  5738. SeedingCxtion = NULL;
  5739. goto CLEANUP_OK;
  5740. }
  5741. //
  5742. // Retrieve the parent computer's name
  5743. //
  5744. WStatus = CfgRegReadString(FKC_SYSVOL_SEEDING_N_PARENT,
  5745. Replica->ReplicaName->Name,
  5746. 0,
  5747. &ParentComputer);
  5748. CLEANUP1_WS(0, ":X: ERROR - no parent computer for %ws :",
  5749. Replica->ReplicaName->Name, WStatus, CLEANUP_OK);
  5750. //
  5751. // Bind to the parent
  5752. //
  5753. WStatus = NtFrsApi_Rpc_BindEx(ParentComputer,
  5754. &ParentPrincName,
  5755. &ParentHandle,
  5756. &ParentAuthLevel);
  5757. CLEANUP_WS(0, "ERROR - binding", WStatus, CLEANUP);
  5758. DPRINT3(4, ":X: Seeding cxtion has bound to %ws (princ name is %ws) auth level %d\n",
  5759. ParentComputer, ParentPrincName, ParentAuthLevel);
  5760. //
  5761. // Placeholder guid for the cxtion
  5762. // Updated once the Ds objects are created
  5763. //
  5764. FrsUuidCreate(&SeedingGuid);
  5765. //
  5766. // Get local computer's NT4 style name. Send ServerPrincName if
  5767. // conversion fails.
  5768. //
  5769. LocalServerName = FrsDsConvertName(DsHandle, ServerPrincName, DS_USER_PRINCIPAL_NAME, NULL, DS_NT4_ACCOUNT_NAME);
  5770. if (LocalServerName == NULL) {
  5771. LocalServerName = FrsWcsDup(ServerPrincName);
  5772. }
  5773. //
  5774. // Create volatile cxtion on the parent
  5775. //
  5776. try {
  5777. WStatus = FrsRpcStartPromotionParent(ParentHandle,
  5778. NULL,
  5779. NULL,
  5780. Replica->SetName->Name,
  5781. NTFRSAPI_REPLICA_SET_TYPE_DOMAIN,
  5782. ParentComputer,
  5783. // Change the following to ComputerName for old DNS behavior
  5784. ComputerDnsName,
  5785. LocalServerName, // NT$ style name or user principal name.
  5786. ParentAuthLevel,
  5787. sizeof(GUID),
  5788. (PUCHAR)&SeedingGuid,
  5789. (PUCHAR)Replica->MemberName->Guid,
  5790. (PUCHAR)&ParentGuid);
  5791. } except (EXCEPTION_EXECUTE_HANDLER) {
  5792. GET_EXCEPTION_CODE(WStatus);
  5793. }
  5794. CLEANUP1_WS(0, ":X: ERROR - Can't create seeding cxtion on parent %ws;",
  5795. ParentComputer, WStatus, CLEANUP);
  5796. DPRINT3(4, ":X: Seeding cxtion has been created on %ws (princ name is %ws) auth level %d\n",
  5797. ParentComputer, ParentPrincName, ParentAuthLevel);
  5798. ParentNT4Name = FrsDsConvertName(DsHandle, ParentPrincName, DS_USER_PRINCIPAL_NAME, NULL, DS_NT4_ACCOUNT_NAME);
  5799. if (ParentNT4Name == NULL) {
  5800. ParentNT4Name = FrsWcsDup(ParentPrincName);
  5801. }
  5802. //
  5803. // Create local seeding cxtion
  5804. //
  5805. SeedingCxtion = FrsAllocType(CXTION_TYPE);
  5806. SeedingCxtion->Inbound = TRUE;
  5807. SetCxtionFlag(SeedingCxtion, CXTION_FLAGS_CONSISTENT |
  5808. CXTION_FLAGS_VOLATILE);
  5809. SeedingCxtion->Name = FrsBuildGName(FrsDupGuid(&SeedingGuid),
  5810. FrsWcsDup(ParentComputer));
  5811. SeedingCxtion->Partner = FrsBuildGName(FrsDupGuid(&ParentGuid),
  5812. FrsWcsDup(ParentComputer));
  5813. SeedingCxtion->PartnerDnsName = FrsWcsDup(ParentComputer);
  5814. SeedingCxtion->PartnerSid = FrsWcsDup(L"<unknown>");
  5815. SeedingCxtion->PartnerPrincName = FrsWcsDup(ParentNT4Name);
  5816. SeedingCxtion->PartSrvName = FrsWcsDup(ParentComputer);
  5817. SeedingCxtion->PartnerAuthLevel = ParentAuthLevel;
  5818. SetCxtionState(SeedingCxtion, CxtionStateUnjoined);
  5819. CLEANUP_OK:
  5820. WStatus = ERROR_SUCCESS;
  5821. CLEANUP:;
  5822. } except (EXCEPTION_EXECUTE_HANDLER) {
  5823. GET_EXCEPTION_CODE(WStatus);
  5824. DPRINT_WS(0, "ERROR - Exception", WStatus);
  5825. }
  5826. try {
  5827. if (ParentHandle) {
  5828. RpcBindingFree(&ParentHandle);
  5829. }
  5830. FrsFree(KeyName);
  5831. FrsFree(ParentComputer);
  5832. FrsFree(ParentPrincName);
  5833. FrsFree(ParentNT4Name);
  5834. FrsFree(LocalServerName);
  5835. } except (EXCEPTION_EXECUTE_HANDLER) {
  5836. GET_EXCEPTION_CODE(WStatus);
  5837. DPRINT_WS(0, "ERROR - Cleanup Exception", WStatus);
  5838. }
  5839. //
  5840. // Retry later. ERROR_SUCCESS means don't retry; there may have
  5841. // been errors that retrying is unlikely to fix.
  5842. //
  5843. if (!WIN_SUCCESS(WStatus)) {
  5844. //
  5845. // Ds poll thread will restart the replica during the next
  5846. // polling cycle if ActiveChange is set to 0.
  5847. //
  5848. ActiveChange = 0;
  5849. }
  5850. return SeedingCxtion;
  5851. }
  5852. VOID
  5853. RcsSetCxtionSchedule(
  5854. IN PREPLICA Replica,
  5855. IN PCXTION Cxtion,
  5856. IN DWORD ScheduleIndex,
  5857. IN DWORD ScheduleShift
  5858. )
  5859. /*++
  5860. Routine Description:
  5861. Set or clear the CXTION_FLAGS_SCHEDULE_OFF bit in the cxtion
  5862. depending on whether the 15min interval identified by
  5863. (ScheduleIndex, ScheduleShift) is set.
  5864. Trigger schedules use the bit differently. A triggered cxtion
  5865. may actually be joined and running even if the schedule is OFF
  5866. because the current set of cos haven't been received/sent, yet.
  5867. So, be careful. The interpretation of CXTION_FLAGS_SCHEDULE_OFF
  5868. varies with the type of schedule.
  5869. Arguments:
  5870. Replica
  5871. Return Value:
  5872. None.
  5873. --*/
  5874. {
  5875. #undef DEBSUB
  5876. #define DEBSUB "RcsSetCxtionSchedule:"
  5877. ULONG i;
  5878. BOOL On;
  5879. PSCHEDULE Schedule;
  5880. //
  5881. // Set or clear CXTION_FLAGS_SCHEDULE_OFF
  5882. //
  5883. //
  5884. // Inbound connection AND In seeding state AND option is set to
  5885. // ignore schedule.
  5886. //
  5887. if (Cxtion->Inbound &&
  5888. ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  5889. Replica->IsSeeding) &&
  5890. NTDSCONN_IGNORE_SCHEDULE(Cxtion->Options))
  5891. ) {
  5892. Schedule = NULL;
  5893. //
  5894. // Outbound connection AND (In vvjoin mode OR never joined) AND option is set to
  5895. // ignore schedule.
  5896. //
  5897. } else if (!Cxtion->Inbound &&
  5898. ((Cxtion->OLCtx == NULL) ||
  5899. WaitingToVVJoin(Cxtion->OLCtx) ||
  5900. InVVJoinMode(Cxtion->OLCtx)) &&
  5901. NTDSCONN_IGNORE_SCHEDULE(Cxtion->Options)
  5902. ) {
  5903. Schedule = NULL;
  5904. } else {
  5905. //
  5906. // No schedule == always on
  5907. //
  5908. Schedule = Cxtion->Schedule;
  5909. if (!Schedule) {
  5910. Schedule = Replica->Schedule;
  5911. }
  5912. }
  5913. //
  5914. // Is this 15minute interval ON or OFF?
  5915. //
  5916. On = TRUE;
  5917. if (Schedule) {
  5918. //
  5919. // Find the interval schedule
  5920. //
  5921. for (i = 0; i < Schedule->NumberOfSchedules; ++i) {
  5922. if (Schedule->Schedules[i].Type == SCHEDULE_INTERVAL) {
  5923. On = ((*(((PUCHAR)Schedule) +
  5924. Schedule->Schedules[i].Offset +
  5925. ScheduleIndex)) >> ScheduleShift) & 1;
  5926. break;
  5927. }
  5928. }
  5929. }
  5930. if (On) {
  5931. DPRINT1(0, ":X: %08x, schedule is on\n",
  5932. (Cxtion->Name && Cxtion->Name->Guid) ? Cxtion->Name->Guid->Data1 : 0);
  5933. ClearCxtionFlag(Cxtion, CXTION_FLAGS_SCHEDULE_OFF);
  5934. } else {
  5935. DPRINT1(0, ":X: %08x, schedule is off.\n",
  5936. (Cxtion->Name && Cxtion->Name->Guid) ? Cxtion->Name->Guid->Data1 : 0);
  5937. SetCxtionFlag(Cxtion, CXTION_FLAGS_SCHEDULE_OFF);
  5938. }
  5939. }
  5940. VOID
  5941. RcsCheckCxtionSchedule(
  5942. IN PREPLICA Replica,
  5943. IN PCXTION Cxtion
  5944. )
  5945. /*++
  5946. Routine Description:
  5947. Call the function to set or clear CXTION_FLAGS_SCHEDULE_OFF once
  5948. the current interval has been determined and the appropriate locks
  5949. acquired.
  5950. Called when a replica is "opened" (read from the DB) and when a
  5951. cxtion is created or its schedule altered in RcsMergeReplicaCxtions().
  5952. Arguments:
  5953. Cmd
  5954. Return Value:
  5955. None.
  5956. --*/
  5957. {
  5958. #undef DEBSUB
  5959. #define DEBSUB "RcsCheckCxtionSchedule:"
  5960. DWORD ScheduleIndex;
  5961. DWORD ScheduleShift;
  5962. SYSTEMTIME SystemTime;
  5963. DWORD ScheduleHour;
  5964. BOOL On;
  5965. //
  5966. // Find the current interval
  5967. //
  5968. GetSystemTime(&SystemTime);
  5969. ScheduleHour = (SystemTime.wDayOfWeek * 24) + SystemTime.wHour;
  5970. ScheduleShift = SystemTime.wMinute / MINUTES_IN_INTERVAL;
  5971. ScheduleIndex = ScheduleHour;
  5972. FRS_ASSERT(ScheduleIndex < SCHEDULE_DATA_BYTES);
  5973. //
  5974. // Set or clear CXTION_FLAGS_SCHEDULE_OFF
  5975. //
  5976. LOCK_CXTION_TABLE(Replica);
  5977. RcsSetCxtionSchedule(Replica, Cxtion, ScheduleIndex, ScheduleShift);
  5978. UNLOCK_CXTION_TABLE(Replica);
  5979. }
  5980. VOID
  5981. RcsCheckSchedules(
  5982. IN PCOMMAND_PACKET Cmd
  5983. )
  5984. /*++
  5985. Routine Description:
  5986. Check all schedules every so often.
  5987. There are three schedule protocols:
  5988. Sysvol cxtion within a site
  5989. ---------------------------
  5990. The cxtion is always on; any schedule is ignored. Normal join
  5991. retries apply. The normal join retry is to increase the timeout
  5992. by MinJoinTimeout every retry until the join succeeds. A
  5993. successful unjoin is followed by an immediate join.
  5994. Normal cxtion
  5995. -------------
  5996. The schedule is treated as a 15 minute interval stop/start
  5997. schedule. Normal join retries apply.
  5998. Sysvol cxtion between sites
  5999. ---------------------------
  6000. The cxtion is treated as a 15-minute interval trigger schedule.
  6001. The downstream partner initiates the join. The upstream partner
  6002. ignores its schedule and responds to any request by the downstream
  6003. partner. The upstream partner unjoins the cxtion when the current
  6004. contents of the outlog at the time of join have been sent and
  6005. acked.
  6006. For interoperability, the minor comm version was bumped and the
  6007. outbound trigger cxtion is not unjoined when the end-of-join
  6008. control co is encountered if the partner is downrev.
  6009. I.e., B2 <-> B3 systems behave like B2 systems wrt trigger
  6010. scheduled cxtions.
  6011. Arguments:
  6012. Cmd
  6013. Return Value:
  6014. None.
  6015. --*/
  6016. {
  6017. #undef DEBSUB
  6018. #define DEBSUB "RcsCheckSchedules:"
  6019. PVOID ReplicaKey;
  6020. PVOID CxtionKey;
  6021. PREPLICA Replica;
  6022. PCXTION Cxtion;
  6023. DWORD ScheduleIndex;
  6024. DWORD ScheduleShift;
  6025. SYSTEMTIME BeginSystemTime;
  6026. SYSTEMTIME EndSystemTime;
  6027. DWORD ScheduleHour;
  6028. DWORD MilliSeconds;
  6029. BOOL On;
  6030. DPRINT1(5, ":X: Command check schedules %08x\n", Cmd);
  6031. //
  6032. // Loop if the interval changes during processing
  6033. //
  6034. AGAIN:
  6035. //
  6036. // Current 15min interval
  6037. //
  6038. GetSystemTime(&BeginSystemTime);
  6039. ScheduleHour = (BeginSystemTime.wDayOfWeek * 24) + BeginSystemTime.wHour;
  6040. ScheduleShift = BeginSystemTime.wMinute / MINUTES_IN_INTERVAL;
  6041. ScheduleIndex = ScheduleHour;
  6042. FRS_ASSERT(ScheduleIndex < SCHEDULE_DATA_BYTES);
  6043. //
  6044. // For each replica (while not shutting down)
  6045. //
  6046. LOCK_REPLICA_TABLE(ReplicasByGuid);
  6047. ReplicaKey = NULL;
  6048. while ((!FrsIsShuttingDown) &&
  6049. (Replica = GTabNextDatumNoLock(ReplicasByGuid, &ReplicaKey))) {
  6050. //
  6051. // Replica hasn't been started or is deleted; ignore for now
  6052. //
  6053. if (!Replica->IsAccepting) {
  6054. continue;
  6055. }
  6056. //
  6057. // Don't bother; replica has been deleted
  6058. //
  6059. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  6060. continue;
  6061. }
  6062. //
  6063. // For each cxtion (while not shutting down)
  6064. //
  6065. LOCK_CXTION_TABLE(Replica);
  6066. CxtionKey = NULL;
  6067. while ((!FrsIsShuttingDown) &&
  6068. (Cxtion = GTabNextDatumNoLock(Replica->Cxtions, &CxtionKey))) {
  6069. //
  6070. // Ignore the (local) journal connection.
  6071. //
  6072. if (Cxtion->JrnlCxtion) {
  6073. continue;
  6074. }
  6075. //
  6076. // Set the cxtion flags related to schedules
  6077. //
  6078. RcsSetCxtionSchedule(Replica, Cxtion, ScheduleIndex, ScheduleShift);
  6079. //
  6080. // Schedule is off. Unjoin the cxtion UNLESS this is
  6081. // a trigger schedule, in which case the cxtion will
  6082. // turn itself off once the current set of changes
  6083. // have been sent.
  6084. //
  6085. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  6086. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  6087. !CxtionStateIs(Cxtion, CxtionStateDeleted) &&
  6088. !CxtionStateIs(Cxtion, CxtionStateStart) &&
  6089. !CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  6090. RcsSubmitReplicaCxtion(Replica, Cxtion, CMD_UNJOIN);
  6091. }
  6092. //
  6093. // Schedule is on. Join the cxtion unless it is already
  6094. // joined or is controlled by a trigger schedule. The
  6095. // join is needed for a trigger scheduled cxtion in case
  6096. // the upstream partner has sent its cos and is now
  6097. // unjoined.
  6098. //
  6099. // Do not send a CMD_JOIN if this replica set is still seeding and
  6100. // connection is in INIT_SYNC state and marked paused.
  6101. // Initial sync command server will unpause it when it is ready to join.
  6102. //
  6103. } else {
  6104. if ((!CxtionStateIs(Cxtion, CxtionStateJoined) ||
  6105. CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) &&
  6106. (!CxtionFlagIs(Cxtion, CXTION_FLAGS_PAUSED) ||
  6107. (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  6108. !CxtionFlagIs(Cxtion, CXTION_FLAGS_INIT_SYNC)))
  6109. ) {
  6110. RcsSubmitReplicaCxtion(Replica, Cxtion, CMD_JOIN_CXTION);
  6111. }
  6112. }
  6113. }
  6114. UNLOCK_CXTION_TABLE(Replica);
  6115. }
  6116. UNLOCK_REPLICA_TABLE(ReplicasByGuid);
  6117. //
  6118. // Has the clock ticked into the next interval? If so, check again
  6119. //
  6120. GetSystemTime(&EndSystemTime);
  6121. if (EndSystemTime.wDayOfWeek != BeginSystemTime.wDayOfWeek ||
  6122. EndSystemTime.wHour != BeginSystemTime.wHour ||
  6123. (EndSystemTime.wMinute / MINUTES_IN_INTERVAL) != (BeginSystemTime.wMinute / MINUTES_IN_INTERVAL)) {
  6124. goto AGAIN;
  6125. }
  6126. //
  6127. // Time until the beginning of the next 15 minute interval
  6128. //
  6129. MilliSeconds = ((((EndSystemTime.wMinute + MINUTES_IN_INTERVAL)
  6130. / MINUTES_IN_INTERVAL)
  6131. * MINUTES_IN_INTERVAL)
  6132. - EndSystemTime.wMinute);
  6133. DPRINT1(5, ":X: Check schedules in %d minutes\n", MilliSeconds);
  6134. MilliSeconds *= (60 * 1000);
  6135. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, MilliSeconds);
  6136. }
  6137. VOID
  6138. RcsMergeReplicaCxtions(
  6139. IN PREPLICA Replica,
  6140. IN PREPLICA NewReplica,
  6141. IN PCXTION VolatileCxtion
  6142. )
  6143. /*++
  6144. Routine Description:
  6145. Update the Replica's cxtions with information from NewReplica.
  6146. Arguments:
  6147. Replica - active replica
  6148. NewReplica
  6149. VolatileCxtion -- Ptr to a cxtion struct created for temporary connections.
  6150. Hence the name Volatile. Currently used for Sysvol Seeding.
  6151. Return Value:
  6152. TRUE - replica set was altered
  6153. FALSE - replica is unaltered
  6154. --*/
  6155. {
  6156. #undef DEBSUB
  6157. #define DEBSUB "RcsMergeReplicaCxtions:"
  6158. ULONG FStatus;
  6159. PVOID Key;
  6160. PCXTION Cxtion;
  6161. PCXTION NextCxtion;
  6162. BOOL UpdateNeeded;
  6163. PCXTION NewCxtion;
  6164. //
  6165. // Note: Review - There needs to be a lock on the table or the cxtion
  6166. // since the outlog, chgorder, and replica code may
  6167. // reference the cxtion struct in parallel.
  6168. //
  6169. //
  6170. // The cxtions are enumerated when the replica is opened. If the
  6171. // replica isn't opened then we don't know the state of the existing
  6172. // cxtions.
  6173. //
  6174. if (!Replica->IsOpen) {
  6175. return;
  6176. }
  6177. //
  6178. // The replica's config record can't be updated; ignore cxtion changes
  6179. //
  6180. if (Replica->NeedsUpdate) {
  6181. return;
  6182. }
  6183. //
  6184. // Add the seeding cxtion
  6185. // The seeding cxtion is created by the caller when the
  6186. // sysvol is seeded after dcpromo. Otherwise, it is created
  6187. // at this time.
  6188. //
  6189. // WARN - The function may open and read the registry and may
  6190. // RPC to another computer.
  6191. //
  6192. VolatileCxtion = RcsCreateSeedingCxtion(Replica, VolatileCxtion);
  6193. if (VolatileCxtion) {
  6194. //
  6195. // Update the cxtion table
  6196. //
  6197. // *NOTE* The following call is synchronous. If we have the Cxtion
  6198. // table lock then a hang is possible.
  6199. //
  6200. FStatus = OutLogSubmit(Replica, VolatileCxtion, CMD_OUTLOG_ADD_NEW_PARTNER);
  6201. if (FRS_SUCCESS(FStatus)) {
  6202. //
  6203. // Update the incore cxtion table
  6204. //
  6205. GTabInsertEntry(Replica->Cxtions, VolatileCxtion, VolatileCxtion->Name->Guid, NULL);
  6206. OutLogInitPartner(Replica, VolatileCxtion);
  6207. } else {
  6208. //
  6209. // Chuck the cxtion. We will retry the create during the
  6210. // next ds polling cycle.
  6211. //
  6212. FrsFreeType(VolatileCxtion);
  6213. }
  6214. }
  6215. //
  6216. // Done
  6217. //
  6218. if (!NewReplica) {
  6219. return;
  6220. }
  6221. //
  6222. // Check for altered or deleted cxtions
  6223. //
  6224. Key = NULL;
  6225. for (Cxtion = GTabNextDatum(Replica->Cxtions, &Key); Cxtion; Cxtion = NextCxtion) {
  6226. NextCxtion = GTabNextDatum(Replica->Cxtions, &Key);
  6227. //
  6228. // Ignore the (local) journal connection.
  6229. //
  6230. if (Cxtion->JrnlCxtion) {
  6231. continue;
  6232. }
  6233. //
  6234. // This cxtion is volatile, it will disappear after the sysvol is seeded.
  6235. // NOTE: the cxtion flags are not stored in the database so, at
  6236. // restart, this cxtion will not have the flag, CXTION_FLAGS_VOLATILE,
  6237. // set. The cxtion is deleted at restart because there isn't a
  6238. // corresponding DS entry.
  6239. //
  6240. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_VOLATILE)) {
  6241. continue;
  6242. }
  6243. NewCxtion = GTabLookup(NewReplica->Cxtions, Cxtion->Name->Guid, NULL);
  6244. //
  6245. // Delete the cxtion after unjoining
  6246. //
  6247. if (NewCxtion == NULL) {
  6248. //
  6249. // Unjoin the cxtion after setting the deferred delete bit.
  6250. // The deferred delete bit will keep the cxtion from re-joining
  6251. // before it can be deleted during the next pass of the ds
  6252. // polling thread. Warning - cxtion may reappear at any time!
  6253. //
  6254. if (!CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6255. LOCK_CXTION_TABLE(Replica);
  6256. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  6257. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  6258. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_DELETE);
  6259. UNLOCK_CXTION_TABLE(Replica);
  6260. RcsForceUnjoin(Replica, Cxtion);
  6261. }
  6262. //
  6263. // If successfully unjoined; move to the deleted-cxtion table
  6264. //
  6265. if (CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6266. RcsDeleteCxtionFromReplica(Replica, Cxtion);
  6267. }
  6268. continue;
  6269. //
  6270. // Deleted cxtion reappeared; reanimate it
  6271. //
  6272. // if the cxtion is deleted or marked for delete
  6273. // and new cxtion is consistent
  6274. // and partner's guid's match
  6275. // then reanimate
  6276. //
  6277. // Don't attempt to reanimate a cxtion if the info in the DS
  6278. // is inconsistent or the cxtion's partner has changed. The
  6279. // cxtion is deleted when its partner changes because the
  6280. // state kept per cxtion is partner specific.
  6281. //
  6282. } else if ((CxtionStateIs(Cxtion, CxtionStateDeleted) ||
  6283. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) &&
  6284. CxtionFlagIs(NewCxtion, CXTION_FLAGS_CONSISTENT) &&
  6285. GUIDS_EQUAL(Cxtion->Partner->Guid, NewCxtion->Partner->Guid)) {
  6286. LOCK_CXTION_TABLE(Replica);
  6287. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_DELETE);
  6288. if (CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6289. SetCxtionState(Cxtion, CxtionStateUnjoined);
  6290. }
  6291. UNLOCK_CXTION_TABLE(Replica);
  6292. }
  6293. //
  6294. // Check for altered fields; Ignore if not consistent
  6295. //
  6296. if (CxtionFlagIs(NewCxtion, CXTION_FLAGS_CONSISTENT)) {
  6297. //
  6298. // No changes, yet
  6299. //
  6300. UpdateNeeded = FALSE;
  6301. //
  6302. // Ignore all change is a field changed that isn't allowed
  6303. // to change.
  6304. //
  6305. //
  6306. // Cxtion Guid
  6307. //
  6308. if (!GUIDS_EQUAL(Cxtion->Name->Guid, NewCxtion->Name->Guid)) {
  6309. DPRINT2(0, ":X: ERROR - %ws\\%ws - Changing cxtion guid is not allowed.\n",
  6310. Replica->MemberName->Name, Cxtion->Name->Name);
  6311. goto DELETE_AND_CONTINUE;
  6312. }
  6313. //
  6314. // Partner Guid
  6315. //
  6316. // The cxtion is deleted when its partner changes because the
  6317. // state kept per cxtion is partner specific. If the cxtion
  6318. // has been newly altered so that its previous mismatched
  6319. // partner guid now matches then the check in the previous
  6320. // basic block would have reanimated the cxtion before getting
  6321. // to this code. Hence, the lack of an "else" clause.
  6322. //
  6323. if (!GUIDS_EQUAL(Cxtion->Partner->Guid, NewCxtion->Partner->Guid)) {
  6324. DPRINT2(0, ":X: ERROR - %ws\\%ws - Changing cxtion's partner guid "
  6325. "is not allowed. DELETING CURRENT CXTION!\n",
  6326. Replica->MemberName->Name, Cxtion->Name->Name);
  6327. //
  6328. // Unjoin the cxtion after setting the deferred delete bit.
  6329. // The deferred delete bit will keep the cxtion from re-joining
  6330. // before it can be deleted during the next pass of the ds
  6331. // polling thread. Warning - cxtion may reappear at any time!
  6332. //
  6333. if (!CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6334. LOCK_CXTION_TABLE(Replica);
  6335. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  6336. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  6337. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_DELETE);
  6338. UNLOCK_CXTION_TABLE(Replica);
  6339. RcsForceUnjoin(Replica, Cxtion);
  6340. }
  6341. //
  6342. // If successfully unjoined; move to the deleted-cxtion table
  6343. //
  6344. if (CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6345. RcsDeleteCxtionFromReplica(Replica, Cxtion);
  6346. }
  6347. goto DELETE_AND_CONTINUE;
  6348. }
  6349. //
  6350. // Partner Name
  6351. //
  6352. if (WSTR_NE(Cxtion->Partner->Name, NewCxtion->Partner->Name)) {
  6353. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner name from %ws to %ws.\n",
  6354. Replica->MemberName->Name, Cxtion->Name->Name,
  6355. Cxtion->Partner->Name, NewCxtion->Partner->Name);
  6356. FrsDsSwapPtrs(&Cxtion->Partner->Name, &NewCxtion->Partner->Name);
  6357. UpdateNeeded = TRUE;
  6358. }
  6359. //
  6360. // Partner PrincName
  6361. //
  6362. if (WSTR_NE(Cxtion->PartnerPrincName, NewCxtion->PartnerPrincName)) {
  6363. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner princname from %ws to %ws.\n",
  6364. Replica->MemberName->Name, Cxtion->Name->Name,
  6365. Cxtion->PartnerPrincName, NewCxtion->PartnerPrincName);
  6366. FrsDsSwapPtrs(&Cxtion->PartnerPrincName, &NewCxtion->PartnerPrincName);
  6367. UpdateNeeded = TRUE;
  6368. }
  6369. //
  6370. // Partner Dns Name
  6371. //
  6372. if (WSTR_NE(Cxtion->PartnerDnsName, NewCxtion->PartnerDnsName)) {
  6373. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner DNS name from %ws to %ws.\n",
  6374. Replica->MemberName->Name, Cxtion->Name->Name,
  6375. Cxtion->PartnerDnsName, NewCxtion->PartnerDnsName);
  6376. FrsDsSwapPtrs(&Cxtion->PartnerDnsName, &NewCxtion->PartnerDnsName);
  6377. UpdateNeeded = TRUE;
  6378. }
  6379. //
  6380. // Partner SID
  6381. //
  6382. if (WSTR_NE(Cxtion->PartnerSid, NewCxtion->PartnerSid)) {
  6383. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner SID from %ws to %ws.\n",
  6384. Replica->MemberName->Name, Cxtion->Name->Name,
  6385. Cxtion->PartnerSid, NewCxtion->PartnerSid);
  6386. FrsDsSwapPtrs(&Cxtion->PartnerSid, &NewCxtion->PartnerSid);
  6387. UpdateNeeded = TRUE;
  6388. }
  6389. //
  6390. // Cxtion Schedule
  6391. //
  6392. if (Cxtion->Schedule || NewCxtion->Schedule) {
  6393. if ((Cxtion->Schedule && !NewCxtion->Schedule) ||
  6394. (!Cxtion->Schedule && NewCxtion->Schedule) ||
  6395. (Cxtion->Schedule->Size != NewCxtion->Schedule->Size) ||
  6396. (memcmp(Cxtion->Schedule,
  6397. NewCxtion->Schedule,
  6398. Cxtion->Schedule->Size))) {
  6399. DPRINT2(4, ":X: %ws\\%ws - Changing cxtion schedule.\n",
  6400. Replica->MemberName->Name, Cxtion->Name->Name);
  6401. FrsDsSwapPtrs(&Cxtion->Schedule, &NewCxtion->Schedule);
  6402. RcsCheckCxtionSchedule(Replica, Cxtion);
  6403. UpdateNeeded = TRUE;
  6404. }
  6405. }
  6406. //
  6407. // Partner Server Name
  6408. //
  6409. if (WSTR_NE(Cxtion->PartSrvName, NewCxtion->PartSrvName)) {
  6410. DPRINT4(4, ":X: %ws\\%ws - Changing partner's server name from %ws to %ws.\n",
  6411. Replica->MemberName->Name, Cxtion->Name->Name,
  6412. Cxtion->PartSrvName, NewCxtion->PartSrvName);
  6413. FrsDsSwapPtrs(&Cxtion->PartSrvName, &NewCxtion->PartSrvName);
  6414. UpdateNeeded = TRUE;
  6415. }
  6416. //
  6417. // Cxtion options.
  6418. //
  6419. if (Cxtion->Options != NewCxtion->Options) {
  6420. DPRINT4(4, ":X: %ws\\%ws - Changing Cxtion's options from 0x%08x to 0x%08x.\n",
  6421. Replica->MemberName->Name, Cxtion->Name->Name,
  6422. Cxtion->Options, NewCxtion->Options);
  6423. Cxtion->Options = NewCxtion->Options;
  6424. Cxtion->Priority = FRSCONN_GET_PRIORITY(Cxtion->Options);
  6425. UpdateNeeded = TRUE;
  6426. }
  6427. //
  6428. // Schedule type
  6429. //
  6430. if (CxtionFlagIs(NewCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) !=
  6431. CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  6432. DPRINT4(4, ":X: %ws\\%ws - Changing schedule type from %s to %s.\n",
  6433. Replica->MemberName->Name, Cxtion->Name->Name,
  6434. CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) ?
  6435. "Trigger" : "Stop/Start",
  6436. CxtionFlagIs(NewCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) ?
  6437. "Trigger" : "Stop/Start");
  6438. if (CxtionFlagIs(NewCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  6439. SetCxtionFlag(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE);
  6440. } else {
  6441. ClearCxtionFlag(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE);
  6442. }
  6443. UpdateNeeded = TRUE;
  6444. }
  6445. //
  6446. // No changes, done
  6447. //
  6448. if (!UpdateNeeded) {
  6449. goto DELETE_AND_CONTINUE;
  6450. }
  6451. //
  6452. // Update the cxtion table in the DB
  6453. //
  6454. // *NOTE* The following call is synchronous. If we have the Cxtion
  6455. // table lock then a hang is possible.
  6456. //
  6457. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_UPDATE_PARTNER);
  6458. if (!FRS_SUCCESS(FStatus)) {
  6459. DPRINT3(0, ":X: WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  6460. Cxtion->Name->Name, Cxtion->Partner->Name,
  6461. Replica->ReplicaName->Name);
  6462. //
  6463. // Ds poll thread will restart the replica during the next
  6464. // polling cycle if ActiveChange is set to 0.
  6465. //
  6466. ActiveChange = 0;
  6467. }
  6468. }
  6469. DELETE_AND_CONTINUE:
  6470. //
  6471. // Remove the cxtion from the new replica set. Anything left
  6472. // after this loop must be a new cxtion. Free the partner
  6473. // so that FrsFreeType() will not attempt to unbind our
  6474. // partner's handles.
  6475. //
  6476. NewCxtion->Partner = FrsFreeGName(NewCxtion->Partner);
  6477. GTabDelete(NewReplica->Cxtions, Cxtion->Name->Guid, NULL, FrsFreeType);
  6478. }
  6479. //
  6480. // New cxtions
  6481. //
  6482. for (Key = NULL;
  6483. NewCxtion = GTabNextDatum(NewReplica->Cxtions, &Key);
  6484. Key = NULL) {
  6485. //
  6486. // Remove the cxtion from the new replica
  6487. //
  6488. GTabDelete(NewReplica->Cxtions, NewCxtion->Name->Guid, NULL, NULL);
  6489. //
  6490. // Inconsistent cxtion; ignore
  6491. //
  6492. if (NewCxtion->JrnlCxtion ||
  6493. !CxtionFlagIs(NewCxtion, CXTION_FLAGS_CONSISTENT)) {
  6494. FrsFreeType(NewCxtion);
  6495. continue;
  6496. }
  6497. RcsCheckCxtionSchedule(Replica, NewCxtion);
  6498. //
  6499. // Update the cxtion table
  6500. //
  6501. // *NOTE* The following call is synchronous. If we have the Cxtion
  6502. // table lock then a hang is possible.
  6503. //
  6504. FStatus = OutLogSubmit(Replica, NewCxtion, CMD_OUTLOG_ADD_NEW_PARTNER);
  6505. if (FRS_SUCCESS(FStatus)) {
  6506. DPRINT2(4, ":X: %ws\\%ws - Created cxtion.\n",
  6507. Replica->MemberName->Name, NewCxtion->Name->Name);
  6508. //
  6509. // Update the incore cxtion table
  6510. //
  6511. GTabInsertEntry(Replica->Cxtions, NewCxtion, NewCxtion->Name->Guid, NULL);
  6512. DPRINT(5, ":X: PERFMON:Adding Connection:REPLICA.C:2\n");
  6513. RcsCreatePerfmonCxtionName(Replica, NewCxtion);
  6514. OutLogInitPartner(Replica, NewCxtion);
  6515. } else {
  6516. DPRINT2_FS(0, ":X: %ws\\%ws - ERROR creating cxtion;",
  6517. Replica->MemberName->Name, NewCxtion->Name->Name, FStatus);
  6518. //
  6519. // Chuck the cxtion. We will retry the create during the
  6520. // next ds polling cycle.
  6521. //
  6522. FrsFreeType(NewCxtion);
  6523. //
  6524. // Ds poll thread will restart the replica during the next
  6525. // polling cycle if ActiveChange is set to 0.
  6526. //
  6527. ActiveChange = 0;
  6528. }
  6529. }
  6530. }
  6531. VOID
  6532. RcsCreatePerfmonCxtionName(
  6533. PREPLICA Replica,
  6534. PCXTION Cxtion
  6535. )
  6536. /*++
  6537. Routine Description:
  6538. Set the OID data structure which is a part of the counter data structure
  6539. stored in the hash table.
  6540. Add ReplicaConn Instance to the registry
  6541. Arguments:
  6542. Replica - active replica
  6543. Cxtion - Connection being added.
  6544. Return Value:
  6545. None.
  6546. --*/
  6547. {
  6548. #undef DEBSUB
  6549. #define DEBSUB "RcsCreatePerfmonCxtionName:"
  6550. PWCHAR ToFrom;
  6551. ULONG NameLen;
  6552. PWCHAR CxNamePtr;
  6553. if ((Cxtion->PartSrvName != NULL) && (Replica->Root != NULL)) {
  6554. //
  6555. // The oid name used in the HT_REPLICA_CONN_DATA is of the form
  6556. // Replica->Root::FROM:Cxtion->PartSrvName or
  6557. // Replica->Root::TO:Cxtion->PartSrvName
  6558. //
  6559. WCHAR Tstr[256];
  6560. _snwprintf(Tstr, ARRAY_SZ(Tstr), L"%ws%ws%ws",
  6561. Replica->Root,
  6562. (Cxtion->Inbound) ? (L"::FROM:") : (L"::TO:"),
  6563. Cxtion->PartSrvName);
  6564. //
  6565. // Finally, add the REPLICACONN instance to the Registry
  6566. //
  6567. AddPerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData, Tstr);
  6568. }
  6569. }
  6570. VOID
  6571. RcsSubmitStopReplicaToDb(
  6572. IN PREPLICA Replica
  6573. )
  6574. /*++
  6575. Routine Description:
  6576. Release the replica's journal state and outbound log state.
  6577. This will also close the replica set if it was open. The close happens
  6578. after the Journaling on the replica has stopped so we save the correct
  6579. Journal restart USN.
  6580. Arguments:
  6581. None.
  6582. Return Value:
  6583. None.
  6584. --*/
  6585. {
  6586. #undef DEBSUB
  6587. #define DEBSUB "RcsSubmitStopReplicaToDb:"
  6588. PCOMMAND_PACKET Cmd = NULL;
  6589. ULONG WStatus;
  6590. Replica->FStatus = FrsErrorSuccess;
  6591. //
  6592. // Abort promotion; if any
  6593. //
  6594. if (Replica->NtFrsApi_ServiceState == NTFRSAPI_SERVICE_PROMOTING) {
  6595. DPRINT1(4, ":S: Promotion aborted: stop for %ws.\n", Replica->SetName->Name);
  6596. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE;
  6597. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  6598. }
  6599. //
  6600. // Attempt to stop journaling even if "IsJournaling" is false because
  6601. // may have journal state even if it isn't journaling. The journal
  6602. // is kept in pVme.
  6603. //
  6604. if (Replica->pVme == NULL) {
  6605. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica->pVme == NULL");
  6606. //
  6607. // Close replica is OK here as long as the Journal has not
  6608. // been started on this replica set.
  6609. //
  6610. RcsCloseReplicaSetmember(Replica);
  6611. RcsCloseReplicaCxtions(Replica);
  6612. return;
  6613. }
  6614. //
  6615. // Submitted to the db command server
  6616. //
  6617. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6618. Replica, // Replica,
  6619. CMD_STOP_REPLICATION_SINGLE_REPLICA, // CmdRequest,
  6620. NULL, // TableCtx,
  6621. NULL, // CallContext,
  6622. 0, // TableType,
  6623. 0, // AccessRequest,
  6624. 0, // IndexType,
  6625. NULL, // KeyValue,
  6626. 0, // KeyValueLength,
  6627. FALSE); // Submit
  6628. //
  6629. // Don't free the packet when the command completes.
  6630. //
  6631. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6632. //
  6633. // SUBMIT DB Cmd and wait for completion.
  6634. //
  6635. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_STOP_REPLICATION_SINGLE_REPLICA");
  6636. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  6637. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  6638. //
  6639. // If wait or database op failed
  6640. //
  6641. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  6642. //
  6643. // If wait / submit failed then let caller know cmd srv submit failed.
  6644. //
  6645. if (FRS_SUCCESS(Replica->FStatus)) {
  6646. Replica->FStatus = FrsErrorCmdSrvFailed;
  6647. }
  6648. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Stop Replica failed;",
  6649. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  6650. DPRINT_WS(0, "ERROR: Stop Replica DB Command failed", WStatus);
  6651. goto out;
  6652. }
  6653. Replica->IsOpen = FALSE;
  6654. out:
  6655. if (Cmd) {
  6656. FrsFreeCommand(Cmd, NULL);
  6657. }
  6658. }
  6659. VOID
  6660. RcsCloseReplicaCxtions(
  6661. IN PREPLICA Replica
  6662. )
  6663. /*++
  6664. Routine Description:
  6665. "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  6666. generate new cxtion structs before active processing (aka joining)
  6667. occurs. The cxtions remain in the DeletedCxtions table so that
  6668. other threads that may have been time sliced just after acquiring
  6669. the cxtion pointer but before making use of it will not AV. We
  6670. could have put in locks but then there would be deadlock and
  6671. perf considerations; all for the sake of this seldom occuring
  6672. operation.
  6673. Arguments:
  6674. Replica
  6675. Return Value:
  6676. None.
  6677. --*/
  6678. {
  6679. #undef DEBSUB
  6680. #define DEBSUB "RcsCloseReplicaCxtions:"
  6681. PVOID Key;
  6682. PCXTION Cxtion;
  6683. //
  6684. // Open; ignore request
  6685. //
  6686. if (Replica->IsOpen) {
  6687. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Replica open at close cxtions");
  6688. return;
  6689. }
  6690. //
  6691. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  6692. // generate new cxtion structs before active processing (aka joining)
  6693. // occurs. The cxtions remain in the DeletedCxtions table so that
  6694. // other threads that may have been time sliced just after acquiring
  6695. // the cxtion pointer but before making use of it will not AV. We
  6696. // could have put in locks but then there would be deadlock and
  6697. // perf considerations; all for the sake of this seldom occuring
  6698. // operation.
  6699. //
  6700. if (Replica->Cxtions) {
  6701. Key = NULL;
  6702. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  6703. Key = NULL;
  6704. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, GenTable Cxtion deleted");
  6705. GTabDelete(Replica->Cxtions, Cxtion->Name->Guid, NULL, NULL);
  6706. //
  6707. // Remove the connection from the perfmon tables so we stop returning
  6708. // data and allow a new connection with the same name to be established.
  6709. //
  6710. // Journal cxtion does not have a perfmon entry
  6711. //
  6712. if (!Cxtion->JrnlCxtion) {
  6713. DeletePerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData);
  6714. }
  6715. GTabInsertEntry(DeletedCxtions, Cxtion, Cxtion->Name->Guid, NULL);
  6716. }
  6717. }
  6718. }
  6719. VOID
  6720. RcsCloseReplicaSetmember(
  6721. IN PREPLICA Replica
  6722. )
  6723. /*++
  6724. Routine Description:
  6725. Close an open replica
  6726. Arguments:
  6727. Replica
  6728. Return Value:
  6729. None.
  6730. --*/
  6731. {
  6732. #undef DEBSUB
  6733. #define DEBSUB "RcsCloseReplicaSetmember:"
  6734. PCOMMAND_PACKET Cmd = NULL;
  6735. ULONG WStatus;
  6736. PVOID Key;
  6737. PCXTION Cxtion;
  6738. Replica->FStatus = FrsErrorSuccess;
  6739. //
  6740. // Not open or still journaling; ignore request
  6741. //
  6742. if (!Replica->IsOpen) {
  6743. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not open");
  6744. return;
  6745. }
  6746. //
  6747. // Submitted to the db command server
  6748. //
  6749. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6750. Replica, // Replica,
  6751. CMD_CLOSE_REPLICA_SET_MEMBER, // CmdRequest,
  6752. NULL, // TableCtx,
  6753. NULL, // CallContext,
  6754. 0, // TableType,
  6755. 0, // AccessRequest,
  6756. 0, // IndexType,
  6757. NULL, // KeyValue,
  6758. 0, // KeyValueLength,
  6759. FALSE); // Submit
  6760. //
  6761. // Don't free the packet when the command completes.
  6762. //
  6763. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6764. //
  6765. // SUBMIT DB Cmd and wait for completion.
  6766. //
  6767. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_CLOSE_REPLICA_SET_MEMBER");
  6768. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  6769. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  6770. //
  6771. // If wait or database op failed
  6772. //
  6773. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  6774. //
  6775. // If wait / submit failed then let caller know cmd srv submit failed.
  6776. //
  6777. if (FRS_SUCCESS(Replica->FStatus)) {
  6778. Replica->FStatus = FrsErrorCmdSrvFailed;
  6779. }
  6780. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Close Replica failed;",
  6781. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  6782. DPRINT_WS(0, "ERROR: Close Replica DB Command failed", WStatus);
  6783. goto out;
  6784. }
  6785. Replica->IsOpen = FALSE;
  6786. out:
  6787. if (Cmd) {
  6788. FrsFreeCommand(Cmd, NULL);
  6789. }
  6790. }
  6791. VOID
  6792. RcsDeleteReplicaFromDb(
  6793. IN PREPLICA Replica
  6794. )
  6795. /*++
  6796. Routine Description:
  6797. Delete the replica from the database
  6798. Arguments:
  6799. Replica
  6800. Return Value:
  6801. winerror
  6802. --*/
  6803. {
  6804. #undef DEBSUB
  6805. #define DEBSUB "RcsDeleteReplicaFromDb:"
  6806. PCOMMAND_PACKET Cmd = NULL;
  6807. ULONG WStatus;
  6808. Replica->FStatus = FrsErrorSuccess;
  6809. //
  6810. // Replica must be opened to delete
  6811. //
  6812. if (Replica->IsOpen) {
  6813. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not open");
  6814. return;
  6815. }
  6816. //
  6817. // Submitted to the db command server
  6818. //
  6819. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6820. Replica, // Replica,
  6821. CMD_DELETE_REPLICA_SET_MEMBER, // CmdRequest,
  6822. NULL, // TableCtx,
  6823. NULL, // CallContext,
  6824. 0, // TableType,
  6825. 0, // AccessRequest,
  6826. 0, // IndexType,
  6827. NULL, // KeyValue,
  6828. 0, // KeyValueLength,
  6829. FALSE); // Submit
  6830. //
  6831. // Don't free the packet when the command completes.
  6832. //
  6833. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6834. //
  6835. // SUBMIT DB Cmd and wait for completion.
  6836. //
  6837. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Submit DB CMD_DELETE_REPLICA_SET_MEMBER");
  6838. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  6839. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  6840. //
  6841. // If wait or database op failed
  6842. //
  6843. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  6844. //
  6845. // If wait / submit failed then let caller know cmd srv submit failed.
  6846. //
  6847. if (FRS_SUCCESS(Replica->FStatus)) {
  6848. Replica->FStatus = FrsErrorCmdSrvFailed;
  6849. }
  6850. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Delete Replica failed;",
  6851. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  6852. DPRINT_WS(0, "ERROR: Delete Replica DB Command failed", WStatus);
  6853. goto out;
  6854. }
  6855. out:
  6856. if (Cmd) {
  6857. FrsFreeCommand(Cmd, NULL);
  6858. }
  6859. }
  6860. VOID
  6861. RcsUpdateReplicaSetMember(
  6862. IN PREPLICA Replica
  6863. )
  6864. /*++
  6865. Routine Description:
  6866. Update the database record for Replica.
  6867. *Note*
  6868. Perf: RcsUpdateReplicaSetMember() should return status as part
  6869. of the function call not use some side-effect flag(NeedsUpdate)
  6870. in the Replica struct.
  6871. Arguments:
  6872. Replica
  6873. Return Value:
  6874. winerror
  6875. --*/
  6876. {
  6877. #undef DEBSUB
  6878. #define DEBSUB "RcsUpdateReplicaSetMember:"
  6879. PCOMMAND_PACKET Cmd = NULL;
  6880. ULONG WStatus;
  6881. Replica->FStatus = FrsErrorSuccess;
  6882. //
  6883. // Replica is not dirty
  6884. //
  6885. if (!Replica->NeedsUpdate || !Replica->IsOpen) {
  6886. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not open or not dirty");
  6887. return;
  6888. }
  6889. //
  6890. // Command packet
  6891. //
  6892. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6893. Replica, // Replica,
  6894. CMD_UPDATE_REPLICA_SET_MEMBER, // CmdRequest,
  6895. NULL, // TableCtx,
  6896. NULL, // CallContext,
  6897. 0, // TableType,
  6898. 0, // AccessRequest,
  6899. 0, // IndexType,
  6900. NULL, // KeyValue,
  6901. 0, // KeyValueLength,
  6902. FALSE); // Submit
  6903. //
  6904. // Don't free the packet when the command completes.
  6905. //
  6906. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6907. //
  6908. // SUBMIT DB Cmd and wait for completion.
  6909. //
  6910. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_UPDATE_REPLICA_SET_MEMBER");
  6911. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  6912. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  6913. //
  6914. // If wait or database op failed
  6915. //
  6916. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  6917. //
  6918. // If wait / submit failed then let caller know cmd srv submit failed.
  6919. //
  6920. if (FRS_SUCCESS(Replica->FStatus)) {
  6921. Replica->FStatus = FrsErrorCmdSrvFailed;
  6922. }
  6923. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Update Replica failed;",
  6924. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  6925. DPRINT_WS(0, "ERROR: Update Replica DB Command failed", WStatus);
  6926. goto out;
  6927. }
  6928. Replica->NeedsUpdate = !FRS_SUCCESS(Replica->FStatus);
  6929. out:
  6930. if (Cmd) {
  6931. FrsFreeCommand(Cmd, NULL);
  6932. }
  6933. }
  6934. BOOL
  6935. RcsHasReplicaRootPathMoved(
  6936. IN PREPLICA Replica,
  6937. IN PREPLICA NewReplica,
  6938. OUT PDWORD ReplicaState
  6939. )
  6940. /*++
  6941. Routine Description:
  6942. Check if the replica root path has moved. Called at each poll.
  6943. The following checks are made to make sure that the volume and journal
  6944. info is not changed while the service was not running.
  6945. VOLUME SERIAL NUMBER MISMATCH CHECK:
  6946. In case of a mismatch the replica set is marked to be deleted.
  6947. REPLICA ROOT DIR OBJECTID MISMATCH CHECK:
  6948. In case of a mismatch the replica set is marked to be deleted.
  6949. REPLICA ROOT DIR FID MISMATCH CHECK:
  6950. In case of a mismatch the replica set is marked to be deleted.
  6951. Arguments:
  6952. Replica - Existing replica structure.
  6953. NewReplica - New replica structure from DS.
  6954. ReplicaState - Error state to move to if root has moved.
  6955. Return Value:
  6956. BOOL.
  6957. --*/
  6958. {
  6959. #undef DEBSUB
  6960. #define DEBSUB "RcsHasReplicaRootPathMoved:"
  6961. HANDLE NewRootHandle = INVALID_HANDLE_VALUE;
  6962. DWORD WStatus;
  6963. DWORD VolumeInfoLength;
  6964. PFILE_FS_VOLUME_INFORMATION VolumeInfo = NULL;
  6965. IO_STATUS_BLOCK Iosb;
  6966. NTSTATUS Status;
  6967. PCONFIG_TABLE_RECORD ConfigRecord = NULL;
  6968. CHAR GuidStr[GUID_CHAR_LEN];
  6969. BOOL Result = FALSE;
  6970. PCOMMAND_PACKET CmdPkt = NULL;
  6971. ULONG AccessRequest;
  6972. PDB_SERVICE_REQUEST DbsRequest = NULL;
  6973. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  6974. FILE_INTERNAL_INFORMATION InternalFileInfo;
  6975. PREPLICA_THREAD_CTX RtCtx = NULL;
  6976. PTABLE_CTX IDTableCtx = NULL;
  6977. PVOID pKey = NULL;
  6978. PIDTABLE_RECORD IDTableRec = NULL;
  6979. //
  6980. // If this is the first time we are starting this replica set.
  6981. // Nothing to compare with.
  6982. //
  6983. if (NewReplica == NULL) {
  6984. goto RETURN;
  6985. }
  6986. ConfigRecord = (PCONFIG_TABLE_RECORD)Replica->ConfigTable.pDataRecord;
  6987. //
  6988. // Always open the path by masking off the FILE_OPEN_REPARSE_POINT flag
  6989. // because we want to open the destination dir not the junction if the root
  6990. // happens to be a mount point.
  6991. //
  6992. WStatus = FrsOpenSourceFileW(&NewRootHandle,
  6993. NewReplica->Root,
  6994. GENERIC_READ,
  6995. FILE_OPEN_FOR_BACKUP_INTENT);
  6996. if (!WIN_SUCCESS(WStatus)) {
  6997. DPRINT1_WS(0, "ERROR - Unable to open root path %ws. Retry as next poll.",
  6998. NewReplica->Root, WStatus);
  6999. goto RETURN;
  7000. }
  7001. //
  7002. // Get the volume information.
  7003. //
  7004. VolumeInfoLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
  7005. MAXIMUM_VOLUME_LABEL_LENGTH;
  7006. VolumeInfo = FrsAlloc(VolumeInfoLength);
  7007. Status = NtQueryVolumeInformationFile(NewRootHandle,
  7008. &Iosb,
  7009. VolumeInfo,
  7010. VolumeInfoLength,
  7011. FileFsVolumeInformation);
  7012. if (!NT_SUCCESS(Status)) {
  7013. DPRINT2(0,"ERROR - Getting NtQueryVolumeInformationFile for %ws. NtStatus = %08x\n",
  7014. NewReplica->Root, Status);
  7015. goto RETURN;
  7016. }
  7017. //
  7018. // VOLUME SERIAL NUMBER MISMATCH CHECK:
  7019. //
  7020. // If LastShutdown is 0 then this is the very first time we have started
  7021. // replication on this replica set so save the volumeinformation in
  7022. // the config record. Even if Lastshutdown is not 0 CnfUsnJournalID could
  7023. // be 0 because it was not getting correctly updated in Win2K.. For sysvol replica sets the
  7024. // JournalID was getting updated correctly but not the volume information.
  7025. //
  7026. if ((ConfigRecord->LastShutdown == (ULONGLONG)0) ||
  7027. (ConfigRecord->ServiceState == CNF_SERVICE_STATE_CREATING) ||
  7028. (ConfigRecord->CnfUsnJournalID == (ULONGLONG)0) ||
  7029. (
  7030. (ConfigRecord->FSVolInfo != NULL) &&
  7031. (ConfigRecord->FSVolInfo->VolumeSerialNumber == 0)
  7032. )) {
  7033. CopyMemory(ConfigRecord->FSVolInfo,VolumeInfo,sizeof(FILE_FS_VOLUME_INFORMATION) + MAXIMUM_VOLUME_LABEL_LENGTH);
  7034. Replica->NeedsUpdate = TRUE;
  7035. } else
  7036. //
  7037. // Check if the VolumeSerialNumber for New Replica matches with the
  7038. // VolumeSerialNumber from the config record for this replica set. If
  7039. // it does not then it means that this replica set has been moved.
  7040. // Returning error here will trigger a deletion of the replica set. The set will
  7041. // be recreated at the next poll cycle and it will either be primary or non-auth
  7042. // depending on the case.
  7043. //
  7044. if (VolumeInfo->VolumeSerialNumber != ConfigRecord->FSVolInfo->VolumeSerialNumber) {
  7045. DPRINT1(0,"ERROR - VolumeSerialNumber mismatch for Replica Set (%ws)\n",Replica->ReplicaName->Name);
  7046. DPRINT2(0,"ERROR - VolumeSerialNumber %x(FS) != %x(DB)\n",
  7047. VolumeInfo->VolumeSerialNumber,ConfigRecord->FSVolInfo->VolumeSerialNumber);
  7048. DPRINT1(0,"ERROR - Replica Set (%ws) is marked to be deleted\n",Replica->ReplicaName->Name);
  7049. Replica->FStatus = FrsErrorMismatchedVolumeSerialNumber;
  7050. *ReplicaState = REPLICA_STATE_MISMATCHED_VOLUME_SERIAL_NO;
  7051. Result = TRUE;
  7052. goto RETURN;
  7053. }
  7054. VolumeInfo = FrsFree(VolumeInfo);
  7055. //
  7056. // Get the FID for the replica root.
  7057. //
  7058. //
  7059. // zero the buffer in case the data that comes back is short.
  7060. //
  7061. ZeroMemory(&InternalFileInfo, sizeof(FILE_INTERNAL_INFORMATION));
  7062. Status = NtQueryInformationFile(NewRootHandle,
  7063. &Iosb,
  7064. &InternalFileInfo,
  7065. sizeof(FILE_INTERNAL_INFORMATION),
  7066. FileInternalInformation);
  7067. if (!NT_SUCCESS(Status)) {
  7068. DPRINT1(0, "ERROR getting FID for %ws\n", NewReplica->Root);
  7069. goto RETURN;
  7070. }
  7071. //
  7072. // zero the buffer in case the data that comes back is short.
  7073. //
  7074. ZeroMemory(&ObjectIdBuffer, sizeof(FILE_OBJECTID_BUFFER));
  7075. //
  7076. // Get the Object ID from the replica root.
  7077. //
  7078. Status = NtFsControlFile(
  7079. NewRootHandle, // file handle
  7080. NULL, // event
  7081. NULL, // apc routine
  7082. NULL, // apc context
  7083. &Iosb, // iosb
  7084. FSCTL_GET_OBJECT_ID, // FsControlCode
  7085. &NewRootHandle, // input buffer
  7086. sizeof(HANDLE), // input buffer length
  7087. &ObjectIdBuffer, // OutputBuffer for data from the FS
  7088. sizeof(FILE_OBJECTID_BUFFER)); // OutputBuffer Length
  7089. if (NT_SUCCESS(Status)) {
  7090. GuidToStr((GUID *)ObjectIdBuffer.ObjectId, GuidStr);
  7091. DPRINT1(4, ":S: Oid for replica root is %s\n", GuidStr );
  7092. } else
  7093. if (Status == STATUS_NOT_IMPLEMENTED) {
  7094. DPRINT1(0, ":S: ERROR - FSCTL_GET_OBJECT_ID failed on file %ws. Object IDs are not enabled on the volume.\n",
  7095. NewReplica->Root);
  7096. DisplayNTStatus(Status);
  7097. }
  7098. FRS_CLOSE(NewRootHandle);
  7099. //
  7100. // REPLICA ROOT DIR OBJECTID MISMATCH CHECK:
  7101. //
  7102. // If LastShutdown is 0 then this is the very first time we have started replication on this replica set
  7103. // in that case skip this check.
  7104. //
  7105. if (ConfigRecord->LastShutdown != (ULONGLONG)0 &&
  7106. ConfigRecord->ServiceState != CNF_SERVICE_STATE_CREATING &&
  7107. ConfigRecord->CnfUsnJournalID != (ULONGLONG)0) {
  7108. //
  7109. // The replica root might have been recreated in which case it will might
  7110. // have a object ID. In that vase we want to recreate the replica set.
  7111. // Check if the ReplicaRootGuid from config record matches with the ReplicaRootGuid
  7112. // from the FileSystem. If it does not then it means that
  7113. // this replica set has been moved. Returning error here will trigger
  7114. // a deletion of the replica set. The set will be recreated at the next
  7115. // poll cycle and it will either be primary or non-auth depending on the
  7116. // case.
  7117. //
  7118. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  7119. Status == STATUS_OBJECTID_NOT_FOUND ||
  7120. !GUIDS_EQUAL(&(ObjectIdBuffer.ObjectId), &(ConfigRecord->ReplicaRootGuid))) {
  7121. DPRINT1(0,"ERROR - Replica root guid mismatch for Replica Set (%ws)\n",Replica->ReplicaName->Name);
  7122. GuidToStr((GUID *)ObjectIdBuffer.ObjectId, GuidStr);
  7123. DPRINT1(0,"ERROR - Replica root guid (FS) (%s)\n",GuidStr);
  7124. GuidToStr((GUID *)&(ConfigRecord->ReplicaRootGuid), GuidStr);
  7125. DPRINT1(0,"ERROR - Replica root guid (DB) (%s)\n",GuidStr);
  7126. DPRINT1(0,"ERROR - Replica Set (%ws) is marked to be deleted\n",Replica->ReplicaName->Name);
  7127. Replica->FStatus = FrsErrorMismatchedReplicaRootObjectId;
  7128. *ReplicaState = REPLICA_STATE_MISMATCHED_REPLICA_ROOT_OBJECT_ID;
  7129. Result = TRUE;
  7130. goto RETURN;
  7131. }
  7132. }
  7133. //
  7134. // REPLICA ROOT DIR FID MISMATCH CHECK:
  7135. //
  7136. // If LastShutdown is 0 then this is the very first time we have started replication on this replica set
  7137. // in that case skip this check.
  7138. //
  7139. if (ConfigRecord->LastShutdown != (ULONGLONG)0 &&
  7140. ConfigRecord->ServiceState != CNF_SERVICE_STATE_CREATING &&
  7141. ConfigRecord->CnfUsnJournalID != (ULONGLONG)0) {
  7142. //
  7143. // Open the ID table.
  7144. //
  7145. RtCtx = FrsAllocType(REPLICA_THREAD_TYPE);
  7146. IDTableCtx = &RtCtx->IDTable;
  7147. AccessRequest = DBS_ACCESS_BYKEY | DBS_ACCESS_CLOSE;
  7148. pKey = (PVOID)&(ConfigRecord->ReplicaRootGuid);
  7149. CmdPkt = DbsPrepareCmdPkt(CmdPkt, // CmdPkt,
  7150. Replica, // Replica,
  7151. CMD_READ_TABLE_RECORD, // CmdRequest,
  7152. IDTableCtx, // TableCtx,
  7153. NULL, // CallContext,
  7154. IDTablex, // TableType,
  7155. AccessRequest, // AccessRequest,
  7156. GuidIndexx, // IndexType,
  7157. pKey, // KeyValue,
  7158. sizeof(GUID), // KeyValueLength,
  7159. FALSE); // Submit
  7160. if (CmdPkt == NULL) {
  7161. DPRINT(0, "ERROR - Failed to init the cmd pkt\n");
  7162. RtCtx = FrsFreeType(RtCtx);
  7163. goto RETURN;;
  7164. }
  7165. FrsSetCompletionRoutine(CmdPkt, FrsCompleteKeepPkt, NULL);
  7166. Status = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, CmdPkt, INFINITE);
  7167. DbsRequest = &CmdPkt->Parameters.DbsRequest;
  7168. IDTableCtx = DBS_GET_TABLECTX(DbsRequest);
  7169. IDTableRec = IDTableCtx->pDataRecord;
  7170. if (DbsRequest == NULL || DbsRequest->FStatus != FrsErrorSuccess) {
  7171. RtCtx = FrsFreeType(RtCtx);
  7172. FrsFreeCommand(CmdPkt, NULL);
  7173. goto RETURN;
  7174. }
  7175. //
  7176. // The replica root might have been recreated by a restore operation in which case
  7177. // it will have the same object ID but a different FID. In that case we want
  7178. // to recreate the replica set. Check if the FID from IDTable matches with the FID
  7179. // from the FileSystem. If it does not then it means that this replica set has been
  7180. // moved. Returning error here will trigger a deletion of the replica set. The set
  7181. // will be recreated at the next poll cycle and it will either be primary or non-auth
  7182. // depending on the case.
  7183. // This can also happen when a junction point is present in the initial path to the replica
  7184. // root. At a later time the junction points destination is changed and the replica rpot
  7185. // has been moved.
  7186. //
  7187. if (IDTableRec->FileID != InternalFileInfo.IndexNumber.QuadPart) {
  7188. DPRINT1(0,"ERROR - Replica root fid mismatch for Replica Set (%ws)\n",Replica->ReplicaName->Name);
  7189. DPRINT1(0,"ERROR - Replica root fid (FS) (%08x %08x)\n",PRINTQUAD(InternalFileInfo.IndexNumber.QuadPart));
  7190. DPRINT1(0,"ERROR - Replica root fid (DB) (%08x %08x)\n",PRINTQUAD(IDTableRec->FileID));
  7191. DPRINT1(0,"ERROR - Replica Set (%ws) is marked to be deleted\n",Replica->ReplicaName->Name);
  7192. RtCtx = FrsFreeType(RtCtx);
  7193. FrsFreeCommand(CmdPkt, NULL);
  7194. Replica->FStatus = FrsErrorMismatchedReplicaRootFileId;
  7195. *ReplicaState = REPLICA_STATE_MISMATCHED_REPLICA_ROOT_FILE_ID;
  7196. Result = TRUE;
  7197. goto RETURN;
  7198. }
  7199. RtCtx = FrsFreeType(RtCtx);
  7200. FrsFreeCommand(CmdPkt, NULL);
  7201. }
  7202. RETURN:
  7203. VolumeInfo = FrsFree(VolumeInfo);
  7204. FRS_CLOSE(NewRootHandle);
  7205. return Result;
  7206. }
  7207. VOID
  7208. RcsStartReplicaSetMember(
  7209. IN PCOMMAND_PACKET Cmd
  7210. )
  7211. /*++
  7212. Routine Description:
  7213. Bring the replica up to joined, active status.
  7214. Arguments:
  7215. Cmd.
  7216. Return Value:
  7217. None.
  7218. --*/
  7219. {
  7220. #undef DEBSUB
  7221. #define DEBSUB "RcsStartReplicaSetMember:"
  7222. PREPLICA Replica;
  7223. PCXTION Cxtion;
  7224. ULONGLONG MembershipExpires;
  7225. PVOID Key;
  7226. DWORD NumberOfCxtions;
  7227. DWORD ReplicaState;
  7228. ULONG FStatus;
  7229. PWCHAR CmdFile = NULL;
  7230. ULONG FileAttributes;
  7231. extern ULONGLONG ActiveChange;
  7232. extern ULONG DsPollingInterval;
  7233. WCHAR DsPollingIntervalStr[7]; // Max interval is NTFRSAPI_MAX_INTERVAL.
  7234. FRS_ERROR_CODE SavedFStatus;
  7235. //
  7236. // Check the command packet
  7237. //
  7238. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7239. return;
  7240. }
  7241. Replica = RsReplica(Cmd);
  7242. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsStartReplicaSetMember entry");
  7243. FRS_PRINT_TYPE(4, Replica);
  7244. //
  7245. // Increment the Replica Sets started counter
  7246. //
  7247. PM_INC_CTR_SERVICE(PMTotalInst, RSStarted, 1);
  7248. //
  7249. // Someone is trying to start a deleted replica. This is either part
  7250. // of startup and we are simply trying to start replication on all
  7251. // replicas or a deleted replica has actually reappeared.
  7252. //
  7253. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  7254. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Tombstoned");
  7255. //
  7256. // The deletion hasn't completed processing. The jrnlcxtion cannot
  7257. // be restarted without restarting the entire replica set. The
  7258. // set needs to be "closed" and then "opened". Let the tombstoning
  7259. // finish before attempting to re-open. A completely closed
  7260. // replica set has IsOpen set to FALSE and no cxtions.
  7261. //
  7262. if (Replica->IsOpen || GTabNumberInTable(Replica->Cxtions)) {
  7263. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica tombstone in progress");
  7264. RcsSubmitTransferToRcs(Cmd, CMD_DELETE);
  7265. return;
  7266. }
  7267. //
  7268. // Don't start a deleted replica unless it has magically reappeared.
  7269. //
  7270. if (RsNewReplica(Cmd) == NULL) {
  7271. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7272. return;
  7273. }
  7274. //
  7275. // Don't reanimate if the tombstone has expired
  7276. //
  7277. if (RcsReplicaHasExpired(Replica)) {
  7278. //
  7279. // Remove registry entry
  7280. //
  7281. RcsReplicaDeleteRegistry(Replica);
  7282. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Expired");
  7283. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7284. return;
  7285. }
  7286. //
  7287. // A deleted replica has reappeared; undelete the replica
  7288. //
  7289. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Reanimating");
  7290. RcsOpenReplicaSetMember(Replica);
  7291. MembershipExpires = Replica->MembershipExpires;
  7292. Replica->MembershipExpires = 0;
  7293. Replica->NeedsUpdate = TRUE;
  7294. RcsUpdateReplicaSetMember(Replica);
  7295. //
  7296. // The above friggen call set NeedsUpdate to false if the update succeeded.
  7297. //
  7298. //
  7299. // Replica cannot be marked as "undeleted" in the DB; retry later
  7300. // and *don't* start. We wouldn't want to start replication only
  7301. // to have the replica disappear from the database at the next
  7302. // reboot or service startup because its timeout expired.
  7303. //
  7304. FStatus = DbsCheckForOverlapErrors(Replica);
  7305. if (Replica->NeedsUpdate || !FRS_SUCCESS(FStatus)) {
  7306. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Reanimation failed");
  7307. Replica->MembershipExpires = MembershipExpires;
  7308. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7309. //
  7310. // Ds poll thread will restart the replica during the next
  7311. // polling cycle if ActiveChange is set to 0.
  7312. //
  7313. ActiveChange = 0;
  7314. //
  7315. // Note: Does there need to be a replica set close here?
  7316. // Need to check all use of Replica->IsOpen to figure this out.
  7317. //
  7318. return;
  7319. }
  7320. //
  7321. // The open above returned success so Replica->IsOpen would be set
  7322. // as expected but since the replica set was marked expired the actual
  7323. // service state for the replica set is STOPPED and the handles to
  7324. // The pre-install dir was never opened. The call to reopen later
  7325. // will fail if Replica->IsOpen is still TRUE. So close it for now.
  7326. //
  7327. // *Note*
  7328. // Perf: Get rid of the friggen Replica->IsOpen flag and use the service
  7329. // state as originally intended.
  7330. //
  7331. RcsCloseReplicaSetmember(Replica);
  7332. //
  7333. // No longer tombstoned; update the registry
  7334. //
  7335. RcsReplicaSetRegistry(Replica);
  7336. //
  7337. // Set registry value "FilesNotToBackup"
  7338. //
  7339. CfgFilesNotToBackup(ReplicasByGuid);
  7340. }
  7341. //
  7342. // If this replica is in the error state then first make sure it is closed.
  7343. // and reset its state to initializing.
  7344. //
  7345. if (REPLICA_IN_ERROR_STATE(Replica->ServiceState)) {
  7346. RcsCloseReplicaSetmember(Replica);
  7347. JrnlSetReplicaState(Replica, REPLICA_STATE_INITIALIZING);
  7348. }
  7349. //
  7350. // Check if the replica root path has moved between two polls.
  7351. //
  7352. if (RcsHasReplicaRootPathMoved(Replica, RsNewReplica(Cmd), &ReplicaState)) {
  7353. //
  7354. // Save the FStatus. We need the correct FStatus to report in the
  7355. // eventlog written in JrnlSetReplicaState(). FStatus set by
  7356. // RcsHasReplicaRootPathMoved() is overwritten when we stop and
  7357. // close the replica set.
  7358. //
  7359. //
  7360. SavedFStatus = Replica->FStatus;
  7361. //
  7362. // The replica root has moved. This could be a intentional move or
  7363. // it could be caused by change of drive letter. In any case we need a
  7364. // confirmation from the user to go ahead and trigger a non-auth restore
  7365. // of the replica set. We will look for a special file "NTFRS_CMD_FILE_MOVE_ROOT"
  7366. // under the new replica root. If this file is present we will go ahead and delete
  7367. // the replica set which will trigger a non-auth restore at the next poll.
  7368. // The command file is deleted when the replica set is initialized.
  7369. //
  7370. CmdFile = FrsWcsCat3((RsNewReplica(Cmd))->Root, L"\\", NTFRS_CMD_FILE_MOVE_ROOT);
  7371. FileAttributes = GetFileAttributes(CmdFile);
  7372. if ((FileAttributes == 0xffffffff) ||
  7373. (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  7374. //
  7375. // Get the DsPollingInteval in minutes.
  7376. //
  7377. _itow(DsPollingInterval / (60 * 1000), DsPollingIntervalStr, 10);
  7378. EPRINT4(EVENT_FRS_ROOT_HAS_MOVED, Replica->SetName->Name, Replica->Root,
  7379. (RsNewReplica(Cmd))->Root, DsPollingIntervalStr);
  7380. DPRINT1(0,"ERROR Command file not found at the new root %ws. Can not move root.\n",CmdFile);
  7381. //
  7382. // This replica state will not trigger a delete but it will still put it on
  7383. // the fault list.
  7384. //
  7385. ReplicaState = REPLICA_STATE_ERROR;
  7386. }
  7387. CmdFile = FrsFree(CmdFile);
  7388. RcsSubmitStopReplicaToDb(Replica);
  7389. RcsCloseReplicaSetmember(Replica);
  7390. RcsCloseReplicaCxtions(Replica);
  7391. //
  7392. // Write the saved FStatus back so we can write it to the eventlog.
  7393. //
  7394. Replica->FStatus = SavedFStatus;
  7395. JrnlSetReplicaState(Replica, ReplicaState);
  7396. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7397. ActiveChange = 0;
  7398. return;
  7399. }
  7400. //
  7401. // Retry the open
  7402. //
  7403. RcsOpenReplicaSetMember(Replica);
  7404. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "B, Replica opened");
  7405. //
  7406. // Pre-Install Dir should now be open.
  7407. //
  7408. if (!HANDLE_IS_VALID(Replica->PreInstallHandle) ||
  7409. !FRS_SUCCESS(Replica->FStatus)) {
  7410. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7411. ActiveChange = 0;
  7412. return;
  7413. }
  7414. //
  7415. // Retry the journal
  7416. //
  7417. RcsInitOneReplicaSet(Replica);
  7418. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsJournaling, "B, Journal opened");
  7419. //
  7420. // Update the database iff fields have changed
  7421. //
  7422. RcsMergeReplicaFields(Replica, RsNewReplica(Cmd));
  7423. //
  7424. // If needed, update the replica in the database
  7425. //
  7426. RcsUpdateReplicaSetMember(Replica);
  7427. //
  7428. // The above friggen call set Replica->NeedsUpdate to false if the update succeeded.
  7429. //
  7430. //
  7431. // Update the database iff cxtions have changed
  7432. //
  7433. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Merge Replica Cxtions");
  7434. NumberOfCxtions = GTabNumberInTable(Replica->Cxtions);
  7435. RcsMergeReplicaCxtions(Replica, RsNewReplica(Cmd), RsNewCxtion(Cmd));
  7436. RsNewCxtion(Cmd) = NULL;
  7437. if (NumberOfCxtions != GTabNumberInTable(Replica->Cxtions)) {
  7438. RcsReplicaSetRegistry(Replica);
  7439. }
  7440. //
  7441. // Accept remote change orders and join outbound connections.
  7442. //
  7443. if (Replica->IsOpen && Replica->IsJournaling) {
  7444. Replica->IsAccepting = TRUE;
  7445. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsAccepting, "B, Is Accepting");
  7446. }
  7447. //
  7448. // Retry the join
  7449. //
  7450. if (Replica->IsOpen && Replica->IsJournaling) {
  7451. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica accepting, Starting cxtions");
  7452. //
  7453. // If we are in the seeding state then let the Initial Sync command server
  7454. // control the joining.
  7455. //
  7456. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  7457. if (Replica->InitSyncQueue == NULL) {
  7458. //
  7459. // Initialize the queue for the InitSync Command server.
  7460. //
  7461. Replica->InitSyncQueue = FrsAlloc(sizeof(FRS_QUEUE));
  7462. FrsInitializeQueue(Replica->InitSyncQueue, &InitSyncCs.Control);
  7463. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, submit CMD_INITSYNC_START_SYNC");
  7464. InitSyncSubmitToInitSyncCs(Replica, CMD_INITSYNC_START_SYNC);
  7465. } else {
  7466. //
  7467. // Initial Sync command server is already working on this replica set.
  7468. //
  7469. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica in initial sync state");
  7470. }
  7471. }
  7472. //
  7473. // Process all the connections in the table by putting a command
  7474. // packet for each cxtion on this replica's command queue.
  7475. //
  7476. Key = NULL;
  7477. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  7478. //
  7479. // If replica is in seeding state then skip the connections that have
  7480. // not completed their initial join. (CXTION_FLAGS_INIT_SYNC)
  7481. // These connections will be joined by the initial sync command server.
  7482. //
  7483. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  7484. CxtionFlagIs(Cxtion, CXTION_FLAGS_INIT_SYNC)) {
  7485. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, skip cxtion join");
  7486. continue;
  7487. }
  7488. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, submit cxtion join");
  7489. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, FALSE);
  7490. }
  7491. } else {
  7492. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT accepting");
  7493. //
  7494. // Ds poll thread will restart the replica during the next
  7495. // polling cycle if ActiveChange is set to 0.
  7496. //
  7497. ActiveChange = 0;
  7498. }
  7499. //
  7500. // Check if this replica set is journaling and is not seeding or is online.
  7501. //
  7502. if (Replica->IsJournaling &&
  7503. ((!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  7504. !Replica->IsSeeding) ||
  7505. BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE))){
  7506. //
  7507. // If this is a sysvol replica set then set sysvol ready if not already set.
  7508. //
  7509. if (FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType) &&
  7510. !Replica->IsSysvolReady) {
  7511. Replica->IsSysvolReady = RcsSetSysvolReady(1);
  7512. if (!Replica->IsSysvolReady) {
  7513. //
  7514. // Ds poll thread will restart the replica during the next
  7515. // polling cycle if ActiveChange is set to 0.
  7516. //
  7517. ActiveChange = 0;
  7518. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica sysvol not ready");
  7519. } else {
  7520. RcsReplicaSetRegistry(Replica);
  7521. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica sysvol is ready");
  7522. }
  7523. }
  7524. //
  7525. // Also make this set online if not already set.
  7526. //
  7527. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  7528. SetFlag(Replica->CnfFlags, CONFIG_FLAG_ONLINE);
  7529. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is Online");
  7530. Replica->NeedsUpdate = TRUE;
  7531. }
  7532. }
  7533. if (Replica->NeedsUpdate) {
  7534. //
  7535. // Ds poll thread will restart the replica during the next
  7536. // polling cycle if ActiveChange is set to 0.
  7537. //
  7538. ActiveChange = 0;
  7539. }
  7540. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7541. }
  7542. VOID
  7543. RcsDeleteReplicaRetry(
  7544. IN PCOMMAND_PACKET Cmd
  7545. )
  7546. /*++
  7547. Routine Description:
  7548. Retry bringing the replica down to an unjoined, idle status.
  7549. Arguments:
  7550. Cmd.
  7551. Return Value:
  7552. None.
  7553. --*/
  7554. {
  7555. #undef DEBSUB
  7556. #define DEBSUB "RcsDeleteReplicaRetry:"
  7557. FILETIME FileTime;
  7558. ULONGLONG Now;
  7559. PREPLICA Replica;
  7560. PVOID CxtionKey;
  7561. PCXTION Cxtion;
  7562. //
  7563. // Check the command packet
  7564. //
  7565. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7566. return;
  7567. }
  7568. Replica = RsReplica(Cmd);
  7569. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsDeleteReplicaRetry entry");
  7570. //
  7571. // No longer tombstoned; done
  7572. //
  7573. if (IS_TIME_ZERO(Replica->MembershipExpires)) {
  7574. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7575. return;
  7576. }
  7577. //
  7578. // Start the unjoin process on all cxtions
  7579. //
  7580. CxtionKey = NULL;
  7581. while ((!FrsIsShuttingDown) &&
  7582. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7583. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Force unjoin cxtion");
  7584. RcsForceUnjoin(Replica, Cxtion);
  7585. }
  7586. //
  7587. // Are all cxtions unjoined?
  7588. //
  7589. CxtionKey = NULL;
  7590. Cxtion = NULL;
  7591. while ((!FrsIsShuttingDown) &&
  7592. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7593. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  7594. !CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  7595. break;
  7596. }
  7597. }
  7598. //
  7599. // Not all cxtions are unjoined (or deleted). Retry this command
  7600. // in a bit if the replica set ramains tombstoned.
  7601. //
  7602. if (Cxtion) {
  7603. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Retry delete later, again");
  7604. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CMD_DELETE_RETRY_LONG_TIMEOUT);
  7605. return;
  7606. }
  7607. //
  7608. // All of the cxtions were successfully unjoined. Shut down the replica.
  7609. //
  7610. //
  7611. // Stop accepting comm packets. Errors are returned to our partner.
  7612. //
  7613. // IsAccepting will become TRUE again in RcsStartReplicaSetMember() before
  7614. // any cxtion rejoins.
  7615. //
  7616. Replica->IsAccepting = FALSE;
  7617. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT Accepting");
  7618. //
  7619. // Stop journal processing and close the replica.
  7620. //
  7621. RcsSubmitStopReplicaToDb(Replica);
  7622. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "IsOpen, Replica closed");
  7623. if (Replica->IsOpen) {
  7624. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, Replica still open");
  7625. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7626. return;
  7627. } else {
  7628. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica closed");
  7629. }
  7630. //
  7631. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  7632. // generate new cxtion structs before active processing (aka joining)
  7633. // occurs. The cxtions remain in the DeletedCxtions table so that
  7634. // other threads that may have been time sliced just after acquiring
  7635. // the cxtion pointer but before making use of it will not AV. We
  7636. // could have put in locks but then there would be deadlock and
  7637. // perf considerations; all for the sake of this seldom occuring
  7638. // operation.
  7639. //
  7640. RcsCloseReplicaCxtions(Replica);
  7641. //
  7642. // Increment the Replica Sets deleted counter
  7643. //
  7644. PM_INC_CTR_SERVICE(PMTotalInst, RSDeleted, 1);
  7645. //
  7646. // Has the tombstone expired?
  7647. //
  7648. if (RcsReplicaHasExpired(Replica)) {
  7649. RcsSubmitTransferToRcs(Cmd, CMD_DELETE_NOW);
  7650. } else {
  7651. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7652. }
  7653. return;
  7654. }
  7655. VOID
  7656. RcsDeleteReplicaSetMember(
  7657. IN PCOMMAND_PACKET Cmd
  7658. )
  7659. /*++
  7660. Routine Description:
  7661. Bring the replica down to an unjoined, idle status.
  7662. Arguments:
  7663. Cmd.
  7664. Return Value:
  7665. None.
  7666. --*/
  7667. {
  7668. #undef DEBSUB
  7669. #define DEBSUB "RcsDeleteReplicaSetMember:"
  7670. FILETIME FileTime;
  7671. ULONGLONG Now;
  7672. PREPLICA Replica;
  7673. PVOID CxtionKey;
  7674. PCXTION Cxtion;
  7675. //
  7676. // Check the command packet
  7677. //
  7678. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7679. return;
  7680. }
  7681. Replica = RsReplica(Cmd);
  7682. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsDeleteReplicaSetMember entry");
  7683. //
  7684. // Time in 100nsec tics since Jan 1, 1601
  7685. //
  7686. GetSystemTimeAsFileTime(&FileTime);
  7687. COPY_TIME(&Now, &FileTime);
  7688. //
  7689. // SET THE TOMBSTONE
  7690. //
  7691. if (IS_TIME_ZERO(Replica->MembershipExpires)) {
  7692. //
  7693. // Set the timeout
  7694. //
  7695. Replica->MembershipExpires = Now + ReplicaTombstoneInFileTime;
  7696. //
  7697. // Update the database record
  7698. //
  7699. Replica->NeedsUpdate = TRUE;
  7700. RcsUpdateReplicaSetMember(Replica);
  7701. //
  7702. // The above friggen call set NeedsUpdate to false if the update succeeded.
  7703. //
  7704. //
  7705. // Couldn't update; reset the timeout and retry at the next ds poll
  7706. //
  7707. if (Replica->NeedsUpdate) {
  7708. Replica->MembershipExpires = 0;
  7709. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7710. return;
  7711. }
  7712. }
  7713. //
  7714. // Set registry value "FilesNotToBackup"
  7715. //
  7716. CfgFilesNotToBackup(ReplicasByGuid);
  7717. //
  7718. // Tombstoned; update the registry
  7719. //
  7720. RcsReplicaSetRegistry(Replica);
  7721. //
  7722. // Start the unjoin process on all cxtions
  7723. //
  7724. CxtionKey = NULL;
  7725. while ((!FrsIsShuttingDown) &&
  7726. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7727. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Force unjoin cxtion");
  7728. RcsForceUnjoin(Replica, Cxtion);
  7729. }
  7730. //
  7731. // Are all cxtions unjoined?
  7732. //
  7733. CxtionKey = NULL;
  7734. Cxtion = NULL;
  7735. while ((!FrsIsShuttingDown) &&
  7736. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7737. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  7738. !CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  7739. break;
  7740. }
  7741. }
  7742. //
  7743. // Not all cxtions are unjoined (or deleted). Try again at the
  7744. // next ds polling cycle IFF the set is still deleted. Return
  7745. // success since the set has been successfully marked as
  7746. // tombstoned.
  7747. if (Cxtion) {
  7748. //
  7749. // Complete the old command packet in case another thread
  7750. // is waiting on it (like FrsDsStartDemotion()).
  7751. //
  7752. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Retry delete later");
  7753. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7754. //
  7755. // Allocate a new command packet that will retry the delete
  7756. // as long as the replica set remains tombstoned.
  7757. //
  7758. Cmd = FrsAllocCommand(Replica->Queue, CMD_DELETE_RETRY);
  7759. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  7760. RsReplica(Cmd) = Replica;
  7761. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CMD_DELETE_RETRY_SHORT_TIMEOUT);
  7762. return;
  7763. }
  7764. //
  7765. // All of the cxtions were successfully unjoined. Shut down the replica.
  7766. //
  7767. //
  7768. // Stop accepting comm packets. Errors are returned to our partner.
  7769. //
  7770. // IsAccepting will become TRUE again in RcsStartReplicaSetMember() before
  7771. // any cxtion rejoins.
  7772. //
  7773. Replica->IsAccepting = FALSE;
  7774. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT Accepting");
  7775. //
  7776. // Stop journal processing and close the replica.
  7777. //
  7778. RcsSubmitStopReplicaToDb(Replica);
  7779. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "IsOpen, Replica closed");
  7780. if (Replica->IsOpen) {
  7781. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, Replica still open");
  7782. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7783. return;
  7784. } else {
  7785. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica closed");
  7786. }
  7787. //
  7788. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  7789. // generate new cxtion structs before active processing (aka joining)
  7790. // occurs. The cxtions remain in the DeletedCxtions table so that
  7791. // other threads that may have been time sliced just after acquiring
  7792. // the cxtion pointer but before making use of it will not AV. We
  7793. // could have put in locks but then there would be deadlock and
  7794. // perf considerations; all for the sake of this seldom occuring
  7795. // operation.
  7796. //
  7797. RcsCloseReplicaCxtions(Replica);
  7798. //
  7799. // Increment the Replica Sets deleted counter
  7800. //
  7801. PM_INC_CTR_SERVICE(PMTotalInst, RSDeleted, 1);
  7802. //
  7803. // Has the tombstone expired?
  7804. //
  7805. if (RcsReplicaHasExpired(Replica)) {
  7806. RcsSubmitTransferToRcs(Cmd, CMD_DELETE_NOW);
  7807. } else {
  7808. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7809. }
  7810. return;
  7811. }
  7812. VOID
  7813. RcsDeleteReplicaSetMemberNow(
  7814. IN PCOMMAND_PACKET Cmd
  7815. )
  7816. /*++
  7817. Routine Description:
  7818. Bring the replica down to an unjoined, idle status. Don't reanimate.
  7819. Arguments:
  7820. Cmd.
  7821. Return Value:
  7822. None.
  7823. --*/
  7824. {
  7825. #undef DEBSUB
  7826. #define DEBSUB "RcsDeleteReplicaSetMemberNow:"
  7827. FILETIME FileTime;
  7828. ULONGLONG Now;
  7829. PREPLICA Replica;
  7830. PVOID CxtionKey;
  7831. PCXTION Cxtion;
  7832. ULONGLONG OldMembershipExpires;
  7833. //
  7834. // Check the command packet
  7835. //
  7836. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7837. return;
  7838. }
  7839. Replica = RsReplica(Cmd);
  7840. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsDeleteReplicaSetMemberNow entry");
  7841. //
  7842. // Time in 100nsec tics since Jan 1, 1601
  7843. //
  7844. GetSystemTimeAsFileTime(&FileTime);
  7845. COPY_TIME(&Now, &FileTime);
  7846. if (IS_TIME_ZERO(Replica->MembershipExpires) || Replica->MembershipExpires >= Now) {
  7847. //
  7848. // Never reanimate this replica.
  7849. //
  7850. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Marking Replica expired");
  7851. RcsOpenReplicaSetMember(Replica);
  7852. OldMembershipExpires = Replica->MembershipExpires;
  7853. Replica->MembershipExpires = Now - ONEDAY;
  7854. Replica->NeedsUpdate = TRUE;
  7855. RcsUpdateReplicaSetMember(Replica);
  7856. //
  7857. // The above friggen call set NeedsUpdate to false if the update succeeded.
  7858. //
  7859. //
  7860. // Replica cannot be updated in the DB. Give up.
  7861. //
  7862. if (Replica->NeedsUpdate) {
  7863. Replica->MembershipExpires = OldMembershipExpires;
  7864. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7865. return;
  7866. }
  7867. }
  7868. //
  7869. // Set registry value "FilesNotToBackup"
  7870. //
  7871. CfgFilesNotToBackup(ReplicasByGuid);
  7872. //
  7873. // Remove registry entry
  7874. //
  7875. RcsReplicaDeleteRegistry(Replica);
  7876. //
  7877. // Start the unjoin process on all cxtions
  7878. //
  7879. CxtionKey = NULL;
  7880. while ((!FrsIsShuttingDown) &&
  7881. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7882. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Force unjoin cxtion");
  7883. RcsForceUnjoin(Replica, Cxtion);
  7884. }
  7885. //
  7886. // Are all cxtions unjoined?
  7887. //
  7888. CxtionKey = NULL;
  7889. Cxtion = NULL;
  7890. while ((!FrsIsShuttingDown) &&
  7891. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7892. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  7893. !CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  7894. break;
  7895. }
  7896. }
  7897. //
  7898. // Not all cxtions are unjoined (or deleted). Try again at the
  7899. // next ds polling cycle IFF the set is still deleted. Return
  7900. // success since the set has been successfully marked as
  7901. // do-not-animate.
  7902. //
  7903. if (Cxtion) {
  7904. //
  7905. // Complete the old command packet in case another thread
  7906. // is waiting on it (like FrsDsStartDemotion()).
  7907. //
  7908. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Retry delete later");
  7909. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7910. //
  7911. // Allocate a new command packet that will retry the delete
  7912. // as long as the replica set remains tombstoned.
  7913. //
  7914. Cmd = FrsAllocCommand(Replica->Queue, CMD_DELETE_RETRY);
  7915. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  7916. RsReplica(Cmd) = Replica;
  7917. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CMD_DELETE_RETRY_SHORT_TIMEOUT);
  7918. return;
  7919. }
  7920. //
  7921. // All of the cxtions were successfully unjoined. Shut down the replica.
  7922. //
  7923. //
  7924. // Stop accepting comm packets. Errors are returned to our partner.
  7925. //
  7926. Replica->IsAccepting = FALSE;
  7927. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT Accepting");
  7928. //
  7929. // Stop journal processing and close the replica.
  7930. //
  7931. RcsSubmitStopReplicaToDb(Replica);
  7932. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "IsOpen, Replica closed");
  7933. if (Replica->IsOpen) {
  7934. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, Replica still open");
  7935. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7936. return;
  7937. } else {
  7938. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica closed");
  7939. }
  7940. //
  7941. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  7942. // generate new cxtion structs before active processing (aka joining)
  7943. // occurs. The cxtions remain in the DeletedCxtions table so that
  7944. // other threads that may have been time sliced just after acquiring
  7945. // the cxtion pointer but before making use of it will not AV. We
  7946. // could have put in locks but then there would be deadlock and
  7947. // perf considerations; all for the sake of this seldom occuring
  7948. // operation.
  7949. //
  7950. RcsCloseReplicaCxtions(Replica);
  7951. //
  7952. // Increment the Replica Sets removed counter
  7953. //
  7954. PM_INC_CTR_SERVICE(PMTotalInst, RSRemoved, 1);
  7955. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7956. return;
  7957. }
  7958. VOID
  7959. RcsStartValidReplicaSetMembers(
  7960. IN PCOMMAND_PACKET Cmd
  7961. )
  7962. /*++
  7963. Routine Description:
  7964. Tell the replicas to bring themselves up to joined, active status.
  7965. This includes the journal and joining with inbound partners.
  7966. This routine is run once at service startup and then once
  7967. an hour to check the schedule.
  7968. Arguments:
  7969. None.
  7970. Return Value:
  7971. None.
  7972. --*/
  7973. {
  7974. #undef DEBSUB
  7975. #define DEBSUB "RcsStartValidReplicaSetMembers:"
  7976. PVOID Key;
  7977. PREPLICA Replica;
  7978. ULONG TimeOut;
  7979. SYSTEMTIME SystemTime;
  7980. DPRINT1(4, ":S: Command start replicas waiting %08x\n", Cmd);
  7981. WaitForSingleObject(ReplicaEvent, INFINITE);
  7982. DPRINT1(4, ":S: Command start replicas %08x\n", Cmd);
  7983. //
  7984. // Send a start command to each replica. Replicas that are already
  7985. // started or starting will ignore the command. The replicas will
  7986. // check their join status and rejoin if needed.
  7987. //
  7988. Key = NULL;
  7989. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  7990. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit Start Replica");
  7991. RcsSubmitReplica(Replica, NULL, CMD_START);
  7992. }
  7993. //
  7994. // Milliseconds till the next hour
  7995. //
  7996. GetSystemTime(&SystemTime);
  7997. TimeOut = ((60 - SystemTime.wMinute) * 60000) +
  7998. ((60 - SystemTime.wSecond) * 1000) +
  7999. (1000 - SystemTime.wMilliseconds);
  8000. DPRINT1(4, "Check schedules in %d seconds\n", TimeOut / 1000);
  8001. #if DBG
  8002. if (DebugInfo.Interval) {
  8003. TimeOut = DebugInfo.Interval * 1000;
  8004. DPRINT1(0, ":X: DEBUG - toggle schedules in %d seconds\n", TimeOut / 1000);
  8005. }
  8006. #endif DBG
  8007. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, TimeOut);
  8008. }
  8009. ULONG
  8010. RcsSubmitCommPktToRcsQueue(
  8011. IN handle_t ServerHandle,
  8012. IN PCOMM_PACKET CommPkt,
  8013. IN PWCHAR AuthClient,
  8014. IN PWCHAR AuthName,
  8015. IN DWORD AuthLevel,
  8016. IN DWORD AuthN,
  8017. IN DWORD AuthZ
  8018. )
  8019. /*++
  8020. Routine Description:
  8021. Convert a comm packet into a command packet and send
  8022. it to the correct replica set. NOTE - RPC owns the comm
  8023. packet.
  8024. Arguments:
  8025. ServerHandle
  8026. CommPkt
  8027. AuthClient
  8028. AuthName
  8029. AuthLevel
  8030. AuthN
  8031. AuthZ
  8032. Return Value:
  8033. Error status to be propagated to the sender
  8034. --*/
  8035. {
  8036. #undef DEBSUB
  8037. #define DEBSUB "RcsSubmitCommPktToRcsQueue:"
  8038. DWORD WStatus;
  8039. PCOMMAND_PACKET Cmd = NULL;
  8040. PREPLICA Replica;
  8041. PCXTION Cxtion = NULL;
  8042. ULONG WaitTime;
  8043. ULONG NumWaitingCOs;
  8044. //
  8045. // Convert the comm packet into a command packet
  8046. //
  8047. Cmd = CommPktToCmd(CommPkt);
  8048. if (Cmd == NULL) {
  8049. COMMAND_RCV_TRACE(3, Cmd, Cxtion, ERROR_INVALID_DATA, "RcvFail - no cmd");
  8050. return ERROR_INVALID_DATA;
  8051. }
  8052. //
  8053. // Must have the replica's name in order to queue the command
  8054. //
  8055. if (RsReplicaName(Cmd) == NULL || RsReplicaName(Cmd)->Name == NULL ) {
  8056. COMMAND_RCV_TRACE(3, Cmd, Cxtion, ERROR_INVALID_NAME, "RcvFail - no replica name");
  8057. FrsCompleteCommand(Cmd, ERROR_INVALID_NAME);
  8058. return ERROR_INVALID_NAME;
  8059. }
  8060. //
  8061. // Find the target replica
  8062. //
  8063. Replica = GTabLookup(ReplicasByGuid, RsReplicaName(Cmd)->Guid, NULL);
  8064. if (Replica == NULL) {
  8065. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_FILE_NOT_FOUND, "RcvFail - replica not found");
  8066. FrsCompleteCommand(Cmd, ERROR_FILE_NOT_FOUND);
  8067. return ERROR_FILE_NOT_FOUND;
  8068. }
  8069. //
  8070. // The target replica may not be accepting comm packets
  8071. //
  8072. if (!Replica->IsAccepting) {
  8073. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_RETRY, "RcvFail - not accepting");
  8074. FrsCompleteCommand(Cmd, ERROR_RETRY);
  8075. return ERROR_RETRY;
  8076. }
  8077. //
  8078. // Find the cxtion
  8079. //
  8080. if (RsCxtion(Cmd)) {
  8081. LOCK_CXTION_TABLE(Replica);
  8082. Cxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  8083. if (Cxtion != NULL) {
  8084. Cxtion->PartnerMajor = CommPkt->Major;
  8085. Cxtion->PartnerMinor = CommPkt->Minor;
  8086. //
  8087. // The count of comm packets is used to detect a hung outbound
  8088. // cxtion (See CMD_HUNG_CXTION). The hang is most likely caused by
  8089. // a dropped ack.
  8090. //
  8091. Cxtion->CommPkts++;
  8092. //
  8093. // This change order may already exist on this machine. If so,
  8094. // use its change order entry because we will need its database
  8095. // context for updates.
  8096. //
  8097. LOCK_CXTION_COE_TABLE(Replica, Cxtion);
  8098. if (RsCoGuid(Cmd)) {
  8099. RsCoe(Cmd) = GTabLookupNoLock(Cxtion->CoeTable, RsCoGuid(Cmd), NULL);
  8100. //
  8101. // Note this command should be a response to a stage file
  8102. // fetch request. As such the Command code should be one of
  8103. // the following:
  8104. // CMD_RECEIVING_STAGE, CMD_RETRY_FETCH, or CMD_ABORT_FETCH.
  8105. // If it is anything else then don't pull it out of the table.
  8106. //
  8107. // This check is needed because if we have just restarted this
  8108. // connection then this CO could be a resend of a CO that was
  8109. // already restarted from the Inbound log. Without the Command
  8110. // check we would incorrectly attach this Coe state to the wrong
  8111. // command packet and possibly cancel the timeout check.
  8112. //
  8113. if (RsCoe(Cmd) && ((Cmd->Command == CMD_RECEIVING_STAGE) ||
  8114. (Cmd->Command == CMD_RETRY_FETCH) ||
  8115. (Cmd->Command == CMD_ABORT_FETCH)) ) {
  8116. GTabDeleteNoLock(Cxtion->CoeTable, RsCoGuid(Cmd), NULL, NULL);
  8117. } else {
  8118. RsCoe(Cmd) = NULL;
  8119. }
  8120. }
  8121. NumWaitingCOs = GTabNumberInTable(Cxtion->CoeTable);
  8122. UNLOCK_CXTION_COE_TABLE(Replica, Cxtion);
  8123. //
  8124. // There is no need to keep a timeout pending if there are no
  8125. // idle change orders. Otherwise, bump the timeout since we
  8126. // have received something from our partner.
  8127. //
  8128. // Note: Need better filter for commands that aren't ACKs.
  8129. //
  8130. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_TIMEOUT_SET)) {
  8131. //
  8132. // :SP1: Volatile connection cleanup.
  8133. //
  8134. // A volatile connection is used to seed sysvols after dcpromo.
  8135. // If there is inactivity on a volatile outbound connection for
  8136. // more than FRS_VOLATILE_CONNECTION_MAX_IDLE_TIME then this
  8137. // connection is unjoined. An unjoin on a volatile outbound
  8138. // connection triggers a delete on that connection. This is to
  8139. // prevent the case where staging files are kept for ever on the
  8140. // parent for a volatile connection.
  8141. //
  8142. WaitTime = (VOLATILE_OUTBOUND_CXTION(Cxtion) ?
  8143. FRS_VOLATILE_CONNECTION_MAX_IDLE_TIME :
  8144. CommTimeoutInMilliSeconds);
  8145. if (VOLATILE_OUTBOUND_CXTION(Cxtion)) {
  8146. WaitSubmit(Cxtion->CommTimeoutCmd, WaitTime, CMD_DELAYED_COMPLETE);
  8147. } else
  8148. if (NumWaitingCOs > 0) {
  8149. if (RsCoe(Cmd) != NULL) {
  8150. //
  8151. // Extend the timer since we still have outstanding
  8152. // change orders that need a response from our partner
  8153. // and the current comm packet is responding to one of
  8154. // those change orders.
  8155. //
  8156. WaitSubmit(Cxtion->CommTimeoutCmd, WaitTime, CMD_DELAYED_COMPLETE);
  8157. }
  8158. } else
  8159. if (Cmd->Command != CMD_START_JOIN) {
  8160. //
  8161. // Not volatile outbound and no COs in CoeTable waiting for
  8162. // a response so disable the cxtion timer... but
  8163. // CMD_START_JOIN's do not disable the join timer because
  8164. // they aren't sent in response to a request by this
  8165. // service. Disabling the timer might hang the service as
  8166. // it waits for a response that never comes and a timeout
  8167. // that never hits.
  8168. //
  8169. ClearCxtionFlag(Cxtion, CXTION_FLAGS_TIMEOUT_SET);
  8170. }
  8171. }
  8172. } else {
  8173. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_SUCCESS, "RcvFail - cxtion not found");
  8174. }
  8175. UNLOCK_CXTION_TABLE(Replica);
  8176. if (Cxtion != NULL) {
  8177. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_SUCCESS, "RcvSuccess");
  8178. }
  8179. } else {
  8180. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_SUCCESS, "RcvFail - no cxtion");
  8181. }
  8182. //
  8183. // Update the command with the replica pointer and the change order
  8184. // command with the local the replica number.
  8185. //
  8186. if (RsPartnerCoc(Cmd)) {
  8187. RsPartnerCoc(Cmd)->NewReplicaNum = ReplicaAddrToId(Replica);
  8188. //
  8189. // We will never see a remotely generated MOVERS. We always
  8190. // see a delete to the old RS followed by a create in the
  8191. // new RS. So set both replica ptrs to our Replica struct.
  8192. //
  8193. RsPartnerCoc(Cmd)->OriginalReplicaNum = ReplicaAddrToId(Replica);
  8194. }
  8195. RsReplica(Cmd) = Replica;
  8196. //
  8197. // Authentication info
  8198. //
  8199. RsAuthClient(Cmd) = FrsWcsDup(AuthClient);
  8200. RsAuthName(Cmd) = FrsWcsDup(AuthName);
  8201. RsAuthLevel(Cmd) = AuthLevel;
  8202. RsAuthN(Cmd) = AuthN;
  8203. RsAuthZ(Cmd) = AuthZ;
  8204. switch(Cmd->Command) {
  8205. case CMD_NEED_JOIN:
  8206. case CMD_START_JOIN:
  8207. case CMD_JOINED:
  8208. case CMD_JOINING:
  8209. case CMD_UNJOIN_REMOTE:
  8210. //
  8211. // Extract user sid
  8212. //
  8213. WStatus = UtilRpcServerHandleToAuthSidString(ServerHandle,
  8214. AuthClient,
  8215. &RsAuthSid(Cmd));
  8216. if (!WIN_SUCCESS(WStatus)) {
  8217. DPRINT1_WS(0, ":X: ERROR - UtilRpcServerHandleToAuthSidString(%ws);",
  8218. AuthClient, WStatus);
  8219. } else {
  8220. COMMAND_RCV_AUTH_TRACE(4,
  8221. CommPkt,
  8222. ERROR_SUCCESS,
  8223. AuthLevel,
  8224. AuthN,
  8225. AuthClient,
  8226. RsAuthSid(Cmd),
  8227. "RcvAuth - Sid");
  8228. }
  8229. break;
  8230. default:
  8231. break;
  8232. }
  8233. //
  8234. // Put the command on the replica's queue
  8235. //
  8236. Cmd->TargetQueue = Replica->Queue;
  8237. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  8238. return ERROR_SUCCESS;
  8239. }
  8240. VOID
  8241. RcsInitKnownReplicaSetMembers(
  8242. IN PCOMMAND_PACKET Cmd
  8243. )
  8244. /*++
  8245. Routine Description:
  8246. Wait for the database to be initialized and then take the
  8247. replicas that were retrieved from the database and put them
  8248. into the table that the replica control command server
  8249. uses. Open the replicas. The journal will be started when
  8250. a replica successfully joins with an outbound partner.
  8251. Arguments:
  8252. Cmd
  8253. Return Value:
  8254. winerror
  8255. --*/
  8256. {
  8257. #undef DEBSUB
  8258. #define DEBSUB "RcsInitKnownReplicaSetMembers:"
  8259. FILETIME FileTime;
  8260. ULONGLONG Now;
  8261. GUID Record0Guid;
  8262. PREPLICA Replica, NextReplica;
  8263. PVOID Key;
  8264. ULONG RootLen;
  8265. //
  8266. // Time in 100nsec tics since Jan 1, 1601
  8267. //
  8268. GetSystemTimeAsFileTime(&FileTime);
  8269. COPY_TIME(&Now, &FileTime);
  8270. //
  8271. // A non-empty table implies multiple calls to this
  8272. // routine our an out-of-sequence call to this routine.
  8273. //
  8274. FRS_ASSERT(GTabNumberInTable(ReplicasByGuid) == 0);
  8275. FRS_ASSERT(GTabNumberInTable(ReplicasByNumber) == 0);
  8276. //
  8277. // Wait for the database, journal, and comm subsystem to start up
  8278. //
  8279. WaitForSingleObject(CommEvent, INFINITE);
  8280. WaitForSingleObject(DataBaseEvent, INFINITE);
  8281. WaitForSingleObject(JournalEvent, INFINITE);
  8282. WaitForSingleObject(ChgOrdEvent, INFINITE);
  8283. if (FrsIsShuttingDown) {
  8284. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  8285. return;
  8286. }
  8287. //
  8288. // Delete the contents of the Replica Set key in the registry
  8289. // and refresh with the current info in the database.
  8290. //
  8291. RcsReplicaClearRegistry();
  8292. //
  8293. // The database built a list of replicas. Insert them into the tables
  8294. //
  8295. ForEachListEntry(&ReplicaListHead, REPLICA, ReplicaList,
  8296. // loop iterator pE is of type REPLICA
  8297. //
  8298. // Replica was opened as part of the database initialization
  8299. //
  8300. pE->IsOpen = TRUE;
  8301. REPLICA_STATE_TRACE(3, Cmd, pE, pE->IsOpen, "B, Replica opened");
  8302. //
  8303. // The timeout for the deleted replica has expired; attempt to
  8304. // delete the replica from the database. The delete will be
  8305. // retried at the next startup if this delete fails. In any case,
  8306. // the replica does not show up in the active set of replicas
  8307. // and so is ignored by all further processing except for shutdown.
  8308. //
  8309. if (RcsReplicaIsRestored(pE) ||
  8310. (!IS_TIME_ZERO(pE->MembershipExpires) && pE->MembershipExpires < Now)) {
  8311. GTabInsertEntry(DeletedReplicas, pE, pE->ReplicaName->Guid, NULL);
  8312. continue;
  8313. }
  8314. //
  8315. // Insert replica information into the registry
  8316. //
  8317. RcsReplicaSetRegistry(pE);
  8318. //
  8319. // Create a queue
  8320. //
  8321. pE->Queue = FrsAlloc(sizeof(FRS_QUEUE));
  8322. FrsInitializeQueue(pE->Queue, &ReplicaCmdServer.Control);
  8323. REPLICA_STATE_TRACE(3, Cmd, pE, 0, "F, Replica added to GUID table");
  8324. //
  8325. // Table by guid
  8326. //
  8327. GTabInsertEntry(ReplicasByGuid, pE, pE->ReplicaName->Guid, NULL);
  8328. //
  8329. // Add ReplicaSet Instance to the registry
  8330. //
  8331. if (pE->Root != NULL) {
  8332. DPRINT(5, ":S: PERFMON:Adding Set:REPLICA.C:2\n");
  8333. AddPerfmonInstance(REPLICASET, pE->PerfRepSetData, pE->Root);
  8334. }
  8335. //
  8336. // Table by number
  8337. //
  8338. GTabInsertEntry(ReplicasByNumber, pE, &pE->ReplicaNumber, NULL);
  8339. );
  8340. //
  8341. // Now account for the replica sets that are on the fault list.
  8342. //
  8343. ForEachListEntry(&ReplicaFaultListHead, REPLICA, ReplicaList,
  8344. // loop iterator pE is of type REPLICA
  8345. //
  8346. // Replica was opened as part of the database initialization
  8347. //
  8348. pE->IsOpen = FALSE;
  8349. REPLICA_STATE_TRACE(3, Cmd, pE, pE->IsOpen, "B, Replica not opened");
  8350. //
  8351. // The timeout for the deleted replica has expired; attempt to
  8352. // delete the replica from the database. The delete will be
  8353. // retried at the next startup if this delete fails. In any case,
  8354. // the replica does not show up in the active set of replicas
  8355. // and so is ignored by all further processing except for shutdown.
  8356. //
  8357. if (RcsReplicaIsRestored(pE) ||
  8358. (!IS_TIME_ZERO(pE->MembershipExpires) && pE->MembershipExpires < Now)) {
  8359. GTabInsertEntry(DeletedReplicas, pE, pE->ReplicaName->Guid, NULL);
  8360. continue;
  8361. }
  8362. //
  8363. // Insert replica information into the registry
  8364. //
  8365. RcsReplicaSetRegistry(pE);
  8366. //
  8367. // Create a queue
  8368. //
  8369. pE->Queue = FrsAlloc(sizeof(FRS_QUEUE));
  8370. FrsInitializeQueue(pE->Queue, &ReplicaCmdServer.Control);
  8371. REPLICA_STATE_TRACE(3, Cmd, pE, 0, "F, Replica added to GUID table");
  8372. //
  8373. // Table by guid
  8374. //
  8375. GTabInsertEntry(ReplicasByGuid, pE, pE->ReplicaName->Guid, NULL);
  8376. //
  8377. // Table by number
  8378. //
  8379. GTabInsertEntry(ReplicasByNumber, pE, &pE->ReplicaNumber, NULL);
  8380. );
  8381. //
  8382. // Set the registry value "FilesNotToBackup"
  8383. //
  8384. CfgFilesNotToBackup(ReplicasByGuid);
  8385. //
  8386. // Close the expired replica sets
  8387. //
  8388. Key = NULL;
  8389. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  8390. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  8391. //
  8392. // Close replica is OK here as long as the Journal has not been started
  8393. // on this replica set.
  8394. //
  8395. RcsCloseReplicaSetmember(Replica);
  8396. RcsCloseReplicaCxtions(Replica);
  8397. }
  8398. }
  8399. //
  8400. // Delete the replica sets with expired tombstones
  8401. //
  8402. Key = NULL;
  8403. for (Replica = GTabNextDatum(DeletedReplicas, &Key);
  8404. Replica;
  8405. Replica = NextReplica) {
  8406. NextReplica = GTabNextDatum(DeletedReplicas, &Key);
  8407. //
  8408. // Replica number 0 is reserved for the template tables in post
  8409. // WIN2K but Databases built with Win2K can still use replica
  8410. // number 0.
  8411. //
  8412. // Record 0 contains the DB templates. Don't delete it but
  8413. // change its fields so that it won't interfere with the
  8414. // creation of other replica set.
  8415. // Note: New databases will not use replica number zero but old
  8416. // databases will. To avoid name conflicts with replica sets
  8417. // created in the future we still need to overwrite a few
  8418. // fields in config record zero.
  8419. //
  8420. if (Replica->ReplicaNumber == DBS_TEMPLATE_TABLE_NUMBER) {
  8421. if (WSTR_NE(Replica->ReplicaName->Name, NTFRS_RECORD_0)) {
  8422. //
  8423. // Pull the entry out of the table since we are changing the
  8424. // replica guid below. (makes the saved guid ptr in the entry
  8425. // invalid and can lead to access violation).
  8426. //
  8427. GTabDelete(DeletedReplicas, Replica->ReplicaName->Guid, NULL, NULL);
  8428. FrsUuidCreate(&Record0Guid);
  8429. //
  8430. // ReplicaName
  8431. //
  8432. FrsFreeGName(Replica->ReplicaName);
  8433. Replica->ReplicaName = FrsBuildGName(FrsDupGuid(&Record0Guid),
  8434. FrsWcsDup(NTFRS_RECORD_0));
  8435. //
  8436. // MemberName
  8437. //
  8438. FrsFreeGName(Replica->MemberName);
  8439. Replica->MemberName = FrsBuildGName(FrsDupGuid(&Record0Guid),
  8440. FrsWcsDup(NTFRS_RECORD_0));
  8441. //
  8442. // SetName
  8443. //
  8444. FrsFreeGName(Replica->SetName);
  8445. Replica->SetName = FrsBuildGName(FrsDupGuid(&Record0Guid),
  8446. FrsWcsDup(NTFRS_RECORD_0));
  8447. //
  8448. // SetType
  8449. //
  8450. Replica->ReplicaSetType = FRS_RSTYPE_OTHER;
  8451. //
  8452. // Root (to avoid failing a replica create because of
  8453. // overlapping roots)
  8454. //
  8455. FrsFree(Replica->Root);
  8456. Replica->Root = FrsWcsDup(NTFRS_RECORD_0_ROOT);
  8457. //
  8458. // Stage (to avoid failing a replica create because of
  8459. // overlapping Stages)
  8460. //
  8461. FrsFree(Replica->Stage);
  8462. Replica->Stage = FrsWcsDup(NTFRS_RECORD_0_STAGE);
  8463. //
  8464. // Update
  8465. //
  8466. Replica->NeedsUpdate = TRUE;
  8467. RcsUpdateReplicaSetMember(Replica);
  8468. //
  8469. // The above friggen call set NeedsUpdate to false if the update succeeded.
  8470. //
  8471. if (Replica->NeedsUpdate) {
  8472. DPRINT(0, ":S: ERROR - Can't update record 0.\n");
  8473. }
  8474. //
  8475. // Insert the entry back into the table with the new Guid index.
  8476. //
  8477. GTabInsertEntry(DeletedReplicas,
  8478. Replica,
  8479. Replica->ReplicaName->Guid,
  8480. NULL);
  8481. }
  8482. RcsCloseReplicaSetmember(Replica);
  8483. RcsCloseReplicaCxtions(Replica);
  8484. } else {
  8485. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Deleting Tombstoned replica");
  8486. //
  8487. // Close replica is OK here as long as the Journal has not
  8488. // been started on this replica set.
  8489. //
  8490. RcsCloseReplicaSetmember(Replica);
  8491. RcsCloseReplicaCxtions(Replica);
  8492. RcsDeleteReplicaFromDb(Replica);
  8493. }
  8494. }
  8495. SetEvent(ReplicaEvent);
  8496. //
  8497. // Check the schedules every so often
  8498. //
  8499. Cmd->Command = CMD_CHECK_SCHEDULES;
  8500. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  8501. //
  8502. // Free up memory by reducing our working set size
  8503. //
  8504. SetProcessWorkingSetSize(ProcessHandle, (SIZE_T)-1, (SIZE_T)-1);
  8505. }
  8506. DWORD
  8507. RcsExitThread(
  8508. PFRS_THREAD FrsThread
  8509. )
  8510. /*++
  8511. Routine Description:
  8512. Immediate cancel of all outstanding RPC calls for the thread
  8513. identified by FrsThread. Set the tombstone to 5 seconds from
  8514. now. If this thread does not exit within that time, any calls
  8515. to ThSupWaitThread() will return a timeout error.
  8516. Arguments:
  8517. FrsThread
  8518. Return Value:
  8519. ERROR_SUCCESS
  8520. --*/
  8521. {
  8522. #undef DEBSUB
  8523. #define DEBSUB "RcsExitThread:"
  8524. ULONG WStatus;
  8525. if (HANDLE_IS_VALID(FrsThread->Handle)) {
  8526. DPRINT1(4, ":S: Canceling RPC requests for thread %ws\n", FrsThread->Name);
  8527. WStatus = RpcCancelThread(FrsThread->Handle);
  8528. if (!RPC_SUCCESS(WStatus)) {
  8529. DPRINT_WS(0, ":S: RpcCancelThread failed.", WStatus);
  8530. }
  8531. }
  8532. return ThSupExitWithTombstone(FrsThread);
  8533. }
  8534. #if _MSC_FULL_VER >= 13008827
  8535. #pragma warning(push)
  8536. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  8537. #endif
  8538. DWORD
  8539. RcsMain(
  8540. PVOID Arg
  8541. )
  8542. /*++
  8543. Routine Description:
  8544. Entry point for replica control command server thread
  8545. Arguments:
  8546. Arg - thread
  8547. Return Value:
  8548. None.
  8549. --*/
  8550. {
  8551. #undef DEBSUB
  8552. #define DEBSUB "RcsMain:"
  8553. PCOMMAND_PACKET Cmd;
  8554. PCOMMAND_SERVER Cs;
  8555. PFRS_QUEUE IdledQueue;
  8556. ULONG Status;
  8557. PFRS_THREAD FrsThread = (PFRS_THREAD)Arg;
  8558. FRS_ASSERT(FrsThread->Data == &ReplicaCmdServer);
  8559. //
  8560. // Immediate cancel of outstanding RPC calls during shutdown
  8561. //
  8562. RpcMgmtSetCancelTimeout(0);
  8563. FrsThread->Exit = RcsExitThread;
  8564. cant_exit_yet:
  8565. //
  8566. // Replica Control Command Server
  8567. // Controls access to the database entries
  8568. //
  8569. while (Cmd = FrsGetCommandServerIdled(&ReplicaCmdServer, &IdledQueue)) {
  8570. switch (Cmd->Command) {
  8571. //
  8572. // INITIALIZATION, STARTUP, AND CONFIGURATION
  8573. //
  8574. case CMD_INIT_SUBSYSTEM:
  8575. DPRINT(0, ":S: Replica subsystem is starting.\n");
  8576. DPRINT1(4, ":S: Command init subsystem %08x\n", Cmd);
  8577. RcsInitKnownReplicaSetMembers(Cmd);
  8578. if (!FrsIsShuttingDown) {
  8579. DPRINT(0, ":S: Replica subsystem has started.\n");
  8580. }
  8581. break;
  8582. case CMD_CHECK_SCHEDULES:
  8583. RcsCheckSchedules(Cmd);
  8584. break;
  8585. case CMD_START_REPLICAS:
  8586. RcsStartValidReplicaSetMembers(Cmd);
  8587. break;
  8588. case CMD_START:
  8589. RcsStartReplicaSetMember(Cmd);
  8590. break;
  8591. case CMD_DELETE:
  8592. RcsDeleteReplicaSetMember(Cmd);
  8593. break;
  8594. case CMD_DELETE_RETRY:
  8595. RcsDeleteReplicaRetry(Cmd);
  8596. break;
  8597. case CMD_DELETE_NOW:
  8598. RcsDeleteReplicaSetMemberNow(Cmd);
  8599. break;
  8600. //
  8601. // CHANGE ORDERS
  8602. //
  8603. case CMD_LOCAL_CO_ACCEPTED:
  8604. RcsLocalCoAccepted(Cmd);
  8605. break;
  8606. case CMD_REMOTE_CO:
  8607. RcsRemoteCoReceived(Cmd);
  8608. break;
  8609. case CMD_REMOTE_CO_ACCEPTED:
  8610. RcsRemoteCoAccepted(Cmd);
  8611. break;
  8612. case CMD_SEND_STAGE:
  8613. RcsSendStageFile(Cmd);
  8614. break;
  8615. case CMD_SENDING_STAGE:
  8616. RcsSendingStageFile(Cmd);
  8617. break;
  8618. case CMD_RECEIVING_STAGE:
  8619. RcsReceivingStageFile(Cmd);
  8620. break;
  8621. case CMD_CREATED_EXISTING:
  8622. RcsSendStageFileRequest(Cmd);
  8623. break;
  8624. case CMD_RECEIVED_STAGE:
  8625. RcsReceivedStageFile(Cmd, CHECK_CXTION_AUTH);
  8626. break;
  8627. case CMD_REMOTE_CO_DONE:
  8628. RcsRemoteCoDoneRvcd(Cmd);
  8629. break;
  8630. case CMD_SEND_ABORT_FETCH:
  8631. RcsSendAbortFetch(Cmd);
  8632. break;
  8633. case CMD_ABORT_FETCH:
  8634. RcsAbortFetch(Cmd);
  8635. break;
  8636. case CMD_SEND_RETRY_FETCH:
  8637. RcsSendRetryFetch(Cmd);
  8638. break;
  8639. case CMD_RETRY_STAGE:
  8640. RcsRetryStageFileCreate(Cmd);
  8641. break;
  8642. case CMD_RETRY_FETCH:
  8643. RcsRetryFetch(Cmd);
  8644. break;
  8645. //
  8646. // JOINING
  8647. //
  8648. case CMD_NEED_JOIN:
  8649. RcsNeedJoin(Cmd);
  8650. break;
  8651. case CMD_START_JOIN:
  8652. RcsStartJoin(Cmd);
  8653. break;
  8654. case CMD_JOIN_CXTION:
  8655. RcsJoinCxtion(Cmd);
  8656. break;
  8657. case CMD_JOINING_AFTER_FLUSH:
  8658. RcsJoiningAfterFlush(Cmd);
  8659. break;
  8660. case CMD_JOINING:
  8661. RcsJoining(Cmd);
  8662. break;
  8663. case CMD_JOINED:
  8664. RcsInboundJoined(Cmd);
  8665. break;
  8666. case CMD_UNJOIN:
  8667. RcsUnJoinCxtion(Cmd, FALSE);
  8668. break;
  8669. case CMD_UNJOIN_REMOTE:
  8670. RcsUnJoinCxtion(Cmd, TRUE);
  8671. break;
  8672. case CMD_HUNG_CXTION:
  8673. RcsHungCxtion(Cmd);
  8674. break;
  8675. //
  8676. // VVJOIN
  8677. //
  8678. case CMD_VVJOIN_SUCCESS:
  8679. RcsVvJoinSuccess(Cmd);
  8680. break;
  8681. case CMD_VVJOIN_DONE:
  8682. RcsVvJoinDone(Cmd);
  8683. break;
  8684. case CMD_VVJOIN_DONE_UNJOIN:
  8685. RcsVvJoinDoneUnJoin(Cmd);
  8686. break;
  8687. case CMD_CHECK_PROMOTION:
  8688. RcsCheckPromotion(Cmd);
  8689. break;
  8690. default:
  8691. DPRINT1(0, "Replica Control: unknown command 0x%x\n", Cmd->Command);
  8692. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  8693. break;
  8694. }
  8695. FrsRtlUnIdledQueue(IdledQueue);
  8696. }
  8697. //
  8698. // Exit
  8699. //
  8700. FrsExitCommandServer(&ReplicaCmdServer, FrsThread);
  8701. goto cant_exit_yet;
  8702. return ERROR_SUCCESS;
  8703. }
  8704. #if _MSC_FULL_VER >= 13008827
  8705. #pragma warning(pop)
  8706. #endif
  8707. VOID
  8708. RcsInitializeReplicaCmdServer(
  8709. VOID
  8710. )
  8711. /*++
  8712. Routine Description:
  8713. Initialize the replica set command server and idle it until the
  8714. database is initialized.
  8715. Arguments:
  8716. None.
  8717. Return Value:
  8718. None.
  8719. --*/
  8720. {
  8721. #undef DEBSUB
  8722. #define DEBSUB "RcsInitializeReplicaCmdServer:"
  8723. ULONG Status;
  8724. PCOMMAND_PACKET Cmd;
  8725. DWORD MaxRepThreads;
  8726. //
  8727. // Retry a join every MinJoinRetry milliseconds, doubling the interval
  8728. // every retry. Stop retrying when the interval is greater than
  8729. // MaxJoinRetry.
  8730. //
  8731. CfgRegReadDWord(FKC_MIN_JOIN_RETRY, NULL, 0, &MinJoinRetry);
  8732. DPRINT1(0, ":S: Min Join Retry : %d\n", MinJoinRetry);
  8733. CfgRegReadDWord(FKC_MAX_JOIN_RETRY, NULL, 0, &MaxJoinRetry);
  8734. DPRINT1(0, ":S: Max Join Retry : %d\n", MaxJoinRetry);
  8735. //
  8736. // The replica command server services commands for configuration changes
  8737. // and REPLICATION.
  8738. //
  8739. CfgRegReadDWord(FKC_MAX_REPLICA_THREADS, NULL, 0, &MaxRepThreads);
  8740. DPRINT1(0, ":S: Max Replica Threads : %d\n", MaxRepThreads);
  8741. //
  8742. // Start replication even if the DS could not be accessed
  8743. //
  8744. CfgRegReadDWord(FKC_REPLICA_START_TIMEOUT, NULL, 0, &ReplicaStartTimeout);
  8745. DPRINT1(0, ":S: Replica Start Timeout: %d\n", ReplicaStartTimeout);
  8746. //
  8747. // Partners are not allowed to join if their clocks are out-of-sync
  8748. //
  8749. CfgRegReadDWord(FKC_PARTNER_CLOCK_SKEW, NULL, 0, &PartnerClockSkew);
  8750. DPRINT1(0, ":S: Partner Clock Skew : %d\n", PartnerClockSkew);
  8751. MaxPartnerClockSkew = (ULONGLONG)PartnerClockSkew *
  8752. CONVERT_FILETIME_TO_MINUTES;
  8753. //
  8754. // Replica tombstone in days
  8755. //
  8756. CfgRegReadDWord(FKC_REPLICA_TOMBSTONE, NULL, 0, &ReplicaTombstone);
  8757. DPRINT1(0, ":S: Replica Tombstone : %d\n", ReplicaTombstone);
  8758. ReplicaTombstoneInFileTime = (ULONGLONG)ReplicaTombstone *
  8759. CONVERT_FILETIME_TO_DAYS;
  8760. //
  8761. // Start the Replica command server
  8762. //
  8763. FrsInitializeCommandServer(&ReplicaCmdServer, MaxRepThreads, L"ReplicaCs", RcsMain);
  8764. //
  8765. // Empty table of replicas. Existing replicas will be filled in after
  8766. // the database has started up.
  8767. //
  8768. DeletedReplicas = GTabAllocTable();
  8769. DeletedCxtions = GTabAllocTable();
  8770. ReplicasByNumber = GTabAllocNumberTable();
  8771. //
  8772. // Tell the replica command server to init.
  8773. //
  8774. Cmd = FrsAllocCommand(&ReplicaCmdServer.Queue, CMD_INIT_SUBSYSTEM);
  8775. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  8776. //
  8777. // The DS may have changed while the service was down. In fact, the
  8778. // service may have been down because the DS was being changed. The
  8779. // current state of the configuration in the DS should be merged
  8780. // with the state in the database before replication begins. But
  8781. // the DS may not be reachable. We don't want to delay replication
  8782. // in the off chance that the DS changed, but we do want to pick
  8783. // up any changes before replication begins. Our compromise is to
  8784. // allow a few minutes for the DS to come online and then start
  8785. // replication anyway.
  8786. //
  8787. if (ReplicaStartTimeout) {
  8788. Cmd = FrsAllocCommand(&ReplicaCmdServer.Queue, CMD_START_REPLICAS);
  8789. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, ReplicaStartTimeout);
  8790. }
  8791. }
  8792. VOID
  8793. RcsFrsUnInitializeReplicaCmdServer(
  8794. VOID
  8795. )
  8796. /*++
  8797. Routine Description:
  8798. Free up the RCS memory.
  8799. Arguments:
  8800. None.
  8801. Return Value:
  8802. None.
  8803. --*/
  8804. {
  8805. #undef DEBSUB
  8806. #define DEBSUB "RcsFrsUnInitializeReplicaCmdServer:"
  8807. GTabFreeTable(ReplicasByNumber, NULL);
  8808. GTabFreeTable(ReplicasByGuid, FrsFreeType);
  8809. GTabFreeTable(DeletedReplicas, FrsFreeType);
  8810. GTabFreeTable(DeletedCxtions, FrsFreeType);
  8811. }
  8812. VOID
  8813. RcsShutDownReplicaCmdServer(
  8814. VOID
  8815. )
  8816. /*++
  8817. Routine Description:
  8818. Abort the replica control command server
  8819. Arguments:
  8820. None.
  8821. Return Value:
  8822. None.
  8823. --*/
  8824. {
  8825. #undef DEBSUB
  8826. #define DEBSUB "RcsShutDownReplicaCmdServer:"
  8827. PVOID Key;
  8828. PVOID SubKey;
  8829. PREPLICA Replica;
  8830. PCXTION Cxtion;
  8831. //
  8832. // Rundown all known queues. New queue entries will bounce.
  8833. //
  8834. Key = NULL;
  8835. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  8836. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Rundown replica cmd srv");
  8837. FrsRunDownCommandServer(&ReplicaCmdServer, Replica->Queue);
  8838. SubKey = NULL;
  8839. while (Cxtion = GTabNextDatum(Replica->Cxtions, &SubKey)) {
  8840. if (Cxtion->VvJoinCs) {
  8841. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Rundown replica VVJoin srv");
  8842. FrsRunDownCommandServer(Cxtion->VvJoinCs, &Cxtion->VvJoinCs->Queue);
  8843. }
  8844. }
  8845. }
  8846. FrsRunDownCommandServer(&ReplicaCmdServer, &ReplicaCmdServer.Queue);
  8847. }
  8848. VOID
  8849. RcsCmdPktCompletionRoutine(
  8850. IN PCOMMAND_PACKET Cmd,
  8851. IN PVOID Arg
  8852. )
  8853. /*++
  8854. Routine Description:
  8855. Completion routine for Replica. Free the replica set info
  8856. and send the command on to the generic command packet
  8857. completion routine for freeing.
  8858. Arguments:
  8859. Cmd
  8860. Arg - Cmd->CompletionArg
  8861. Return Value:
  8862. None.
  8863. --*/
  8864. {
  8865. #undef DEBSUB
  8866. #define DEBSUB "RcsCmdPktCompletionRoutine:"
  8867. PCHANGE_ORDER_ENTRY Coe;
  8868. DPRINT1(5, "Replica completion %08x\n", Cmd);
  8869. //
  8870. // To preserve order among change orders all subsequent change orders
  8871. // from this connection are going to the Inbound log (as a consequence
  8872. // of the Unjoin below). We will retry them later when the connection
  8873. // is restarted.
  8874. //
  8875. if (RsCoe(Cmd)) {
  8876. Coe = RsCoe(Cmd);
  8877. RsCoe(Cmd) = NULL;
  8878. //
  8879. // Unjoin if possible
  8880. // The unjoin will fail if there isn't a cxtion or
  8881. // the join guid is out-of-date. Which is what we
  8882. // want -- we don't want a lot of unjoins flooding
  8883. // the replica queue and wrecking havoc with future
  8884. // joins.
  8885. //
  8886. // WARN: Must happen before the call to ChgOrdInboundRetry below.
  8887. //
  8888. if (RsReplica(Cmd)) {
  8889. CHANGE_ORDER_TRACE(3, Coe, "Retry/Unjoin");
  8890. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  8891. Cmd = NULL;
  8892. }
  8893. //
  8894. // Retry the change order. This must happen *AFTER* issueing
  8895. // the unjoin above so that any change orders kicked loose by
  8896. // the following retry will be pushed into the retry path because
  8897. // their join guid will be invalidated during the unjoin.
  8898. //
  8899. SET_COE_FLAG(Coe, COE_FLAG_NO_INBOUND);
  8900. if (CO_STATE_IS_LE(Coe, IBCO_STAGING_RETRY)) {
  8901. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to staging retry");
  8902. ChgOrdInboundRetry(Coe, IBCO_STAGING_RETRY);
  8903. } else
  8904. if (CO_STATE_IS_LE(Coe, IBCO_FETCH_RETRY)) {
  8905. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to fetch retry");
  8906. ChgOrdInboundRetry(Coe, IBCO_FETCH_RETRY);
  8907. } else
  8908. if (CO_STATE_IS_LE(Coe, IBCO_INSTALL_RETRY)) {
  8909. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to install retry");
  8910. ChgOrdInboundRetry(Coe, IBCO_INSTALL_RETRY);
  8911. } else {
  8912. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to retry");
  8913. ChgOrdInboundRetry(Coe, CO_STATE(Coe));
  8914. }
  8915. //
  8916. // Command was transfered to the replica command server for unjoin
  8917. //
  8918. if (!Cmd) {
  8919. return;
  8920. }
  8921. }
  8922. //
  8923. // The originator owns the disposition of this command packet
  8924. //
  8925. if (HANDLE_IS_VALID(RsCompletionEvent(Cmd))) {
  8926. SetEvent(RsCompletionEvent(Cmd));
  8927. return;
  8928. }
  8929. //
  8930. // Free up the "address" portion of the command
  8931. //
  8932. FrsFreeGName(RsTo(Cmd));
  8933. FrsFreeGName(RsFrom(Cmd));
  8934. FrsFreeGName(RsReplicaName(Cmd));
  8935. FrsFreeGName(RsCxtion(Cmd));
  8936. FrsFree(RsBlock(Cmd));
  8937. FrsFree(RsGVsn(Cmd));
  8938. FrsFree(RsCoGuid(Cmd));
  8939. FrsFree(RsJoinGuid(Cmd));
  8940. FrsFree(RsJoinTime(Cmd));
  8941. FrsFree(RsReplicaVersionGuid(Cmd));
  8942. //
  8943. // Free the copy of our partner's change order command and the data extension.
  8944. //
  8945. if (RsPartnerCoc(Cmd) != NULL) {
  8946. FrsFree(RsPartnerCocExt(Cmd));
  8947. FrsFree(RsPartnerCoc(Cmd));
  8948. }
  8949. //
  8950. // a replica (never free the RsReplica(Cmd) field; it addresses
  8951. // an active replica in the Replicas table).
  8952. //
  8953. FrsFreeType(RsNewReplica(Cmd));
  8954. //
  8955. // Seeding cxtion
  8956. // Delete the connection from the perfmon tables.
  8957. //
  8958. if (RsNewCxtion(Cmd) != NULL) {
  8959. FrsFreeType(RsNewCxtion(Cmd));
  8960. }
  8961. //
  8962. // Free the compression table, if any.
  8963. //
  8964. if (RsCompressionTable(Cmd)) {
  8965. GTabFreeTable(RsCompressionTable(Cmd), FrsFree);
  8966. }
  8967. //
  8968. // Free the version vector, if any
  8969. //
  8970. RsVVector(Cmd) = VVFreeOutbound(RsVVector(Cmd));
  8971. RsReplicaVv(Cmd) = VVFreeOutbound(RsReplicaVv(Cmd));
  8972. //
  8973. // Authentication info
  8974. //
  8975. FrsFree(RsAuthClient(Cmd));
  8976. FrsFree(RsAuthName(Cmd));
  8977. FrsFree(RsAuthSid(Cmd));
  8978. //
  8979. // Md5 Digest
  8980. //
  8981. FrsFree(RsMd5Digest(Cmd));
  8982. //
  8983. // Send the packet on to the generic completion routine for freeing
  8984. //
  8985. FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL);
  8986. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  8987. }
  8988. VOID
  8989. RcsSubmitTransferToRcs(
  8990. IN PCOMMAND_PACKET Cmd,
  8991. IN USHORT Command
  8992. )
  8993. /*++
  8994. Routine Description:
  8995. Transfer a request to the replica command server
  8996. Arguments:
  8997. Cmd
  8998. Command
  8999. Return Value:
  9000. None.
  9001. --*/
  9002. {
  9003. #undef DEBSUB
  9004. #define DEBSUB "RcsSubmitTransferToRcs:"
  9005. Cmd->TargetQueue = RsReplica(Cmd)->Queue;
  9006. Cmd->Command = Command;
  9007. RsTimeout(Cmd) = 0;
  9008. DPRINT3(5, "Transfer %08x (%08x) to %ws\n",
  9009. Command, Cmd, RsReplica(Cmd)->SetName->Name);
  9010. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  9011. }
  9012. VOID
  9013. RcsSubmitRemoteCoInstallRetry(
  9014. IN PCHANGE_ORDER_ENTRY Coe
  9015. )
  9016. /*++
  9017. Routine Description:
  9018. Submit a remote change order to retry the file install.
  9019. Arguments:
  9020. Coe - Change order entry.
  9021. Return Value:
  9022. None.
  9023. --*/
  9024. {
  9025. #undef DEBSUB
  9026. #define DEBSUB "RcsSubmitRemoteCoInstallRetry:"
  9027. PCOMMAND_PACKET Cmd;
  9028. PREPLICA Replica;
  9029. Replica = Coe->NewReplica;
  9030. Cmd = FrsAllocCommand(Replica->Queue, 0);
  9031. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  9032. //
  9033. // Address of change order entry
  9034. //
  9035. RsCoe(Cmd) = Coe;
  9036. //
  9037. // Mask out the irrelevant usn reasons
  9038. //
  9039. RsCoc(Cmd)->ContentCmd &= CO_CONTENT_MASK;
  9040. //
  9041. // Guid of the change order entry
  9042. //
  9043. RsCoGuid(Cmd) = FrsDupGuid(&RsCoc(Cmd)->ChangeOrderGuid);
  9044. //
  9045. // Initialize the command packet for eventual transfer to
  9046. // the replica set command server
  9047. //
  9048. RsReplica(Cmd) = Replica;
  9049. //
  9050. // Cxtion's guid (note - we lose the printable name for now)
  9051. //
  9052. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coe->Cmd.CxtionGuid), NULL);
  9053. DPRINT3(5, "Submit %08x (%08x) to %ws\n",
  9054. CMD_REMOTE_CO_ACCEPTED, Cmd, Replica->SetName->Name);
  9055. FrsInstallCsSubmitTransfer(Cmd, CMD_INSTALL_STAGE);
  9056. }
  9057. VOID
  9058. RcsSubmitRemoteCoAccepted(
  9059. IN PCHANGE_ORDER_ENTRY Coe
  9060. )
  9061. /*++
  9062. Routine Description:
  9063. Submit a remote change order to the staging file generator.
  9064. Arguments:
  9065. Co
  9066. Return Value:
  9067. None.
  9068. --*/
  9069. {
  9070. #undef DEBSUB
  9071. #define DEBSUB "RcsSubmitRemoteCoAccepted:"
  9072. PCOMMAND_PACKET Cmd;
  9073. PREPLICA Replica;
  9074. Replica = Coe->NewReplica;
  9075. Cmd = FrsAllocCommand(Replica->Queue, CMD_REMOTE_CO_ACCEPTED);
  9076. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  9077. //
  9078. // Address of change order entry
  9079. //
  9080. RsCoe(Cmd) = Coe;
  9081. //
  9082. // Mask out the irrelevant usn reasons
  9083. //
  9084. RsCoc(Cmd)->ContentCmd &= CO_CONTENT_MASK;
  9085. //
  9086. // Guid of the change order entry
  9087. //
  9088. RsCoGuid(Cmd) = FrsDupGuid(&RsCoc(Cmd)->ChangeOrderGuid);
  9089. //
  9090. // Initialize the command packet for eventual transfer to
  9091. // the replica set command server
  9092. //
  9093. RsReplica(Cmd) = Replica;
  9094. //
  9095. // Cxtion's guid (note - we lose the printable name for now)
  9096. //
  9097. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coe->Cmd.CxtionGuid), NULL);
  9098. //
  9099. // Join guid
  9100. //
  9101. RsJoinGuid(Cmd) = FrsDupGuid(&Coe->JoinGuid);
  9102. DPRINT1(5, "Submit %08x\n", Cmd);
  9103. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  9104. }
  9105. VOID
  9106. RcsSubmitLocalCoAccepted(
  9107. IN PCHANGE_ORDER_ENTRY Coe
  9108. )
  9109. /*++
  9110. Routine Description:
  9111. Submit a local change order to the staging file generator.
  9112. Arguments:
  9113. Coe
  9114. Return Value:
  9115. None.
  9116. --*/
  9117. {
  9118. #undef DEBSUB
  9119. #define DEBSUB "RcsSubmitLocalCoAccepted:"
  9120. PCOMMAND_PACKET Cmd;
  9121. PREPLICA Replica;
  9122. //
  9123. // NewReplica?
  9124. //
  9125. Replica = Coe->NewReplica;
  9126. Cmd = FrsAllocCommand(Replica->Queue, CMD_LOCAL_CO_ACCEPTED);
  9127. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  9128. //
  9129. // Address of the change order entry
  9130. //
  9131. RsCoe(Cmd) = Coe;
  9132. //
  9133. // Mask out the irrelevant usn reasons
  9134. //
  9135. RsCoc(Cmd)->ContentCmd &= CO_CONTENT_MASK;
  9136. //
  9137. // Guid of the change order entry
  9138. //
  9139. RsCoGuid(Cmd) = FrsDupGuid(&RsCoc(Cmd)->ChangeOrderGuid);
  9140. //
  9141. // Initialize the command packet for eventual transfer to
  9142. // the replica set command server
  9143. //
  9144. RsReplica(Cmd) = Replica;
  9145. //
  9146. // Cxtion's guid (note - we lose the printable name for now)
  9147. //
  9148. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coe->Cmd.CxtionGuid), NULL);
  9149. DPRINT1(5, "Submit %08x\n", Cmd);
  9150. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  9151. }
  9152. ULONG
  9153. RcsSubmitCommPktWithErrorToRcs(
  9154. IN PCOMM_PACKET CommPkt
  9155. )
  9156. /*++
  9157. Routine Description:
  9158. A comm packet could not be sent because of an error. If the
  9159. comm packet was for a joined cxtion then the affected
  9160. replica\cxtion is unjoined.
  9161. Arguments:
  9162. CommPkt - Comm packet that couldn't be sent
  9163. Return Value:
  9164. Error status to be propagated to the sender
  9165. --*/
  9166. {
  9167. #undef DEBSUB
  9168. #define DEBSUB "RcsSubmitCommPktWithErrorToRcs:"
  9169. PCOMMAND_PACKET Cmd;
  9170. PREPLICA Replica;
  9171. PGNAME TmpGName;
  9172. //
  9173. // Convert the comm packet into a command packet
  9174. //
  9175. Cmd = CommPktToCmd(CommPkt);
  9176. FRS_ASSERT(Cmd != NULL);
  9177. FRS_ASSERT(RsTo(Cmd));
  9178. FRS_ASSERT(RsFrom(Cmd));
  9179. FRS_ASSERT(RsReplicaName(Cmd));
  9180. //
  9181. // Rebuild the replica name to address the originating, or local, replica
  9182. //
  9183. TmpGName = RsReplicaName(Cmd);
  9184. RsReplicaName(Cmd) = FrsBuildGName(FrsDupGuid(RsFrom(Cmd)->Guid),
  9185. FrsWcsDup(RsReplicaName(Cmd)->Name));
  9186. FrsFreeGName(TmpGName);
  9187. //
  9188. // Adjust the "to" and "from" addresses
  9189. //
  9190. TmpGName = RsTo(Cmd);
  9191. RsTo(Cmd) = RsFrom(Cmd);
  9192. RsFrom(Cmd) = TmpGName;
  9193. //
  9194. // Find the target replica
  9195. //
  9196. Replica = GTabLookup(ReplicasByGuid, RsReplicaName(Cmd)->Guid, NULL);
  9197. if (Replica == NULL) {
  9198. DPRINT1(4, ":S: WARN - Submit comm pkt w/error: Replica not found: %ws\n",
  9199. RsReplicaName(Cmd)->Name);
  9200. FrsCompleteCommand(Cmd, ERROR_FILE_NOT_FOUND);
  9201. return ERROR_FILE_NOT_FOUND;
  9202. }
  9203. RsReplica(Cmd) = Replica;
  9204. //
  9205. // The target replica may not be accepting comm packets. The
  9206. // target replica will reset itself before accepting
  9207. // commpkts again.
  9208. //
  9209. if (!Replica->IsAccepting) {
  9210. DPRINT1(4, ":S: WARN - Submit comm pkt w/error: Replica is not accepting: %ws\n",
  9211. Replica->ReplicaName->Name);
  9212. FrsCompleteCommand(Cmd, ERROR_RETRY);
  9213. return ERROR_RETRY;
  9214. }
  9215. switch (Cmd->Command) {
  9216. //
  9217. // NEVER SENT VIA A COMM PKT
  9218. //
  9219. case CMD_INIT_SUBSYSTEM:
  9220. case CMD_CHECK_SCHEDULES:
  9221. case CMD_START_REPLICAS:
  9222. // case CMD_STOP:
  9223. case CMD_START:
  9224. case CMD_DELETE:
  9225. case CMD_DELETE_NOW:
  9226. case CMD_LOCAL_CO_ACCEPTED:
  9227. case CMD_REMOTE_CO_ACCEPTED:
  9228. case CMD_SENDING_STAGE:
  9229. case CMD_RECEIVED_STAGE:
  9230. case CMD_CREATED_EXISTING:
  9231. case CMD_SEND_ABORT_FETCH:
  9232. case CMD_SEND_RETRY_FETCH:
  9233. case CMD_JOIN_CXTION:
  9234. case CMD_UNJOIN:
  9235. case CMD_VVJOIN_START:
  9236. case CMD_VVJOIN_SUCCESS:
  9237. case CMD_HUNG_CXTION:
  9238. case CMD_JOINING_AFTER_FLUSH:
  9239. FRS_ASSERT(!"RcsSubmitCommPktWithErrorToRcs: invalid cmd for comm pkt");
  9240. break;
  9241. //
  9242. // There is other retry code in replica.c that will take care of these
  9243. //
  9244. case CMD_UNJOIN_REMOTE:
  9245. case CMD_JOINED:
  9246. case CMD_NEED_JOIN:
  9247. case CMD_START_JOIN:
  9248. DPRINT3(5, ":X: Ignore commpkt with error Command:%08x Cmd:%08x CommPkt:%08x\n",
  9249. Cmd->Command, Cmd, CommPkt);
  9250. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  9251. break;
  9252. //
  9253. // SENT VIA COMM PKT; UNJOIN
  9254. //
  9255. case CMD_JOINING:
  9256. case CMD_REMOTE_CO:
  9257. case CMD_SEND_STAGE:
  9258. case CMD_RECEIVING_STAGE:
  9259. case CMD_REMOTE_CO_DONE:
  9260. case CMD_ABORT_FETCH:
  9261. case CMD_RETRY_FETCH:
  9262. case CMD_VVJOIN_DONE:
  9263. //
  9264. // Put the unjoin command on the replica's queue
  9265. //
  9266. DPRINT3(5, ":X: Submit commpkt with error Command:%08x Cmd:%08x CommPkt:%08x\n",
  9267. Cmd->Command, Cmd, CommPkt);
  9268. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  9269. break;
  9270. default:
  9271. break;
  9272. }
  9273. return ERROR_SUCCESS;
  9274. }