Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
14 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsFolder.cxx
  6. //
  7. // Contents: implements the base DFS Folder class
  8. //
  9. // Classes: DfsFolder.
  10. //
  11. // History: Dec. 8 2000, Author: udayh
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include "DfsFolder.hxx"
  15. #include "DfsFolderReferralData.hxx"
  16. #include "DfsInit.hxx"
  17. //
  18. // logging specific includes
  19. //
  20. #include "DfsFolder.tmh"
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Function: GetReferralData - get the referral data
  24. //
  25. // Arguments: ppReferralData - the referral data for this folder
  26. // pCacheHit - did we find it already loaded?
  27. //
  28. // Returns: Status
  29. // ERROR_SUCCESS if we could get the referral data
  30. // error status otherwise.
  31. //
  32. //
  33. // Description: This routine returns a reference DfsFolderReferralDAta
  34. // for the folder. If one does not already exist in this
  35. // folder, we create a new one. If someone is in the process
  36. // of loading the referral, we wait on the event in
  37. // the referral data which gets signalled when the thread
  38. // responsible for loading is done with the load.
  39. //
  40. //--------------------------------------------------------------------------
  41. DFSSTATUS
  42. DfsFolder::GetReferralData(
  43. OUT DfsFolderReferralData **ppReferralData,
  44. OUT BOOLEAN *pCacheHit,
  45. IN BOOLEAN AddToLoadedList )
  46. {
  47. DfsFolderReferralData *pRefData;
  48. DFSSTATUS Status = STATUS_SUCCESS;
  49. *pCacheHit = FALSE;
  50. Status = AcquireWriteLock();
  51. if ( Status != STATUS_SUCCESS )
  52. {
  53. return Status;
  54. }
  55. // First see if we may need to do a reload.
  56. if (_LoadState == DfsFolderLoadFailed &&
  57. IsTimeToRetry())
  58. {
  59. ASSERT(_pReferralData == NULL);
  60. _LoadState = DfsFolderNotLoaded;
  61. DFS_TRACE_HIGH(REFERRAL_SERVER, "Retrying failed folder load for %wZ (%wZ)\n",
  62. GetFolderMetadataName(),
  63. GetFolderLogicalName());
  64. }
  65. //
  66. // WE take difference action depending on the load state.
  67. //
  68. switch ( _LoadState )
  69. {
  70. case DfsFolderLoaded:
  71. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: Cache hit\n");
  72. //
  73. // we are dealing with a loaded folder. Just acquire a reference
  74. // and return the loaded referral data.
  75. //
  76. ASSERT (_pReferralData != NULL);
  77. pRefData = _pReferralData;
  78. pRefData->Timeout = _Timeout;
  79. pRefData->AcquireReference();
  80. ReleaseLock();
  81. *pCacheHit = TRUE;
  82. *ppReferralData = pRefData;
  83. break;
  84. case DfsFolderNotLoaded:
  85. //
  86. // The folder is not loaded. Make sure that the referral data is
  87. // indeed empty. Create a new instance of the referral data
  88. // and set the state to load in progress.
  89. // The create reference of the folder referral data is inherited
  90. // by the folder. (we are holding a reference to the referral
  91. // data in _pReferralData). This reference is released when
  92. // we RemoveReferralData at a later point.
  93. //
  94. ASSERT(_pReferralData == NULL);
  95. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: not loaded\n");
  96. _pReferralData = new DfsFolderReferralData( &Status,
  97. this );
  98. if ( _pReferralData != NULL )
  99. {
  100. if(Status == ERROR_SUCCESS)
  101. {
  102. _LoadState = DfsFolderLoadInProgress;
  103. if (IsFolderRoot() == TRUE)
  104. {
  105. _pReferralData->SetRootReferral();
  106. }
  107. if (IsFolderInSiteReferrals() ||
  108. ((_pParent != NULL) && (_pParent->IsFolderInSiteReferrals())))
  109. {
  110. _pReferralData->SetInSite();
  111. }
  112. //
  113. // Site costing is inherited from the parent.
  114. //
  115. if (IsFolderSiteCostingEnabled() ||
  116. ((_pParent != NULL) && (_pParent->IsFolderSiteCostingEnabled())))
  117. {
  118. _pReferralData->SetSiteCosting();
  119. }
  120. if (IsFolderOutOfDomain())
  121. {
  122. _pReferralData->SetOutOfDomain();
  123. }
  124. _pReferralData->Timeout = _Timeout;
  125. pRefData = _pReferralData;
  126. }
  127. else
  128. {
  129. _pReferralData->ReleaseReference();
  130. _pReferralData = NULL;
  131. }
  132. } else
  133. {
  134. Status = ERROR_NOT_ENOUGH_MEMORY;
  135. }
  136. //
  137. // We no longer need the lock. We have allocate the referral
  138. // data and marked the state accordingly. No other thread can
  139. // interfere with our load now.
  140. //
  141. ReleaseLock();
  142. //
  143. // Now we load the referral data, and save the status of the
  144. // load in both our load status as well as the load status
  145. // in the referral data.
  146. // If the load was successful, we add this to the loaded list
  147. // of referral data that can be scavenged later. We set the load
  148. // state to loaded, and signal the event so that all waiting
  149. // threads can now be woken up.
  150. //
  151. if ( Status == ERROR_SUCCESS )
  152. {
  153. DFS_TRACE_NORM(REFERRAL_SERVER, " Load called on link %wZ (%wZ)\n",
  154. GetFolderMetadataName(),
  155. GetFolderLogicalName());
  156. //
  157. // We depend on _pReferralData being non-null although
  158. // we aren't holding the folder lock still.
  159. //
  160. _pReferralData->FolderOffLine = IsFolderOffline();
  161. Status = LoadReferralData( _pReferralData);
  162. if(IsFolderOffline())
  163. {
  164. DFS_TRACE_NORM(REFERRAL_SERVER, "Link %wZ (%wZ) is OFFLINE\n",
  165. GetFolderMetadataName(),
  166. GetFolderLogicalName());
  167. }
  168. _LoadStatus = Status;
  169. _pReferralData->LoadStatus = Status;
  170. if ( Status == ERROR_SUCCESS )
  171. {
  172. //
  173. // Acquire a reference on the new referral data, since we
  174. // have to return a referenced referral data to the caller.
  175. // Get the reference here before we add it to the loaded list,
  176. // otherwise we could end up with the referral data
  177. // being freed up.
  178. //
  179. pRefData->AcquireReference();
  180. _LoadState = DfsFolderLoaded;
  181. _RetryFailedLoadTimeout = 0;
  182. if (AddToLoadedList == TRUE)
  183. {
  184. DfsAddReferralDataToLoadedList( _pReferralData );
  185. }
  186. *ppReferralData = pRefData;
  187. pRefData->Signal();
  188. }
  189. else
  190. {
  191. DFSSTATUS RemoveStatus;
  192. _LoadState = DfsFolderLoadFailed;
  193. // We'll try reloading this at some other time
  194. _RetryFailedLoadTimeout = GetTickCount();
  195. pRefData->Signal();
  196. RemoveStatus = RemoveReferralData(pRefData, NULL);
  197. DFS_TRACE_ERROR_HIGH(_LoadStatus, REFERRAL_SERVER,
  198. "Replica load failed for %wZ (%wZ), load status %x\n",
  199. GetFolderMetadataName(),
  200. GetFolderLogicalName(),
  201. _LoadStatus);
  202. }
  203. }
  204. break;
  205. case DfsFolderLoadInProgress:
  206. //
  207. // The load is in progress. We acquire a reference on the
  208. // referral data being loaded and wait for the event in the
  209. // referral data to be signalled. The return status of the wait
  210. // indicates if we can return the referral data or we fail
  211. // this request with an error.
  212. //
  213. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: load in progress\n");
  214. ASSERT(_pReferralData != NULL);
  215. pRefData = _pReferralData;
  216. pRefData->AcquireReference();
  217. ReleaseLock();
  218. DFSLOG("Thread: Waiting fod ..r referral load\n");
  219. Status = pRefData->Wait();
  220. if ( Status == ERROR_SUCCESS )
  221. {
  222. *ppReferralData = pRefData;
  223. } else
  224. {
  225. pRefData->ReleaseReference();
  226. }
  227. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: load in progress done\n");
  228. break;
  229. case DfsFolderLoadFailed:
  230. //
  231. // The Load failed. REturn error. We've already setup a time
  232. // after which we'll reattempt the load.
  233. //
  234. ASSERT(_pReferralData == NULL);
  235. Status = _LoadStatus;
  236. ReleaseLock();
  237. *ppReferralData = NULL;
  238. break;
  239. default:
  240. //
  241. // We should never get here. Its an invalid state.
  242. //
  243. ASSERT(TRUE);
  244. Status = ERROR_INVALID_STATE;
  245. ReleaseLock();
  246. break;
  247. }
  248. ASSERT((Status != ERROR_SUCCESS) || (*ppReferralData != NULL));
  249. return Status;
  250. }
  251. //+-------------------------------------------------------------------------
  252. //
  253. // Function: RemoveReferralData - remove the referral data from folder
  254. //
  255. // Arguments: NONE
  256. //
  257. // Returns: Status
  258. // ERROR_SUCCESS if we could remove the referral data
  259. // error status otherwise.
  260. //
  261. //
  262. // Description: This routine removes the cached reference to the loaded
  263. // referral data in the folder, and releases its reference
  264. // on it.
  265. // This causes all future GetREferralDAta to be loaded
  266. // back from the store.
  267. //
  268. //--------------------------------------------------------------------------
  269. DFSSTATUS
  270. DfsFolder::RemoveReferralData(
  271. DfsFolderReferralData *pRemoveReferralData,
  272. PBOOLEAN pRemoved )
  273. {
  274. DFSSTATUS Status = ERROR_SUCCESS;
  275. DfsFolderReferralData *pRefData = NULL;
  276. //
  277. // Get tnhe exclusive lock on the folder
  278. //
  279. if (pRemoved != NULL)
  280. {
  281. *pRemoved = FALSE;
  282. }
  283. AcquireWriteLock();
  284. if ( (pRemoveReferralData == NULL) ||
  285. (pRemoveReferralData == _pReferralData) )
  286. {
  287. //
  288. // BUG 773319 : There's a race between the worker thread
  289. // trying to sync and purge referral data in UpdateLinkFolder
  290. // and referrals trying to load referral data in GetReferralData.
  291. // GetReferralData drops the folder-lock with the understanding that
  292. // others will honor the DfsFolderLoadInProgress flag.
  293. //
  294. if (_LoadState == DfsFolderLoadInProgress)
  295. {
  296. pRefData = _pReferralData;
  297. ASSERT(pRefData != NULL);
  298. pRefData->AcquireReference();
  299. ReleaseLock();
  300. DFS_TRACE_NORM(REFERRAL_SERVER,
  301. "ReplicaData load in progress for Link %wZ (%wZ). Waiting\n",
  302. GetFolderMetadataName(),
  303. GetFolderLogicalName());
  304. //
  305. // We wait here because we don't want to lose our race to the thread
  306. // that did LoadReferralData. The sync-thread would've already created
  307. // folders based on what was in cache at one point. What's about to
  308. // get loaded may be inconsistent with respect to the linkfolder data.
  309. //
  310. (VOID)pRefData->Wait();
  311. // Release the reference we took above.
  312. pRefData->ReleaseReference();
  313. pRefData = NULL;
  314. AcquireWriteLock();
  315. };
  316. //
  317. // There are only two states that LoadInProgress transition to: Loaded and LoadFailed.
  318. // If we are in any other state then we are done because some other thread must have
  319. // beaten us to it.
  320. //
  321. // Also, don't change the LoadFailed status here. There's a separate timer ticking on
  322. // on that transition.
  323. //
  324. if (_LoadState == DfsFolderLoaded || _LoadState == DfsFolderLoadFailed)
  325. {
  326. // Don't take another reference here. We want to deref its original reference
  327. // to get rid of it (see below).
  328. pRefData = _pReferralData;
  329. _pReferralData = NULL;
  330. _LoadState = (_LoadState == DfsFolderLoaded) ?
  331. DfsFolderNotLoaded : DfsFolderLoadFailed;
  332. }
  333. }
  334. ReleaseLock();
  335. //
  336. // Release reference on the referral data. This is the reference
  337. // we had taken when we had cached the referral data in this folder.
  338. //
  339. if (pRefData != NULL)
  340. {
  341. if (pRefData->GetOwningFolder() != NULL)
  342. {
  343. DFS_TRACE_LOW(REFERRAL, "Purged cached referral for Logical Name %ws, Link %ws\n",
  344. pRefData->GetOwningFolder()->GetFolderLogicalNameString(),
  345. pRefData->GetOwningFolder()->GetFolderMetadataNameString());
  346. }
  347. pRefData->ReleaseReference();
  348. if (pRemoved != NULL)
  349. {
  350. *pRemoved = TRUE;
  351. }
  352. }
  353. return Status;
  354. }