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.

423 lines
13 KiB

  1. /*
  2. * DRIVEARB.C
  3. *
  4. *
  5. * DRIVEARB.DLL - Shared Drive Aribiter for shared disks and libraries
  6. * - inter-machine sharing client
  7. * - inter-app sharing service
  8. *
  9. * Author: ErvinP
  10. *
  11. * (c) 2000 Microsoft Corporation
  12. *
  13. */
  14. #include <windows.h>
  15. #include <stdlib.h>
  16. #include <wtypes.h>
  17. #include <dlmhdr.h> // BUGBUG - get a common DLM header from Cluster team
  18. #include <drivearb.h>
  19. #include "internal.h"
  20. /*
  21. * SHARED DATA Section
  22. *
  23. * Note: in order for global data items to be placed
  24. * in a non-default section, they must be
  25. * explicitly initialized!
  26. */
  27. #pragma data_seg("DRIVEARB_SharedDataSection")
  28. DWORD g_initializingGlobals = 0;
  29. DWORD g_numDrivesInFileMap = 0;
  30. #pragma data_seg()
  31. #pragma comment(linker, "/section:DRIVEARB_SharedDataSection,rws")
  32. /*
  33. * These are the process-local handles to the inter-process SHARED global:
  34. * mutex
  35. * fileMapping for the drives array
  36. * view pointer into that fileMapping
  37. */
  38. HANDLE g_hSharedGlobalMutex = NULL;
  39. HANDLE g_allDrivesFileMap = NULL;
  40. driveContext *g_allDrivesViewPtr = NULL;
  41. STDAPI_(BOOL) DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved)
  42. {
  43. BOOL result = FALSE;
  44. switch (dwReason){
  45. case DLL_PROCESS_ATTACH:
  46. /*
  47. * DllMain calls are synchronized on a per-process basis,
  48. * but not between processes, so we need some synchronization
  49. * here while creating our globalMutex handle.
  50. * Since we don't even have our global mutex yet,
  51. * use InterlockedIncrement on a shared-data counter here
  52. * to synchronize multiple DLL_PROCESS_ATTACH calls.
  53. */
  54. while (InterlockedIncrement(&g_initializingGlobals) != 1){
  55. InterlockedDecrement(&g_initializingGlobals);
  56. Sleep(1);
  57. }
  58. /*
  59. * See if the global mutex is already allocated
  60. * for some other process by trying to open it.
  61. * If not, allocate it.
  62. */
  63. g_hSharedGlobalMutex = OpenMutex(SYNCHRONIZE, FALSE, GLOBAL_MUTEX_NAME);
  64. if (!g_hSharedGlobalMutex){
  65. g_hSharedGlobalMutex = CreateMutex(NULL, FALSE, GLOBAL_MUTEX_NAME);
  66. }
  67. if (g_hSharedGlobalMutex){
  68. result = InitDrivesFileMappingForProcess();
  69. }
  70. InterlockedDecrement(&g_initializingGlobals);
  71. break;
  72. case DLL_PROCESS_DETACH:
  73. /*
  74. * Don't need to synchronize with other processes here
  75. * because we're only closing our process-local handles.
  76. */
  77. DestroyDrivesFileMappingForProcess();
  78. if (g_hSharedGlobalMutex){
  79. CloseHandle(g_hSharedGlobalMutex);
  80. g_hSharedGlobalMutex = NULL;
  81. }
  82. result = TRUE;
  83. break;
  84. case DLL_THREAD_ATTACH:
  85. case DLL_THREAD_DETACH:
  86. default:
  87. result = TRUE;
  88. break;
  89. }
  90. return result;
  91. }
  92. HANDLE __stdcall OpenDriveSession(LPSTR driveName, INVALIDATE_DRIVE_HANDLE_PROC invalidateHandleProc)
  93. {
  94. clientSessionContext *session;
  95. if (lstrlen(driveName) > 0){
  96. if (invalidateHandleProc){
  97. session = NewClientSession(driveName);
  98. if (session){
  99. BOOL ok;
  100. WaitForSingleObject(g_hSharedGlobalMutex, INFINITE);
  101. ok = InitializeClientArbitration(session);
  102. if (ok){
  103. session->driveViewPtr->sessionReferenceCount++;
  104. }
  105. ReleaseMutex(g_hSharedGlobalMutex);
  106. if (!ok){
  107. FreeClientSession(session);
  108. session = NULL;
  109. }
  110. }
  111. else {
  112. ASSERT(session);
  113. }
  114. }
  115. else {
  116. ASSERT(invalidateHandleProc);
  117. session = NULL;
  118. }
  119. }
  120. else {
  121. ASSERT(lstrlen(driveName) > 0);
  122. session = NULL;
  123. }
  124. return (HANDLE)session;
  125. }
  126. VOID __stdcall CloseDriveSession(HANDLE hSession)
  127. {
  128. clientSessionContext *session = (clientSessionContext *)hSession;
  129. if (session->sig == DRIVEARB_SIG){ // sanity check
  130. WaitForSingleObject(g_hSharedGlobalMutex, INFINITE);
  131. /*
  132. * Need to lock drive to make sure driveViewPtr is valid.
  133. */
  134. if (LOCKDriveForSession(session)){
  135. ASSERT(session->driveViewPtr->sessionReferenceCount > 0);
  136. session->driveViewPtr->sessionReferenceCount--;
  137. UNLOCKDriveForSession(session);
  138. }
  139. ShutDownClientArbitration(session);
  140. ReleaseMutex(g_hSharedGlobalMutex);
  141. FreeClientSession(session);
  142. }
  143. else {
  144. ASSERT(session->sig == DRIVEARB_SIG);
  145. }
  146. }
  147. BOOL __stdcall AcquireDrive(HANDLE hDriveSession, DWORD flags)
  148. {
  149. clientSessionContext *session = (clientSessionContext *)hDriveSession;
  150. BOOL result = FALSE;
  151. if (session->sig == DRIVEARB_SIG){ // sanity check
  152. if (LOCKDriveForSession(session)){
  153. driveContext *drive = session->driveViewPtr;
  154. BOOL gotAppOwnership = FALSE;
  155. BOOL unlockedAbort = FALSE;
  156. if (drive->state == DRIVESTATE_UNAVAILABLE_LOCALLY){
  157. /*
  158. * Attempt to get ownership of the drive
  159. * for this node synchronously.
  160. * This should not fail.
  161. *
  162. * BUGBUG - need to implement DRIVEARB_NOWAIT flag in arbiter, too
  163. */
  164. BOOL gotNodeOwnership;
  165. gotNodeOwnership = AcquireNodeLevelOwnership(session);
  166. if (gotNodeOwnership){
  167. drive->state = DRIVESTATE_AVAILABLE_LOCALLY;
  168. }
  169. else {
  170. ASSERT(gotNodeOwnership);
  171. }
  172. }
  173. if (drive->state == DRIVESTATE_AVAILABLE_LOCALLY){
  174. gotAppOwnership = TRUE;
  175. }
  176. else if (drive->state == DRIVESTATE_INUSE_LOCALLY){
  177. /*
  178. * The drive is owned by the local node,
  179. * but some other app is using it.
  180. * Wait to get ownership by the calling app.
  181. */
  182. while (TRUE){
  183. BOOL availableNow;
  184. if (drive->state == DRIVESTATE_UNAVAILABLE_LOCALLY){
  185. /*
  186. * This is not possible now, but may become possible
  187. * if we implement some sort of fairness (such that
  188. * we may release node-level ownership in ReleaseDrive
  189. * even though local clients are waiting).
  190. */
  191. availableNow = FALSE;
  192. }
  193. else if (drive->state == DRIVESTATE_AVAILABLE_LOCALLY){
  194. availableNow = TRUE;
  195. }
  196. else if ((flags & DRIVEARB_REQUEST_READ) && drive->denyRead){
  197. availableNow = FALSE;
  198. }
  199. else if ((flags & DRIVEARB_REQUEST_WRITE) && drive->denyWrite){
  200. availableNow = FALSE;
  201. }
  202. else if ((drive->numCurrentReaders > 0) &&
  203. !(flags & DRIVEARB_INTRANODE_SHARE_READ)){
  204. availableNow = FALSE;
  205. }
  206. else if ((drive->numCurrentWriters > 0) &&
  207. !(flags & DRIVEARB_INTRANODE_SHARE_WRITE)){
  208. availableNow = FALSE;
  209. }
  210. else {
  211. availableNow = TRUE;
  212. }
  213. if (availableNow){
  214. gotAppOwnership = TRUE;
  215. break;
  216. }
  217. else if (flags & DRIVEARB_NOWAIT){
  218. break;
  219. }
  220. else {
  221. /*
  222. * We need to wait for the drive to become available.
  223. */
  224. DWORD waitRes;
  225. // DBGMSG("AcquireDrive waiting ...", (ULONG_PTR)session->sessionDriveEvent);
  226. session->state = CLIENTSTATE_WAITING;
  227. drive->numWaitingSessions++;
  228. /*
  229. * Unlock the drive while waiting for the event.
  230. */
  231. UNLOCKDriveForSession(session);
  232. waitRes = WaitForSingleObject(session->sessionDriveEvent, INFINITE);
  233. // DBGMSG(" ... AcquireDrive done waiting.", waitRes);
  234. if (waitRes == WAIT_FAILED){
  235. DWORD errCode = GetLastError();
  236. DBGMSG("WaitForSingleObject failed with:", errCode);
  237. }
  238. if (LOCKDriveForSession(session)){
  239. drive->numWaitingSessions--;
  240. }
  241. else {
  242. /*
  243. * Couldn't re-lock, abort.
  244. *
  245. * BUGBUG - numWaitingSessions is wrong now,
  246. * but can't correct it because can't lock the drive
  247. */
  248. unlockedAbort = TRUE;
  249. break;
  250. }
  251. }
  252. }
  253. }
  254. if (gotAppOwnership){
  255. drive->state = DRIVESTATE_INUSE_LOCALLY;
  256. if (flags & DRIVEARB_REQUEST_READ){
  257. drive->numCurrentReaders++;
  258. }
  259. if (flags & DRIVEARB_REQUEST_WRITE){
  260. drive->numCurrentWriters++;
  261. }
  262. if (!(flags & DRIVEARB_INTRANODE_SHARE_READ)){
  263. drive->denyRead = TRUE;
  264. }
  265. if (!(flags & DRIVEARB_INTRANODE_SHARE_WRITE)){
  266. drive->denyWrite = TRUE;
  267. }
  268. session->shareFlags = flags;
  269. session->state = CLIENTSTATE_ACTIVE;
  270. result = TRUE;
  271. }
  272. if (!unlockedAbort){
  273. UNLOCKDriveForSession(session);
  274. }
  275. }
  276. }
  277. else {
  278. ASSERT(session->sig == DRIVEARB_SIG);
  279. }
  280. return result;
  281. }
  282. VOID __stdcall ReleaseDrive(HANDLE hDriveSession)
  283. {
  284. clientSessionContext *session = (clientSessionContext *)hDriveSession;
  285. // DBGMSG("> ReleaseDrive", 0);
  286. if (session->sig == DRIVEARB_SIG){ // sanity check
  287. driveContext *drive;
  288. if (LOCKDriveForSession(session)){
  289. BOOL eventSetOk;
  290. drive = session->driveViewPtr;
  291. if (session->shareFlags & DRIVEARB_REQUEST_READ){
  292. ASSERT(drive->numCurrentReaders > 0);
  293. drive->numCurrentReaders--;
  294. }
  295. if (session->shareFlags & DRIVEARB_REQUEST_WRITE){
  296. ASSERT(drive->numCurrentWriters > 0);
  297. drive->numCurrentWriters--;
  298. }
  299. if (!(session->shareFlags & DRIVEARB_INTRANODE_SHARE_READ)){
  300. ASSERT(drive->denyRead);
  301. drive->denyRead = FALSE;
  302. }
  303. if (!(session->shareFlags & DRIVEARB_INTRANODE_SHARE_WRITE)){
  304. ASSERT(drive->denyWrite);
  305. drive->denyWrite = FALSE;
  306. }
  307. session->state = CLIENTSTATE_INACTIVE;
  308. /*
  309. * Only release the drive to other machines if there are
  310. * no clients waiting for it on this machine.
  311. *
  312. * BUGBUG - implement some fairness to apps on other nodes
  313. */
  314. ASSERT(drive->state == DRIVESTATE_INUSE_LOCALLY);
  315. if (drive->numWaitingSessions == 0){
  316. ReleaseNodeLevelOwnership(session);
  317. drive->state = DRIVESTATE_UNAVAILABLE_LOCALLY;
  318. }
  319. else {
  320. drive->state = DRIVESTATE_AVAILABLE_LOCALLY;
  321. }
  322. UNLOCKDriveForSession(session);
  323. // DBGMSG("ReleaseDrive setting event:", (ULONG_PTR)session->sessionDriveEvent);
  324. eventSetOk = PulseEvent(session->sessionDriveEvent);
  325. if (!eventSetOk){
  326. DWORD errCode = GetLastError();
  327. DBGMSG("PulseEvent failed with:", errCode);
  328. }
  329. }
  330. }
  331. else {
  332. ASSERT(session->sig == DRIVEARB_SIG);
  333. }
  334. // DBGMSG("< ReleaseDrive", 0);
  335. }