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.

401 lines
13 KiB

  1. /*
  2. * WORKGRP.C
  3. *
  4. * RSM Service : Work Groups (collections of work items)
  5. *
  6. * Author: ErvinP
  7. *
  8. * (c) 2001 Microsoft Corporation
  9. *
  10. */
  11. #include <windows.h>
  12. #include <stdlib.h>
  13. #include <wtypes.h>
  14. #include <ntmsapi.h>
  15. #include "internal.h"
  16. #include "resource.h"
  17. #include "debug.h"
  18. WORKGROUP *NewWorkGroup()
  19. {
  20. WORKGROUP *workGroup;
  21. workGroup = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(WORKGROUP));
  22. if (workGroup){
  23. workGroup->allWorkItemsCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  24. if (workGroup->allWorkItemsCompleteEvent){
  25. InitializeListHead(&workGroup->workItemsList);
  26. InitializeCriticalSection(&workGroup->lock);
  27. }
  28. else {
  29. GlobalFree(workGroup);
  30. workGroup = NULL;
  31. }
  32. }
  33. ASSERT(workGroup);
  34. return workGroup;
  35. }
  36. VOID FreeWorkGroup(WORKGROUP *workGroup)
  37. {
  38. FlushWorkGroup(workGroup);
  39. CloseHandle(workGroup->allWorkItemsCompleteEvent);
  40. DeleteCriticalSection(&workGroup->lock);
  41. GlobalFree(workGroup);
  42. }
  43. /*
  44. * FlushWorkGroup
  45. *
  46. * Release all the workItems in the workGroup.
  47. */
  48. VOID FlushWorkGroup(WORKGROUP *workGroup)
  49. {
  50. EnterCriticalSection(&workGroup->lock);
  51. while (!IsListEmpty(&workGroup->workItemsList)){
  52. LIST_ENTRY *listEntry;
  53. WORKITEM *workItem;
  54. listEntry = RemoveHeadList(&workGroup->workItemsList);
  55. workItem = CONTAINING_RECORD(listEntry, WORKITEM, workGroupListEntry);
  56. InitializeListHead(&workItem->workGroupListEntry);
  57. workItem->workGroup = NULL;
  58. /*
  59. * Dereference the objects in the workItem.
  60. */
  61. FlushWorkItem(workItem);
  62. /*
  63. * Get the workItem back in the library's free queue.
  64. */
  65. switch (workItem->state){
  66. case WORKITEMSTATE_FREE:
  67. break;
  68. case WORKITEMSTATE_PENDING:
  69. // BUGBUG FINISH - have to abort whatever the library thread
  70. // is doing with this workItem.
  71. DequeuePendingWorkItem(workItem->owningLib, workItem);
  72. EnqueueFreeWorkItem(workItem->owningLib, workItem);
  73. break;
  74. case WORKITEMSTATE_COMPLETE:
  75. DequeueCompleteWorkItem(workItem->owningLib, workItem);
  76. EnqueueFreeWorkItem(workItem->owningLib, workItem);
  77. break;
  78. case WORKITEMSTATE_STAGING:
  79. EnqueueFreeWorkItem(workItem->owningLib, workItem);
  80. break;
  81. default:
  82. DBGERR(("bad workItem state in FlushWorkGroup"));
  83. break;
  84. }
  85. }
  86. LeaveCriticalSection(&workGroup->lock);
  87. }
  88. /*
  89. * BuildMountWorkGroup
  90. *
  91. * Build a work group (collection of work items) for a mount
  92. * request, which may include multiple mounts, possibly spanning
  93. * more than one library.
  94. */
  95. HRESULT BuildMountWorkGroup(WORKGROUP *workGroup,
  96. LPNTMS_GUID lpMediaOrPartitionIds,
  97. LPNTMS_GUID lpDriveIds,
  98. DWORD dwCount,
  99. DWORD dwOptions,
  100. DWORD dwPriority)
  101. {
  102. HRESULT result;
  103. ULONG i;
  104. ASSERT(IsListEmpty(&workGroup->workItemsList));
  105. /*
  106. * 1. Create a workItem for each mount request.
  107. * We will only proceed if all the mount requests are valid.
  108. */
  109. result = ERROR_SUCCESS;
  110. for (i = 0; i < dwCount; i++){
  111. DRIVE *drive;
  112. /*
  113. * If NTMS_MOUNT_SPECIFIC_DRIVE is set,
  114. * we must mount a specific drive.
  115. * Otherwise, we select the drives and return them in lpDriveIds.
  116. */
  117. if (dwOptions & NTMS_MOUNT_SPECIFIC_DRIVE){
  118. drive = FindDrive(&lpDriveIds[i]);
  119. }
  120. else {
  121. drive = NULL;
  122. }
  123. if (drive || !(dwOptions & NTMS_MOUNT_SPECIFIC_DRIVE)){
  124. PHYSICAL_MEDIA *physMedia = NULL;
  125. MEDIA_PARTITION *mediaPart = NULL;
  126. /*
  127. * We may be given either a physical media or a
  128. * media partition to mount. Figure out which one
  129. * by trying to resolve the GUID as either.
  130. */
  131. physMedia = FindPhysicalMedia(&lpMediaOrPartitionIds[i]);
  132. if (!physMedia){
  133. mediaPart = FindMediaPartition(&lpMediaOrPartitionIds[i]);
  134. if (mediaPart){
  135. physMedia = mediaPart->owningPhysicalMedia;
  136. }
  137. }
  138. if (physMedia){
  139. LIBRARY *lib;
  140. BOOLEAN ok;
  141. /*
  142. * Figure out what library we're dealing with.
  143. * Since we may not be given a specific drive,
  144. * we have to figure it out from the media.
  145. * For sanity, check that the media is in a pool.
  146. *
  147. * BUGBUG - how do we keep the media from moving
  148. * before the work item fires ?
  149. */
  150. ok = LockPhysicalMediaWithLibrary(physMedia);
  151. if (ok){
  152. LIBRARY *lib;
  153. lib = physMedia->owningMediaPool ?
  154. physMedia->owningMediaPool->owningLibrary :
  155. NULL;
  156. if (lib){
  157. /*
  158. * If we're targetting a specific drive, then
  159. * it should be in the same library.
  160. */
  161. if (!drive || (drive->lib == lib)){
  162. OBJECT_HEADER *mediaOrPartObj =
  163. mediaPart ?
  164. (OBJECT_HEADER *)mediaPart :
  165. (OBJECT_HEADER *)physMedia;
  166. WORKITEM *workItem;
  167. workItem = DequeueFreeWorkItem(lib, TRUE);
  168. if (workItem){
  169. BuildSingleMountWorkItem( workItem,
  170. drive,
  171. mediaOrPartObj,
  172. dwOptions,
  173. dwPriority);
  174. /*
  175. * We've built one of the mount requests.
  176. * Put it in the work group.
  177. */
  178. InsertTailList( &workGroup->workItemsList,
  179. &workItem->workGroupListEntry);
  180. workItem->workGroup = workGroup;
  181. }
  182. else {
  183. result = ERROR_NOT_ENOUGH_MEMORY;
  184. }
  185. }
  186. else {
  187. result = ERROR_DRIVE_MEDIA_MISMATCH;
  188. }
  189. }
  190. else {
  191. result = ERROR_INVALID_LIBRARY;
  192. }
  193. UnlockPhysicalMediaWithLibrary(physMedia);
  194. }
  195. else {
  196. result = ERROR_DATABASE_FAILURE;
  197. }
  198. }
  199. else {
  200. result = ERROR_INVALID_MEDIA;
  201. }
  202. }
  203. else {
  204. result = ERROR_INVALID_DRIVE;
  205. }
  206. if (result != ERROR_SUCCESS){
  207. break;
  208. }
  209. }
  210. if (result == ERROR_SUCCESS){
  211. workGroup->numTotalWorkItems = workGroup->numPendingWorkItems = dwCount;
  212. }
  213. else {
  214. /*
  215. * If we failed, release any work items that we did create.
  216. */
  217. FlushWorkGroup(workGroup);
  218. }
  219. return result;
  220. }
  221. /*
  222. * BuildDismountWorkGroup
  223. *
  224. * Build a work group (collection of work items) for a dismount
  225. * request, which may include multiple dismounts, possibly spanning
  226. * more than one library.
  227. */
  228. HRESULT BuildDismountWorkGroup( WORKGROUP *workGroup,
  229. LPNTMS_GUID lpMediaOrPartitionIds,
  230. DWORD dwCount,
  231. DWORD dwOptions)
  232. {
  233. HRESULT result;
  234. ULONG i;
  235. ASSERT(IsListEmpty(&workGroup->workItemsList));
  236. /*
  237. * 1. Create a workItem for each dismount request.
  238. * We will only proceed if all the dismount requests are valid.
  239. */
  240. result = ERROR_SUCCESS;
  241. for (i = 0; i < dwCount; i++){
  242. PHYSICAL_MEDIA *physMedia = NULL;
  243. MEDIA_PARTITION *mediaPart = NULL;
  244. /*
  245. * We may be given either a physical media or a
  246. * media partition to mount. Figure out which one
  247. * by trying to resolve the GUID as either.
  248. */
  249. physMedia = FindPhysicalMedia(&lpMediaOrPartitionIds[i]);
  250. if (!physMedia){
  251. mediaPart = FindMediaPartition(&lpMediaOrPartitionIds[i]);
  252. if (mediaPart){
  253. physMedia = mediaPart->owningPhysicalMedia;
  254. }
  255. }
  256. if (physMedia){
  257. LIBRARY *lib;
  258. BOOLEAN ok;
  259. /*
  260. * Figure out what library we're dealing with.
  261. */
  262. ok = LockPhysicalMediaWithLibrary(physMedia);
  263. if (ok){
  264. LIBRARY *lib;
  265. lib = physMedia->owningMediaPool ?
  266. physMedia->owningMediaPool->owningLibrary :
  267. NULL;
  268. if (lib){
  269. OBJECT_HEADER *mediaOrPartObj =
  270. mediaPart ?
  271. (OBJECT_HEADER *)mediaPart :
  272. (OBJECT_HEADER *)physMedia;
  273. WORKITEM *workItem;
  274. workItem = DequeueFreeWorkItem(lib, TRUE);
  275. if (workItem){
  276. BuildSingleDismountWorkItem( workItem,
  277. mediaOrPartObj,
  278. dwOptions);
  279. /*
  280. * We've built one of the mount requests.
  281. * Put it in the work group.
  282. */
  283. InsertTailList( &workGroup->workItemsList,
  284. &workItem->workGroupListEntry);
  285. workItem->workGroup = workGroup;
  286. }
  287. else {
  288. result = ERROR_NOT_ENOUGH_MEMORY;
  289. }
  290. }
  291. else {
  292. result = ERROR_DRIVE_MEDIA_MISMATCH;
  293. }
  294. UnlockPhysicalMediaWithLibrary(physMedia);
  295. }
  296. else {
  297. result = ERROR_DATABASE_FAILURE;
  298. }
  299. }
  300. else {
  301. result = ERROR_INVALID_MEDIA;
  302. }
  303. }
  304. if (result == ERROR_SUCCESS){
  305. workGroup->numTotalWorkItems = workGroup->numPendingWorkItems = dwCount;
  306. }
  307. else {
  308. /*
  309. * If we failed, release any work items that we did create and clean up.
  310. */
  311. FlushWorkGroup(workGroup);
  312. }
  313. return result;
  314. }
  315. /*
  316. * ScheduleWorkGroup
  317. *
  318. * Submit all the work items in the work group.
  319. */
  320. HRESULT ScheduleWorkGroup(WORKGROUP *workGroup)
  321. {
  322. LIST_ENTRY *listEntry;
  323. HRESULT result;
  324. EnterCriticalSection(&workGroup->lock);
  325. /*
  326. * Set the workGroup's status to success.
  327. * If any workItems fail, they'll set this to an error code.
  328. */
  329. workGroup->resultStatus = ERROR_SUCCESS;
  330. listEntry = &workGroup->workItemsList;
  331. while ((listEntry = listEntry->Flink) != &workGroup->workItemsList){
  332. WORKITEM *workItem = CONTAINING_RECORD(listEntry, WORKITEM, workGroupListEntry);
  333. ASSERT(workItem->state == WORKITEMSTATE_STAGING);
  334. /*
  335. * Give this workItem to the library and wake up the library thread.
  336. */
  337. EnqueuePendingWorkItem(workItem->owningLib, workItem);
  338. }
  339. LeaveCriticalSection(&workGroup->lock);
  340. result = ERROR_SUCCESS;
  341. return result;
  342. }