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.

1462 lines
41 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. forks.c
  5. Abstract:
  6. This module contains the routines for manipulating the open forks.
  7. Author:
  8. Jameel Hyder (microsoft!jameelh)
  9. Revision History:
  10. 25 Apr 1992 Initial Version
  11. Notes: Tab stop: 4
  12. --*/
  13. #define FORK_LOCALS
  14. #define FORKIO_LOCALS
  15. #define FILENUM FILE_FORKS
  16. #include <afp.h>
  17. #include <client.h>
  18. #include <fdparm.h>
  19. #include <pathmap.h>
  20. #include <scavengr.h>
  21. #include <afpinfo.h>
  22. #include <forkio.h>
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text( INIT, AfpForksInit)
  25. #pragma alloc_text( PAGE, afpForkConvertToAbsOffSize)
  26. #pragma alloc_text( PAGE_AFP, AfpAdmWForkClose)
  27. #pragma alloc_text( PAGE_AFP, AfpForkReferenceById)
  28. #endif
  29. /*** AfpForksInit
  30. *
  31. * Initialize locks for forks.
  32. */
  33. NTSTATUS
  34. AfpForksInit(
  35. VOID
  36. )
  37. {
  38. INITIALIZE_SPIN_LOCK(&AfpForksLock);
  39. return STATUS_SUCCESS;
  40. }
  41. /*** AfpForkReferenceByRefNum
  42. *
  43. * Map a OForkRefNum to an open fork entry for the session and reference it.
  44. *
  45. * LOCKS: ofe_Lock
  46. *
  47. * CALLABLE at DISPATCH_LEVEL ONLY !!!
  48. */
  49. POPENFORKENTRY FASTCALL
  50. AfpForkReferenceByRefNum(
  51. IN PSDA pSda,
  52. IN DWORD OForkRefNum
  53. )
  54. {
  55. POPENFORKSESS pOpenForkSess;
  56. POPENFORKENTRY pOpenForkEntry;
  57. POPENFORKENTRY pOFEntry = NULL;
  58. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  59. ASSERT (VALID_SDA(pSda));
  60. if (OForkRefNum == 0)
  61. {
  62. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_ERR,
  63. ("AfpForkReferenceByRefNum: client sent 0 for ForkRefNumFork\n"));
  64. return(NULL);
  65. }
  66. pOpenForkSess = &pSda->sda_OpenForkSess;
  67. while (OForkRefNum > FORK_OPEN_CHUNKS)
  68. {
  69. OForkRefNum -= FORK_OPEN_CHUNKS;
  70. pOpenForkSess = pOpenForkSess->ofs_Link;
  71. if (pOpenForkSess == NULL)
  72. return NULL;
  73. }
  74. pOpenForkEntry = pOpenForkSess->ofs_pOpenForkEntry[OForkRefNum-1];
  75. // If this has been marked closed, then return NULL
  76. if (pOpenForkEntry != NULL)
  77. {
  78. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  79. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkEntry->ofe_Lock);
  80. if (!(pOpenForkEntry->ofe_Flags & OPEN_FORK_CLOSING))
  81. {
  82. pOpenForkEntry->ofe_RefCount ++;
  83. pOFEntry = pOpenForkEntry;
  84. }
  85. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkEntry->ofe_Lock);
  86. }
  87. return pOFEntry;
  88. }
  89. /*** AfpForkReferenceByPointer
  90. *
  91. * Reference the Open Fork Entry. This is used by the admin APIs.
  92. *
  93. * LOCKS: ofe_Lock
  94. */
  95. POPENFORKENTRY FASTCALL
  96. AfpForkReferenceByPointer(
  97. IN POPENFORKENTRY pOpenForkEntry
  98. )
  99. {
  100. POPENFORKENTRY pOFEntry = NULL;
  101. KIRQL OldIrql;
  102. ASSERT (VALID_OPENFORKENTRY(pOpenForkEntry));
  103. ACQUIRE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, &OldIrql);
  104. if (!(pOpenForkEntry->ofe_Flags & OPEN_FORK_CLOSING))
  105. {
  106. pOpenForkEntry->ofe_RefCount ++;
  107. pOFEntry = pOpenForkEntry;
  108. }
  109. RELEASE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, OldIrql);
  110. return pOFEntry;
  111. }
  112. /*** AfpForkReferenceById
  113. *
  114. * Reference the Open Fork Entry. This is used by the admin APIs.
  115. *
  116. * LOCKS: ofe_Lock, AfpForksLock
  117. * LOCK_ORDER: ofe_Lock after AfpForksLock
  118. */
  119. POPENFORKENTRY FASTCALL
  120. AfpForkReferenceById(
  121. IN DWORD ForkId
  122. )
  123. {
  124. POPENFORKENTRY pOpenForkEntry;
  125. POPENFORKENTRY pOFEntry = NULL;
  126. KIRQL OldIrql;
  127. ASSERT (ForkId != 0);
  128. ACQUIRE_SPIN_LOCK(&AfpForksLock, &OldIrql);
  129. for (pOpenForkEntry = AfpOpenForksList;
  130. (pOpenForkEntry != NULL) && (pOpenForkEntry->ofe_ForkId >= ForkId);
  131. pOpenForkEntry = pOpenForkEntry->ofe_Next)
  132. {
  133. if (pOpenForkEntry->ofe_ForkId == ForkId)
  134. {
  135. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkEntry->ofe_Lock);
  136. if (!(pOpenForkEntry->ofe_Flags & OPEN_FORK_CLOSING))
  137. {
  138. pOFEntry = pOpenForkEntry;
  139. pOpenForkEntry->ofe_RefCount ++;
  140. }
  141. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkEntry->ofe_Lock);
  142. break;
  143. }
  144. }
  145. RELEASE_SPIN_LOCK(&AfpForksLock, OldIrql);
  146. return pOFEntry;
  147. }
  148. /*** AfpForkClose
  149. *
  150. * Close an open fork. Simply set the close flag on the open fork and update
  151. * connection counts, if any.
  152. *
  153. * LOCKS: ofd_EntryLock, cds_ConnLock
  154. */
  155. VOID
  156. AfpForkClose(
  157. IN POPENFORKENTRY pOpenForkEntry
  158. )
  159. {
  160. PCONNDESC pConnDesc;
  161. PVOLDESC pVolDesc = pOpenForkEntry->ofe_pOpenForkDesc->ofd_pVolDesc;
  162. KIRQL OldIrql;
  163. BOOLEAN fAlreadyClosing=FALSE;
  164. ASSERT(VALID_CONNDESC(pOpenForkEntry->ofe_pConnDesc));
  165. pConnDesc = pOpenForkEntry->ofe_pConnDesc;
  166. if ((pConnDesc != NULL) &&
  167. (AfpConnectionReferenceByPointer(pConnDesc) != NULL))
  168. {
  169. ASSERT (pConnDesc->cds_pVolDesc == pVolDesc);
  170. INTERLOCKED_DECREMENT_LONG(&pConnDesc->cds_cOpenForks);
  171. // update the disk quota for this user
  172. if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
  173. {
  174. // reference again: afpUpdateDiskQuotaInfo will remove this refcount
  175. if (AfpConnectionReferenceByPointer(pConnDesc) != NULL)
  176. {
  177. afpUpdateDiskQuotaInfo(pConnDesc);
  178. }
  179. }
  180. AfpConnectionDereference(pConnDesc);
  181. }
  182. ACQUIRE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, &OldIrql);
  183. if (!(pOpenForkEntry->ofe_Flags & OPEN_FORK_CLOSING))
  184. {
  185. pOpenForkEntry->ofe_Flags |= OPEN_FORK_CLOSING;
  186. }
  187. else
  188. {
  189. fAlreadyClosing = TRUE;
  190. }
  191. RELEASE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, OldIrql);
  192. if (!fAlreadyClosing)
  193. {
  194. // Take away the creation reference
  195. AfpForkDereference(pOpenForkEntry);
  196. }
  197. }
  198. /*** AfpForkDereference
  199. *
  200. * Dereference an open fork entry. If it is marked for deletion and this is
  201. * the last reference, then it is cleaned up.
  202. *
  203. * LOCKS: AfpForksLock (SPIN), vds_VolLock (SPIN), ofd_Lock (SPIN),
  204. * LOCKS: ofe_Lock (SPIN), AfpStatisticsLock (SPIN), sda_Lock (SPIN)
  205. *
  206. * LOCK_ORDER: AfpStatisticsLock after ofd_Lock after vds_VolLock
  207. *
  208. */
  209. VOID FASTCALL
  210. AfpForkDereference(
  211. IN POPENFORKENTRY pOpenForkEntry
  212. )
  213. {
  214. POPENFORKSESS pOpenForkSess;
  215. POPENFORKDESC pOpenForkDesc;
  216. PVOLDESC pVolDesc;
  217. PFORKLOCK pForkLock, *ppForkLock;
  218. DWORD OForkRefNum, FileNum, NumLocks;
  219. PSDA pSda;
  220. KIRQL OldIrql;
  221. BOOLEAN Resource, LastClose = False;
  222. BOOLEAN Cleanup;
  223. PDFENTRY pDfEntry = NULL;
  224. FORKSIZE forklen;
  225. DWORD Status;
  226. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  227. ACQUIRE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, &OldIrql);
  228. pOpenForkEntry->ofe_RefCount --;
  229. ASSERT(pOpenForkEntry->ofe_RefCount >= 0);
  230. Cleanup = (pOpenForkEntry->ofe_RefCount == 0);
  231. RELEASE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, OldIrql);
  232. if (!Cleanup)
  233. return;
  234. // Unlink this from the global list
  235. ACQUIRE_SPIN_LOCK(&AfpForksLock, &OldIrql);
  236. AfpUnlinkDouble(pOpenForkEntry, ofe_Next, ofe_Prev);
  237. AfpNumOpenForks --;
  238. RELEASE_SPIN_LOCK(&AfpForksLock, OldIrql);
  239. // Clean up the rest
  240. pOpenForkDesc = pOpenForkEntry->ofe_pOpenForkDesc;
  241. pVolDesc = pOpenForkDesc->ofd_pVolDesc;
  242. ASSERT(VALID_CONNDESC(pOpenForkEntry->ofe_pConnDesc));
  243. pSda = pOpenForkEntry->ofe_pSda;
  244. ASSERT(VALID_OPENFORKDESC(pOpenForkDesc));
  245. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  246. ("AfpForkDereference: Closing Fork %ld for Session %ld\n",
  247. pOpenForkEntry->ofe_ForkId, pSda->sda_SessionId));
  248. // Save OForkRefNum for clearing up the Sda entry later on
  249. OForkRefNum = pOpenForkEntry->ofe_OForkRefNum;
  250. Resource = RESCFORK(pOpenForkEntry);
  251. // We are not relying on
  252. // change notifies to update our cached DFE Fork lengths and
  253. // modified times from Writes and SetForkParms, so we must do it
  254. // ourselves at the time when the fork handle is closed by mac.
  255. // Note the order that the locks are taken here and for
  256. // FpExchangeFiles/AfpExchangeForkAfpIds to prevent a FileId stored
  257. // in the OpenForkDesc from changing out from under us due to
  258. // an FpExchangeFiles call.
  259. AfpSwmrAcquireExclusive(&pVolDesc->vds_ExchangeFilesLock);
  260. // Save file number so we can clear the ALREADY_OPEN flag in the DFEntry.
  261. FileNum = pOpenForkDesc->ofd_FileNumber;
  262. // Get rid of locks for this fork entry and reduce the use count
  263. // We do not actually have to unlock the ranges as the close will
  264. // get rid of them for us. If use count goes to zero, also unlink
  265. // this fork desc from the volume list.
  266. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  267. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkDesc->ofd_Lock);
  268. pOpenForkDesc->ofd_UseCount --;
  269. for (NumLocks = 0, ppForkLock = &pOpenForkDesc->ofd_pForkLock;
  270. (pForkLock = *ppForkLock) != NULL;
  271. NOTHING)
  272. {
  273. if (pForkLock->flo_pOpenForkEntry == pOpenForkEntry)
  274. {
  275. ASSERT(pOpenForkDesc->ofd_NumLocks > 0);
  276. pOpenForkDesc->ofd_NumLocks --;
  277. ASSERT(pOpenForkEntry->ofe_cLocks > 0);
  278. #if DBG
  279. pOpenForkEntry->ofe_cLocks --;
  280. #endif
  281. NumLocks ++;
  282. *ppForkLock = pForkLock->flo_Next;
  283. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  284. ("AfpForkDereference: Freeing lock %lx\n", pForkLock));
  285. AfpIOFreeBuffer(pForkLock);
  286. }
  287. else ppForkLock = &pForkLock->flo_Next;
  288. }
  289. INTERLOCKED_ADD_ULONG_DPC(&AfpServerStatistics.stat_CurrentFileLocks,
  290. (ULONG)(-(LONG)NumLocks),
  291. &(AfpStatisticsLock.SpinLock));
  292. ASSERT (pOpenForkEntry->ofe_cLocks == 0);
  293. if (pOpenForkDesc->ofd_UseCount == 0)
  294. {
  295. ASSERT (pOpenForkDesc->ofd_NumLocks == 0);
  296. ASSERT (pOpenForkDesc->ofd_cOpenR <= FORK_OPEN_READ);
  297. ASSERT (pOpenForkDesc->ofd_cOpenW <= FORK_OPEN_WRITE);
  298. ASSERT (pOpenForkDesc->ofd_cDenyR <= FORK_DENY_READ);
  299. ASSERT (pOpenForkDesc->ofd_cDenyW <= FORK_DENY_WRITE);
  300. LastClose = True;
  301. // Unlink the OpenForkDesc from the Volume Descriptor
  302. AfpUnlinkDouble(pOpenForkDesc, ofd_Next, ofd_Prev);
  303. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkDesc->ofd_Lock);
  304. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  305. // Free the memory for the OpenFork descriptor and path buffer
  306. if (pOpenForkDesc->ofd_FilePath.Length > 0)
  307. {
  308. AfpFreeMemory(pOpenForkDesc->ofd_FilePath.Buffer);
  309. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  310. ("AfpForkDereference: Freeing path to file %lx\n",
  311. pOpenForkDesc->ofd_FilePath.Buffer));
  312. }
  313. // Dereference the volume descriptor now
  314. AfpVolumeDereference(pVolDesc);
  315. // Finally free the open fork descriptor
  316. AfpFreeMemory(pOpenForkDesc);
  317. }
  318. else
  319. {
  320. // Update the open & deny modes
  321. pOpenForkDesc->ofd_cOpenR -= (pOpenForkEntry->ofe_OpenMode & FORK_OPEN_READ);
  322. pOpenForkDesc->ofd_cOpenW -= (pOpenForkEntry->ofe_OpenMode & FORK_OPEN_WRITE);
  323. pOpenForkDesc->ofd_cDenyR -= (pOpenForkEntry->ofe_DenyMode & FORK_OPEN_READ);
  324. pOpenForkDesc->ofd_cDenyW -= (pOpenForkEntry->ofe_DenyMode & FORK_OPEN_WRITE);
  325. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkDesc->ofd_Lock);
  326. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  327. }
  328. // Lookup the DFE entry by ID, query for the fork length and
  329. // for the appropriate time (LastWriteTime for DATA$ fork,
  330. // ChangeTime for Resource) and set the LastWriteTime
  331. // to last ChangeTime if its resource fork. If its the last close
  332. // for this fork, since we already have the DFE pointer and hold
  333. // the IdDb SWMR, update the DFE_FLAGS_x_ALREADYOPEN flag. Then
  334. // release the SWMR.
  335. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  336. pDfEntry = AfpFindDfEntryById(pVolDesc,
  337. FileNum,
  338. DFE_FILE);
  339. Status = AfpIoQuerySize(&pOpenForkEntry->ofe_FileSysHandle,
  340. &forklen);
  341. if (NT_SUCCESS(Status) && (pDfEntry != NULL))
  342. {
  343. if (IS_VOLUME_NTFS(pVolDesc))
  344. {
  345. AfpIoChangeNTModTime(&pOpenForkEntry->ofe_FileSysHandle,
  346. &pDfEntry->dfe_LastModTime);
  347. }
  348. if (Resource)
  349. {
  350. pDfEntry->dfe_RescLen = forklen.LowPart;
  351. if (LastClose)
  352. {
  353. pDfEntry->dfe_Flags &= ~DFE_FLAGS_R_ALREADYOPEN;
  354. #ifdef AGE_DFES
  355. if (IS_VOLUME_AGING_DFES(pVolDesc))
  356. {
  357. pDfEntry->dfe_Parent->dfe_pDirEntry->de_ChildForkOpenCount --;
  358. }
  359. #endif
  360. }
  361. }
  362. else
  363. {
  364. pDfEntry->dfe_DataLen = forklen.LowPart;
  365. if (LastClose)
  366. {
  367. pDfEntry->dfe_Flags &= ~DFE_FLAGS_D_ALREADYOPEN;
  368. #ifdef AGE_DFES
  369. if (IS_VOLUME_AGING_DFES(pVolDesc))
  370. {
  371. pDfEntry->dfe_Parent->dfe_pDirEntry->de_ChildForkOpenCount --;
  372. }
  373. #endif
  374. }
  375. }
  376. }
  377. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  378. AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
  379. // Now clear up the entry in the Sda
  380. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  381. pSda->sda_cOpenForks--;
  382. pOpenForkSess = &pSda->sda_OpenForkSess;
  383. while (OForkRefNum > FORK_OPEN_CHUNKS)
  384. {
  385. OForkRefNum -= FORK_OPEN_CHUNKS;
  386. pOpenForkSess = pOpenForkSess->ofs_Link;
  387. ASSERT (pOpenForkSess != NULL);
  388. }
  389. ASSERT (pOpenForkEntry == pOpenForkSess->ofs_pOpenForkEntry[OForkRefNum-1]);
  390. pOpenForkSess->ofs_pOpenForkEntry[OForkRefNum-1] = NULL;
  391. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  392. AfpSdaDereferenceSession(pSda); // Remove the reference for this fork here
  393. ASSERT(VALID_CONNDESC(pOpenForkEntry->ofe_pConnDesc));
  394. AfpConnectionDereference(pOpenForkEntry->ofe_pConnDesc);
  395. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  396. // All done, close the fork handle and free the OFE
  397. if (pOpenForkEntry->ofe_ForkHandle != NULL)
  398. {
  399. AfpIoClose(&pOpenForkEntry->ofe_FileSysHandle);
  400. }
  401. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  402. ("AfpForkDereference: Fork %ld is history\n", pOpenForkEntry->ofe_ForkId));
  403. AfpFreeMemory(pOpenForkEntry);
  404. }
  405. /*** AfpCheckDenyConflict
  406. *
  407. * Check if the requested Open & Deny Modes clash with current open & deny modes.
  408. *
  409. * LOCKS: ofd_Lock, vds_VolLock (SPIN) IFF ppOpenForkDesc is NULL ELSE
  410. * LOCKS_ASSUMED: vds_VolLock (SPIN)
  411. *
  412. * LOCK_ORDER: ofd_Lock after vds_VolLock
  413. */
  414. AFPSTATUS
  415. AfpCheckDenyConflict(
  416. IN PVOLDESC pVolDesc,
  417. IN DWORD AfpId,
  418. IN BOOLEAN Resource,
  419. IN BYTE OpenMode,
  420. IN BYTE DenyMode,
  421. IN POPENFORKDESC * ppOpenForkDesc OPTIONAL
  422. )
  423. {
  424. KIRQL OldIrql;
  425. POPENFORKDESC pOpenForkDesc;
  426. AFPSTATUS Status = AFP_ERR_NONE;
  427. BOOLEAN Foundit = False;
  428. if (ARGUMENT_PRESENT(ppOpenForkDesc))
  429. *ppOpenForkDesc = NULL;
  430. else ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  431. // check the list of open forks in this volume for any deny conflicts
  432. for (pOpenForkDesc = pVolDesc->vds_pOpenForkDesc;
  433. pOpenForkDesc != NULL;
  434. pOpenForkDesc = pOpenForkDesc->ofd_Next)
  435. {
  436. BOOLEAN DescRes;
  437. // Take the DescLock before looking at AfpId since FpExchangeFiles
  438. // can change the ID
  439. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkDesc->ofd_Lock);
  440. DescRes = (pOpenForkDesc->ofd_Flags & OPEN_FORK_RESOURCE) ? True : False;
  441. if ((pOpenForkDesc->ofd_FileNumber == AfpId) &&
  442. !(DescRes ^ Resource))
  443. {
  444. Foundit = True;
  445. // Check that the open & deny modes do not clash with existing
  446. // settings
  447. if (((OpenMode & FORK_OPEN_READ) && (pOpenForkDesc->ofd_cDenyR > 0)) ||
  448. ((OpenMode & FORK_OPEN_WRITE) && (pOpenForkDesc->ofd_cDenyW > 0)) ||
  449. ((DenyMode & FORK_DENY_READ) && (pOpenForkDesc->ofd_cOpenR > 0)) ||
  450. ((DenyMode & FORK_DENY_WRITE) && (pOpenForkDesc->ofd_cOpenW > 0)))
  451. {
  452. Status = AFP_ERR_DENY_CONFLICT;
  453. }
  454. }
  455. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkDesc->ofd_Lock);
  456. if (Foundit)
  457. {
  458. break;
  459. }
  460. }
  461. if (ARGUMENT_PRESENT(ppOpenForkDesc))
  462. *ppOpenForkDesc = pOpenForkDesc;
  463. else RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  464. return Status;
  465. }
  466. /*** AfpForkOpen
  467. *
  468. * This is called after the fork has been successfully opened. Deny-mode conflicts are
  469. * checked and if no conflicts are found, appropriate data structures are created and
  470. * linked. If a deny conflict results, return NULL for pOpenForkEntry.
  471. *
  472. * LOCKS: AfpForksLock (SPIN), vds_VolLock (SPIN), cds_VolLock (SPIN), ofd_Lock (SPIN), ofe_Lock (SPIN)
  473. * LOCK_ORDER: vds_ExchangeFilesLock, then ofd_Lock after vds_VolLock
  474. * LOCKS_ASSUMED: vds_ExchangeFilesLock
  475. */
  476. AFPSTATUS
  477. AfpForkOpen(
  478. IN PSDA pSda,
  479. IN PCONNDESC pConnDesc,
  480. IN PPATHMAPENTITY pPME,
  481. IN PFILEDIRPARM pFDParm,
  482. IN DWORD AccessMode,
  483. IN BOOLEAN Resource,
  484. OUT POPENFORKENTRY * ppOpenForkEntry,
  485. OUT PBOOLEAN pCleanupExchgLock
  486. )
  487. {
  488. POPENFORKENTRY pOpenForkEntry;
  489. POPENFORKDESC pOpenForkDesc;
  490. PVOLDESC pVolDesc;
  491. AFPSTATUS Status = AFP_ERR_NONE;
  492. KIRQL OldIrql;
  493. BYTE OpenMode, DenyMode;
  494. BOOLEAN NewForkDesc = False;
  495. ASSERT(VALID_CONNDESC(pConnDesc));
  496. pVolDesc = pConnDesc->cds_pVolDesc;
  497. ASSERT(VALID_VOLDESC(pVolDesc));
  498. OpenMode = (BYTE)(AccessMode & FORK_OPEN_MASK);
  499. DenyMode = (BYTE)((AccessMode >> FORK_DENY_SHIFT) & FORK_DENY_MASK);
  500. *ppOpenForkEntry = NULL;
  501. if ((pOpenForkEntry = (POPENFORKENTRY)AfpAllocZeroedNonPagedMemory(sizeof(OPENFORKENTRY))) == NULL)
  502. return AFP_ERR_MISC;
  503. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  504. Status = AfpCheckDenyConflict(pVolDesc,
  505. pFDParm->_fdp_AfpId,
  506. Resource,
  507. OpenMode,
  508. DenyMode,
  509. &pOpenForkDesc);
  510. if (pOpenForkDesc == NULL)
  511. {
  512. // This fork has not been opened. We can party.
  513. if ((pOpenForkDesc = (POPENFORKDESC)AfpAllocZeroedNonPagedMemory(sizeof(OPENFORKDESC))) == NULL)
  514. Status = AFP_ERR_MISC;
  515. else
  516. {
  517. NewForkDesc = True;
  518. INITIALIZE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock);
  519. #if DBG
  520. pOpenForkDesc->Signature = OPENFORKDESC_SIGNATURE;
  521. #endif
  522. pOpenForkDesc->ofd_pVolDesc = pVolDesc;
  523. pOpenForkDesc->ofd_FileNumber = pFDParm->_fdp_AfpId;
  524. pOpenForkDesc->ofd_Flags = Resource ?
  525. OPEN_FORK_RESOURCE : OPEN_FORK_DATA;
  526. }
  527. }
  528. if ((pOpenForkDesc != NULL) && (Status == AFP_ERR_NONE))
  529. {
  530. // A lock is not needed if this is a new fork desc
  531. if (!NewForkDesc)
  532. {
  533. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkDesc->ofd_Lock);
  534. }
  535. pOpenForkDesc->ofd_UseCount ++;
  536. pOpenForkDesc->ofd_cOpenR += (OpenMode & FORK_OPEN_READ);
  537. pOpenForkDesc->ofd_cOpenW += (OpenMode & FORK_OPEN_WRITE);
  538. pOpenForkDesc->ofd_cDenyR += (DenyMode & FORK_DENY_READ);
  539. pOpenForkDesc->ofd_cDenyW += (DenyMode & FORK_DENY_WRITE);
  540. if (NewForkDesc)
  541. {
  542. // Now link this into the volume descriptor but only if it is a
  543. // new forkdesc. Explicitly reference the volume descriptor. We
  544. // cannot call AfpVolumeReference here since we already own the
  545. // volume lock Moreover since the connection is owning it, the
  546. // volume is OK. Initialize the volume relative path of the file
  547. // being opened from the PME.
  548. pOpenForkDesc->ofd_FilePath = pPME->pme_FullPath;
  549. pOpenForkDesc->ofd_FileName = pPME->pme_UTail;
  550. // Set the pme_FullPath to NULL so that it does not get freed up
  551. pPME->pme_FullPath.Buffer = NULL;
  552. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  553. ("AfpForksOpen: Initializing forkdesc with path %Z(%lx), name %Z(%lx)\n",
  554. &pOpenForkDesc->ofd_FilePath, pOpenForkDesc->ofd_FilePath.Buffer,
  555. &pOpenForkDesc->ofd_FileName, pOpenForkDesc->ofd_FileName.Buffer));
  556. pVolDesc->vds_RefCount ++;
  557. AfpLinkDoubleAtHead(pVolDesc->vds_pOpenForkDesc,
  558. pOpenForkDesc,
  559. ofd_Next,
  560. ofd_Prev);
  561. }
  562. else
  563. {
  564. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkDesc->ofd_Lock);
  565. }
  566. }
  567. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  568. if ((pOpenForkDesc == NULL) || (Status != AFP_ERR_NONE))
  569. {
  570. AfpFreeMemory(pOpenForkEntry);
  571. return Status;
  572. }
  573. ASSERT (Status == AFP_ERR_NONE);
  574. // All seems to be fine, so far. We'll go ahead and create the appropriate
  575. // data structures and link them in. In case of errors we'll back out.
  576. do
  577. {
  578. #if DBG
  579. pOpenForkEntry->Signature = OPENFORKENTRY_SIGNATURE;
  580. #endif
  581. INITIALIZE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock);
  582. pOpenForkEntry->ofe_pSda = pSda;
  583. if (AfpConnectionReferenceByPointer(pConnDesc) == NULL)
  584. {
  585. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_ERR,
  586. ("AfpForkOpen: couldn't reference pConnDesc\n"));
  587. AfpFreeMemory(pOpenForkEntry);
  588. return AFP_ERR_MISC;
  589. }
  590. pOpenForkEntry->ofe_pConnDesc = pConnDesc;
  591. pOpenForkEntry->ofe_pOpenForkDesc = pOpenForkDesc;
  592. pOpenForkEntry->ofe_OpenMode = OpenMode;
  593. pOpenForkEntry->ofe_DenyMode = DenyMode;
  594. pOpenForkEntry->ofe_FileSysHandle = pPME->pme_Handle;
  595. pOpenForkEntry->ofe_Flags = Resource ?
  596. OPEN_FORK_RESOURCE : OPEN_FORK_DATA;
  597. // One reference for creation and the other for the api to dereference.
  598. pOpenForkEntry->ofe_RefCount = 2;
  599. if (!afpForkGetNewForkRefNumAndLinkInSda(pSda, pOpenForkEntry))
  600. {
  601. AfpFreeMemory(pOpenForkEntry);
  602. AfpConnectionDereference(pConnDesc);
  603. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_ERR,("AfpForkOpen: ...LinkInSda failed\n"));
  604. return AFP_ERR_MISC;
  605. }
  606. // Now link this in global list
  607. ACQUIRE_SPIN_LOCK(&AfpForksLock, &OldIrql);
  608. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  609. pSda->sda_cOpenForks++;
  610. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  611. pOpenForkEntry->ofe_ForkId = afpNextForkId ++;
  612. AfpLinkDoubleAtHead(AfpOpenForksList,
  613. pOpenForkEntry,
  614. ofe_Next,
  615. ofe_Prev);
  616. AfpNumOpenForks ++;
  617. RELEASE_SPIN_LOCK(&AfpForksLock, OldIrql);
  618. if (NewForkDesc)
  619. {
  620. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  621. if ((Status = AfpSetDFFileFlags(pVolDesc,
  622. pFDParm->_fdp_AfpId,
  623. Resource ?
  624. DFE_FLAGS_R_ALREADYOPEN :
  625. DFE_FLAGS_D_ALREADYOPEN,
  626. False,
  627. False)) != AFP_ERR_NONE)
  628. {
  629. break;
  630. }
  631. }
  632. if (NT_SUCCESS(Status))
  633. {
  634. *ppOpenForkEntry = pOpenForkEntry;
  635. Status = AFP_ERR_NONE;
  636. }
  637. else
  638. {
  639. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  640. }
  641. } while (False);
  642. // Perform cleanup here, if we failed for any reason
  643. if (Status != AFP_ERR_NONE)
  644. {
  645. ASSERT (pOpenForkEntry != NULL);
  646. ACQUIRE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, &OldIrql);
  647. pOpenForkEntry->ofe_Flags |= OPEN_FORK_CLOSING;
  648. RELEASE_SPIN_LOCK(&pOpenForkEntry->ofe_Lock, OldIrql);
  649. // We must free this lock on behalf of AfpFspDispOpenFork because
  650. // the act of dereferencing it will end up calling ForkClose which
  651. // also must take this lock. Indicate to caller that he should not
  652. // attempt to release this lock again.
  653. AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
  654. *pCleanupExchgLock = False;
  655. // remove the refcount for the api (which won't see this pOpenForkEntry)
  656. AfpForkDereference(pOpenForkEntry);
  657. // remove the creation refcount
  658. AfpForkDereference(pOpenForkEntry);
  659. //
  660. // Dereferencing the open fork entry will close the handle passed
  661. // to us. NULL out the callers handle value so the caller does
  662. // not try to close it again.
  663. //
  664. pPME->pme_Handle.fsh_FileHandle = NULL;
  665. }
  666. return Status;
  667. }
  668. /*** AfpForkLockOperation
  669. *
  670. * Called for both ByteRangeLock/Unlock as well as Read/Write.
  671. * For Lock, a check is made to ensure the requested range does not
  672. * overlap an existing range FROM ANY OPEN FORK.
  673. * For Unlock, the requested range MUST MATCH exactly with an existing
  674. * locked range.
  675. * For IO, return the effective range where IO is possible - could be
  676. * potentially be an empty range. Note in this case that the start of
  677. * the range must be free to get a non-empty range. For an empty range
  678. * AFP_ERR_LOCK is returned. For a non-empty range AFP_ERR_NONE.
  679. *
  680. * Locks are maintained in a sorted (descending) order from the OpenForkDesc.
  681. * The search can be abandoned if the start of the requested range is
  682. * larger than the end of the encountered range.
  683. *
  684. * LOCKS: ofd_Lock (SPIN)
  685. */
  686. AFPSTATUS
  687. AfpForkLockOperation(
  688. IN PSDA pSda,
  689. IN POPENFORKENTRY pOpenForkEntry,
  690. IN OUT PFORKOFFST pOffset,
  691. IN OUT PFORKSIZE pSize,
  692. IN LOCKOP Operation, // LOCK, UNLOCK or IOCHECK
  693. IN BOOLEAN EndFlag // If True range is from end, else start
  694. )
  695. {
  696. POPENFORKDESC pOpenForkDesc;
  697. PFORKLOCK pForkLock, pForkLockNew, *ppForkLock;
  698. IO_STATUS_BLOCK IoStsBlk;
  699. PFAST_IO_DISPATCH pFastIoDisp;
  700. KIRQL OldIrql;
  701. AFPSTATUS Status;
  702. LONG Offset, Size;
  703. DWORD EndOff;
  704. BOOLEAN UnlockForkDesc = True;
  705. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  706. ("AfpForkLockOperation: (%s) - (%ld,%ld,%ld,%ld)\n",
  707. (Operation == LOCK) ? "Lock" : ((Operation == UNLOCK) ? "Unlock" : "Io"),
  708. pOffset->LowPart, pSize->LowPart,
  709. pOpenForkEntry->ofe_ForkId, pSda->sda_SessionId));
  710. if (EndFlag)
  711. {
  712. LONG Off;
  713. Size = pSize->LowPart;
  714. if (pSize->QuadPart < 0)
  715. {
  716. FORKSIZE FSize;
  717. FSize.QuadPart = -(pSize->QuadPart);
  718. Size = -(LONG)(FSize.LowPart);
  719. }
  720. Off = pOffset->LowPart;
  721. if (pOffset->QuadPart < 0)
  722. {
  723. FORKSIZE FOffset;
  724. FOffset.QuadPart = -(pOffset->QuadPart);
  725. Off = -(LONG)(FOffset.LowPart);
  726. }
  727. if ((Status = afpForkConvertToAbsOffSize(pOpenForkEntry,
  728. Off,
  729. &Size,
  730. pOffset)) != AFP_ERR_NONE)
  731. return Status;
  732. pSize->QuadPart = Size;
  733. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  734. ("AfpForkLockOperation: Effective (%s) - (%ld,%ld,%ld,%ld)\n",
  735. (Operation == LOCK) ? "Lock" : ((Operation == UNLOCK) ? "Unlock" : "Io"),
  736. pOffset->LowPart, Size,
  737. pOpenForkEntry->ofe_ForkId,
  738. pSda->sda_SessionId));
  739. }
  740. Offset = pOffset->LowPart;
  741. Size = pSize->LowPart;
  742. // Walk down the list and check. If the option is to lock, then no locks
  743. // should conflict. If the option is to unlock, then the lock should
  744. // exist and owned. If the option is to check for Io, then either the
  745. // overlapped range be 'owned' or the start of the range must not overap
  746. // OPTIMIZATION - if there is only one instance of this fork open, then
  747. // all locks belong to this fork and hence there can be no conflicts.
  748. pOpenForkDesc = pOpenForkEntry->ofe_pOpenForkDesc;
  749. ASSERT (pOpenForkDesc->ofd_UseCount > 0);
  750. if ((Operation == IOCHECK) &&
  751. (pOpenForkDesc->ofd_UseCount == 1))
  752. {
  753. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  754. ("AfpForkLockOperation: Skipping for IOCHECK - UseCount %ld ,Locks %ld\n",
  755. pOpenForkDesc->ofd_UseCount, pOpenForkDesc->ofd_NumLocks));
  756. return AFP_ERR_NONE;
  757. }
  758. // Set default error code.
  759. Status = (Operation == UNLOCK) ? AFP_ERR_RANGE_NOT_LOCKED : AFP_ERR_NONE;
  760. EndOff = (DWORD)Offset + (DWORD)Size - 1;
  761. ACQUIRE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock, &OldIrql);
  762. for (ppForkLock = &pOpenForkDesc->ofd_pForkLock;
  763. (pForkLock = *ppForkLock) != NULL;
  764. ppForkLock = &pForkLock->flo_Next)
  765. {
  766. DWORD LEndOff;
  767. // There are 4 possible ways locks can overlap
  768. //
  769. // 1 2
  770. // +-----------+ +-----------+
  771. // | | | |
  772. // | |
  773. // +-- LockRange --+
  774. // | |
  775. // | 3 |
  776. // +-------+
  777. // | 4 |
  778. // +-----------------------+
  779. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  780. ("AfpForkLockOperation: (%s) - Found (%ld,%ld,%ld,%ld)\n",
  781. (Operation == LOCK) ? "Lock" : ((Operation == UNLOCK) ? "Unlock" : "Io"),
  782. pForkLock->flo_Offset, pForkLock->flo_Size,
  783. pForkLock->flo_pOpenForkEntry->ofe_ForkId,
  784. pForkLock->flo_Key));
  785. // Calculate the end point of the current locked range
  786. LEndOff = (DWORD)(pForkLock->flo_Offset) + (DWORD)(pForkLock->flo_Size) - 1;
  787. // The list is ordered by descending flo_Offset. We can stop scanning
  788. // if the start of the requested range is more than the end of the
  789. // current locked range.
  790. if ((DWORD)Offset > LEndOff)
  791. {
  792. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  793. ("AfpForkLockOperation: %s Request (%ld, %ld) - Current (%ld,%ld), %s\n",
  794. (Operation == LOCK) ? "Lock" : ((Operation == UNLOCK) ? "Unlock" : "Io"),
  795. Offset, Size, pForkLock->flo_Offset, pForkLock->flo_Size,
  796. (Operation == UNLOCK) ? "failing" : "success"));
  797. break;
  798. }
  799. // The end of the requested range is beyond the locked range ?
  800. // continue scanning.
  801. if (EndOff < (DWORD)(pForkLock->flo_Offset))
  802. {
  803. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  804. ("AfpForkLockOperation: %s Request (%ld, %ld) - Current (%ld,%ld), skipping\n",
  805. (Operation == LOCK) ? "Lock" : ((Operation == UNLOCK) ? "Unlock" : "Io"),
  806. Offset, Size, pForkLock->flo_Offset,
  807. pForkLock->flo_Size,
  808. (Operation == UNLOCK) ? "failing" : "success"));
  809. continue;
  810. }
  811. // We have either a match or an overlap.
  812. if (Operation == LOCK)
  813. {
  814. // For a lock request it is a failure.
  815. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_WARN,
  816. ("AfpForkLockOperation: Lock Request (%ld, %ld) - Current (%ld,%ld), failing\n",
  817. Offset, Size, pForkLock->flo_Offset, pForkLock->flo_Size));
  818. Status = (pForkLock->flo_pOpenForkEntry == pOpenForkEntry) ?
  819. AFP_ERR_RANGE_OVERLAP : AFP_ERR_LOCK;
  820. }
  821. else if (Operation == UNLOCK)
  822. {
  823. // For an unlock request, we must have an exact match. Also the session key
  824. // and the OpenForkEntry must match
  825. if ((Offset == pForkLock->flo_Offset) &&
  826. (Size == pForkLock->flo_Size) &&
  827. (pForkLock->flo_Key == pSda->sda_SessionId) &&
  828. (pForkLock->flo_pOpenForkEntry == pOpenForkEntry))
  829. {
  830. // Unlink this lock from the list
  831. *ppForkLock = pForkLock->flo_Next;
  832. pOpenForkDesc->ofd_NumLocks --;
  833. pOpenForkEntry->ofe_cLocks --;
  834. RELEASE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock, OldIrql);
  835. UnlockForkDesc = False;
  836. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  837. ("AfpForkLockOperation: (Unlock) Deleting Range,Key (%ld,%ld,%ld,%ld)\n",
  838. Offset, Size, pOpenForkEntry->ofe_ForkId, pSda->sda_SessionId));
  839. // Try the fast I/O path first. If that fails, call AfpIoForkUnlock
  840. // to use the normal build-an-IRP path.
  841. pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
  842. if ((pFastIoDisp != NULL) &&
  843. (pFastIoDisp->FastIoUnlockSingle != NULL) &&
  844. pFastIoDisp->FastIoUnlockSingle(AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject),
  845. pOffset,
  846. pSize,
  847. AfpProcessObject,
  848. pSda->sda_SessionId,
  849. &IoStsBlk,
  850. pOpenForkEntry->ofe_pDeviceObject))
  851. {
  852. DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
  853. ("AfpForkLockOperation: Fast Unlock Succeeded\n"));
  854. #ifdef PROFILING
  855. // The fast I/O path worked. Update profile
  856. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
  857. #endif
  858. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrentFileLocks,
  859. (ULONG)-1,
  860. &AfpStatisticsLock);
  861. Status = AFP_ERR_NONE;
  862. }
  863. else
  864. {
  865. #ifdef PROFILING
  866. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
  867. #endif
  868. Status = AfpIoForkLockUnlock(pSda, pForkLock, pOffset, pSize, FUNC_UNLOCK);
  869. }
  870. AfpIOFreeBuffer(pForkLock);
  871. }
  872. else
  873. {
  874. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_WARN,
  875. ("AfpForkLockOperation: UnLock Request (%ld, %ld) - Current (%ld,%ld), failing\n",
  876. Offset, Size, pForkLock->flo_Offset, pForkLock->flo_Size));
  877. }
  878. }
  879. else
  880. {
  881. ASSERT (Operation == IOCHECK);
  882. // Check if this is a conflict
  883. if (pForkLock->flo_Key != pSda->sda_SessionId)
  884. {
  885. if ((Offset < pForkLock->flo_Offset) &&
  886. (EndOff >= (DWORD)(pForkLock->flo_Offset)))
  887. {
  888. pSize->LowPart = (pForkLock->flo_Offset - Offset);
  889. }
  890. else Status = AFP_ERR_LOCK;
  891. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  892. ("AfpForkLockOperation: Conflict found\n"));
  893. }
  894. else
  895. {
  896. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  897. ("AfpForkLockOperation: Our own lock found, ignoring\n"));
  898. }
  899. }
  900. break;
  901. }
  902. // We have the right status code. Do the needful
  903. if (Operation == LOCK)
  904. {
  905. if (Status == AFP_ERR_NONE)
  906. {
  907. Status = AFP_ERR_MISC;
  908. // Allocate the locks out of the pool.
  909. if ((pForkLockNew = (PFORKLOCK)AfpIOAllocBuffer(sizeof(FORKLOCK))) != NULL)
  910. {
  911. #if DBG
  912. pForkLockNew->Signature = FORKLOCK_SIGNATURE;
  913. #endif
  914. // Link this in such that the list is sorted in ascending order.
  915. // ppForkLock points to the place where the new lock will be
  916. // added, pForkLock is the next in the list.
  917. pForkLockNew->flo_Next = pForkLock;
  918. *ppForkLock = pForkLockNew;
  919. pForkLockNew->flo_Key = pSda->sda_SessionId;
  920. pForkLockNew->flo_pOpenForkEntry = pOpenForkEntry;
  921. pForkLockNew->flo_Offset = Offset;
  922. pForkLockNew->flo_Size = Size;
  923. pOpenForkDesc->ofd_NumLocks ++;
  924. pOpenForkEntry->ofe_cLocks ++;
  925. RELEASE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock, OldIrql);
  926. UnlockForkDesc = False;
  927. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  928. ("AfpForkLockOperation: Adding Range,Key (%ld,%ld,%ld,%ld)\n",
  929. Offset, Size,
  930. pOpenForkEntry->ofe_ForkId, pSda->sda_SessionId));
  931. // Try the fast I/O path first. If that fails, fall through to the
  932. // normal build-an-IRP path.
  933. pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
  934. if ((pFastIoDisp != NULL) &&
  935. (pFastIoDisp->FastIoLock != NULL) &&
  936. pFastIoDisp->FastIoLock(AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject),
  937. pOffset,
  938. pSize,
  939. AfpProcessObject,
  940. pSda->sda_SessionId,
  941. True, // Fail immediately
  942. True, // Exclusive
  943. &IoStsBlk,
  944. pOpenForkEntry->ofe_pDeviceObject))
  945. {
  946. if (NT_SUCCESS(IoStsBlk.Status) ||
  947. (IoStsBlk.Status == STATUS_LOCK_NOT_GRANTED))
  948. {
  949. DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
  950. ("AfpIoForkLock: Fast Lock Succeeded\n"));
  951. #ifdef PROFILING
  952. // The fast I/O path worked. Update profile
  953. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
  954. #endif
  955. if (IoStsBlk.Status == STATUS_LOCK_NOT_GRANTED)
  956. {
  957. Status = AFP_ERR_LOCK;
  958. }
  959. else
  960. {
  961. Status = AFP_ERR_NONE;
  962. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrentFileLocks,
  963. 1,
  964. &AfpStatisticsLock);
  965. }
  966. }
  967. }
  968. else
  969. {
  970. #ifdef PROFILING
  971. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
  972. #endif
  973. Status = AfpIoForkLockUnlock(pSda, pForkLockNew, pOffset, pSize, FUNC_LOCK);
  974. }
  975. if ((Status != AFP_ERR_NONE) &&
  976. (Status != AFP_ERR_EXTENDED) &&
  977. (Status != AFP_ERR_QUEUE))
  978. {
  979. // Undo the above work
  980. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_ERR,
  981. ("AfpForkLockOperation: AfpIoForkLock failed %lx, aborting for range %ld,%ld\n",
  982. Status, Offset, EndOff));
  983. AfpForkLockUnlink(pForkLockNew);
  984. }
  985. }
  986. }
  987. }
  988. if (UnlockForkDesc)
  989. RELEASE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock, OldIrql);
  990. return Status;
  991. }
  992. /*** AfpForkLockUnlink
  993. *
  994. * Unlink this lock from its open file descriptor and free it.
  995. */
  996. VOID
  997. AfpForkLockUnlink(
  998. IN PFORKLOCK pForkLock
  999. )
  1000. {
  1001. POPENFORKDESC pOpenForkDesc = pForkLock->flo_pOpenForkEntry->ofe_pOpenForkDesc;
  1002. PFORKLOCK * ppForkLock;
  1003. PFORKLOCK pTmpForkLock;
  1004. KIRQL OldIrql;
  1005. ACQUIRE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock, &OldIrql);
  1006. pOpenForkDesc->ofd_NumLocks --;
  1007. pForkLock->flo_pOpenForkEntry->ofe_cLocks --;
  1008. for (ppForkLock = &pOpenForkDesc->ofd_pForkLock;
  1009. (pTmpForkLock = *ppForkLock) != NULL;
  1010. ppForkLock = &pTmpForkLock->flo_Next)
  1011. {
  1012. if (*ppForkLock == pForkLock)
  1013. {
  1014. *ppForkLock = pForkLock->flo_Next;
  1015. break;
  1016. }
  1017. }
  1018. RELEASE_SPIN_LOCK(&pOpenForkDesc->ofd_Lock, OldIrql);
  1019. AfpIOFreeBuffer(pForkLock);
  1020. }
  1021. /*** afpForkConvertToAbsOffSize
  1022. *
  1023. * Convert the offset,size pair as supplied by the client to their absolute
  1024. * values.
  1025. */
  1026. LOCAL AFPSTATUS
  1027. afpForkConvertToAbsOffSize(
  1028. IN POPENFORKENTRY pOpenForkEntry,
  1029. IN LONG Offset,
  1030. IN OUT PLONG pSize,
  1031. OUT PFORKOFFST pAbsOffset
  1032. )
  1033. {
  1034. AFPSTATUS Status;
  1035. PAGED_CODE ();
  1036. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  1037. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  1038. ("afpForkConvertToAbsOffSize: Converting %ld, %ld\n", Offset, *pSize));
  1039. // We are relative to the end, then convert it to absolute
  1040. if ((Status = AfpIoQuerySize(&pOpenForkEntry->ofe_FileSysHandle,
  1041. pAbsOffset)) == AFP_ERR_NONE)
  1042. {
  1043. FORKOFFST EndRange, MaxOffset;
  1044. MaxOffset.QuadPart = Offset;
  1045. pAbsOffset->QuadPart += MaxOffset.QuadPart;
  1046. MaxOffset.QuadPart = MAXLONG;
  1047. // Now we have the *pAbsOffset and Size. Normalize the size.
  1048. // if the *pAbsOffset is > MAXLONG, refuse this.
  1049. if ((pAbsOffset->QuadPart > MaxOffset.QuadPart) ||
  1050. (pAbsOffset->QuadPart < 0))
  1051. Status = AFP_ERR_PARAM;
  1052. else
  1053. {
  1054. EndRange.QuadPart = pAbsOffset->QuadPart + *pSize;
  1055. if (EndRange.QuadPart >= MaxOffset.QuadPart)
  1056. *pSize = (MAXLONG - pAbsOffset->LowPart);
  1057. DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
  1058. ("afpForkConvertToAbsOffSize: Converted to %ld, %ld\n",
  1059. pAbsOffset->LowPart, *pSize));
  1060. Status = AFP_ERR_NONE;
  1061. }
  1062. }
  1063. return Status;
  1064. }
  1065. /*** AfpAdmWForkClose
  1066. *
  1067. * Close a fork forcibly. This is an admin operation and must be queued
  1068. * up since this can potentially cause filesystem operations that are valid
  1069. * only in the system process context.
  1070. */
  1071. AFPSTATUS
  1072. AfpAdmWForkClose(
  1073. IN OUT PVOID InBuf OPTIONAL,
  1074. IN LONG OutBufLen OPTIONAL,
  1075. OUT PVOID OutBuf OPTIONAL
  1076. )
  1077. {
  1078. PAFP_FILE_INFO pFileInfo = (PAFP_FILE_INFO)InBuf;
  1079. POPENFORKENTRY pOpenForkEntry;
  1080. DWORD ForkId;
  1081. AFPSTATUS Status = AFPERR_InvalidId;
  1082. if ((ForkId = pFileInfo->afpfile_id) != 0)
  1083. {
  1084. if ((pOpenForkEntry = AfpForkReferenceById(ForkId)) != NULL)
  1085. {
  1086. AfpForkClose(pOpenForkEntry);
  1087. AfpForkDereference(pOpenForkEntry);
  1088. Status = AFP_ERR_NONE;
  1089. }
  1090. }
  1091. else
  1092. {
  1093. BOOLEAN Shoot;
  1094. DWORD ForkId = MAXULONG;
  1095. KIRQL OldIrql;
  1096. Status = AFP_ERR_NONE;
  1097. while (True)
  1098. {
  1099. ACQUIRE_SPIN_LOCK(&AfpForksLock, &OldIrql);
  1100. for (pOpenForkEntry = AfpOpenForksList;
  1101. pOpenForkEntry != NULL;
  1102. pOpenForkEntry = pOpenForkEntry->ofe_Next)
  1103. {
  1104. if (pOpenForkEntry->ofe_ForkId > ForkId)
  1105. continue;
  1106. ForkId = pOpenForkEntry->ofe_ForkId;
  1107. Shoot = False;
  1108. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkEntry->ofe_Lock);
  1109. if (!(pOpenForkEntry->ofe_Flags & OPEN_FORK_CLOSING))
  1110. {
  1111. pOpenForkEntry->ofe_RefCount ++;
  1112. Shoot = True;
  1113. }
  1114. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkEntry->ofe_Lock);
  1115. if (Shoot)
  1116. {
  1117. RELEASE_SPIN_LOCK(&AfpForksLock, OldIrql);
  1118. AfpForkClose(pOpenForkEntry);
  1119. AfpForkDereference(pOpenForkEntry);
  1120. break;
  1121. }
  1122. }
  1123. if (pOpenForkEntry == NULL)
  1124. {
  1125. RELEASE_SPIN_LOCK(&AfpForksLock, OldIrql);
  1126. break;
  1127. }
  1128. }
  1129. }
  1130. return Status;
  1131. }
  1132. /*** afpForkGetNewForkRefNumAndLinkInSda
  1133. *
  1134. * Assign a new OForkRefNum to a fork that is being opened. The smallest one
  1135. * is always allocated. Make the right entry in the SDA point to the
  1136. * OpenForkEntry.
  1137. *
  1138. * LOCKS: sda_Lock (SPIN)
  1139. */
  1140. LOCAL BOOLEAN
  1141. afpForkGetNewForkRefNumAndLinkInSda(
  1142. IN PSDA pSda,
  1143. IN POPENFORKENTRY pOpenForkEntry
  1144. )
  1145. {
  1146. POPENFORKSESS pOpenForkSess;
  1147. KIRQL OldIrql;
  1148. USHORT i;
  1149. USHORT OForkRefNum = 1;
  1150. BOOLEAN Found = False;
  1151. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  1152. pOpenForkSess = &pSda->sda_OpenForkSess;
  1153. pOpenForkEntry->ofe_OForkRefNum = 0;
  1154. while (!Found)
  1155. {
  1156. for (i = 0; i < FORK_OPEN_CHUNKS; i++, OForkRefNum++)
  1157. {
  1158. if (pOpenForkSess->ofs_pOpenForkEntry[i] == NULL)
  1159. {
  1160. pOpenForkSess->ofs_pOpenForkEntry[i] = pOpenForkEntry;
  1161. pOpenForkEntry->ofe_OForkRefNum = OForkRefNum;
  1162. Found = True;
  1163. break;
  1164. }
  1165. }
  1166. if (!Found)
  1167. {
  1168. if (pOpenForkSess->ofs_Link != NULL)
  1169. {
  1170. pOpenForkSess = pOpenForkSess->ofs_Link;
  1171. continue;
  1172. }
  1173. if ((pOpenForkSess->ofs_Link = (POPENFORKSESS)AfpAllocZeroedNonPagedMemory(sizeof(OPENFORKSESS))) != NULL)
  1174. {
  1175. pOpenForkSess->ofs_Link->ofs_pOpenForkEntry[0] = pOpenForkEntry;
  1176. pOpenForkEntry->ofe_OForkRefNum = OForkRefNum;
  1177. Found = True;
  1178. }
  1179. break;
  1180. }
  1181. }
  1182. if (Found)
  1183. {
  1184. // Reference sda for this fork and up the MaxOForkRefNum, if needed
  1185. pSda->sda_RefCount ++;
  1186. if (OForkRefNum > pSda->sda_MaxOForkRefNum)
  1187. pSda->sda_MaxOForkRefNum = OForkRefNum;
  1188. }
  1189. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  1190. return Found;
  1191. }
  1192. /*** AfpExchangeForkAfpIds
  1193. *
  1194. * When an FpExchangeFiles occurs, if the data or resource fork of either
  1195. * of the 2 files being exchanged is open, we must fix up the AfpId kept
  1196. * in the OpenForkDesc structure. This is because when the final close
  1197. * is done on the fork, the cleanup code must clear the DFE_X_ALREADYOPEN
  1198. * flag in the corresponding DFEntry of the Idindex database.
  1199. *
  1200. * LOCKS: ofd_Lock (SPIN), vds_VolLock (SPIN)
  1201. * LOCK_ORDER: ofd_Lock after vds_VolLock
  1202. * LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Exclusive)
  1203. */
  1204. VOID
  1205. AfpExchangeForkAfpIds(
  1206. IN PVOLDESC pVolDesc,
  1207. IN DWORD AfpId1,
  1208. IN DWORD AfpId2
  1209. )
  1210. {
  1211. KIRQL OldIrql;
  1212. POPENFORKDESC pOpenForkDesc;
  1213. AFPSTATUS Status = AFP_ERR_NONE;
  1214. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1215. // check the list of open forks in this volume for the IDs specified
  1216. for (pOpenForkDesc = pVolDesc->vds_pOpenForkDesc;
  1217. pOpenForkDesc != NULL;
  1218. pOpenForkDesc = pOpenForkDesc->ofd_Next)
  1219. {
  1220. ACQUIRE_SPIN_LOCK_AT_DPC(&pOpenForkDesc->ofd_Lock);
  1221. if (pOpenForkDesc->ofd_FileNumber == AfpId1)
  1222. {
  1223. pOpenForkDesc->ofd_FileNumber = AfpId2;
  1224. }
  1225. else if (pOpenForkDesc->ofd_FileNumber == AfpId2)
  1226. {
  1227. pOpenForkDesc->ofd_FileNumber = AfpId1;
  1228. }
  1229. RELEASE_SPIN_LOCK_FROM_DPC(&pOpenForkDesc->ofd_Lock);
  1230. }
  1231. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1232. }
  1233.