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.

589 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: page.cxx
  7. //
  8. // Contents: Paging code for MSF
  9. //
  10. // Classes: Defined in page.hxx
  11. //
  12. // Functions:
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "msfhead.cxx"
  16. #include "mread.hxx"
  17. //+---------------------------------------------------------------------
  18. //
  19. // Member: CMSFPage::Byteswap, public
  20. //
  21. // Synopsis: Byteswap the elments of the page
  22. //
  23. // Algorithm: Call the corresponding byteswap routine depending on the
  24. // actual type of the Mutli-stream.
  25. //
  26. //----------------------------------------------------------------------
  27. void CMSFPage::ByteSwap(void)
  28. {
  29. CPagedVector* pVect = GetVector();
  30. if (pVect->GetParent()->GetHeader()->DiffByteOrder())
  31. {
  32. switch (_sid)
  33. {
  34. case SIDDIR:
  35. ((CDirSect *)_ab)->
  36. ByteSwap( ((CDirVector*)pVect)->GetSectorSize() );
  37. break;
  38. case SIDFAT:
  39. case SIDMINIFAT:
  40. case SIDDIF:
  41. ((CFatSect *)_ab)->
  42. ByteSwap( ((CFatVector*)pVect)->GetSectBlock() );
  43. break;
  44. default:
  45. break;
  46. }
  47. }
  48. }
  49. //+---------------------------------------------------------------------------
  50. //
  51. // Member: CMSFPageTable::CMSFPageTable, public
  52. //
  53. // Synopsis: CMSFPageTable constructor.
  54. //
  55. // Arguments: [pmsParent] -- Pointer to multistream for this page table.
  56. //
  57. // Notes:
  58. //
  59. //----------------------------------------------------------------------------
  60. CMSFPageTable::CMSFPageTable( CMStream *const pmsParent,
  61. const ULONG cMinPages,
  62. const ULONG cMaxPages)
  63. : _pmsParent(pmsParent), _cActivePages(0), _cPages(0),
  64. _pmpCurrent(NULL),
  65. _cbSector(pmsParent->GetSectorSize()),
  66. _cMinPages(cMinPages), _cMaxPages(cMaxPages),
  67. _cReferences(1)
  68. {
  69. }
  70. //+---------------------------------------------------------------------------
  71. //
  72. // Member: CMSFPage::CMSFPage, public
  73. //
  74. // Synopsis: CMSFPage default constructor
  75. //
  76. //----------------------------------------------------------------------------
  77. CMSFPage::CMSFPage(CMSFPage *pmp)
  78. {
  79. if (pmp == NULL)
  80. {
  81. SetChain(this, this);
  82. }
  83. else
  84. {
  85. SetChain(pmp->GetPrev(), pmp);
  86. GetPrev()->SetNext(this);
  87. GetNext()->SetPrev(this);
  88. }
  89. SetSid(NOSTREAM);
  90. SetOffset(0);
  91. SetSect(ENDOFCHAIN);
  92. SetFlags(0);
  93. SetVector(NULL);
  94. _cReferences = 0;
  95. }
  96. //+---------------------------------------------------------------------------
  97. //
  98. // Member: CMSFPageTable::~CMSFPageTable, public
  99. //
  100. // Synopsis: CMSFPageTable destructor
  101. //
  102. //----------------------------------------------------------------------------
  103. CMSFPageTable::~CMSFPageTable()
  104. {
  105. if (_pmpCurrent != NULL)
  106. {
  107. CMSFPage *pmp = _pmpCurrent;
  108. CMSFPage *pmpNext;
  109. while (pmp != pmp->GetNext())
  110. {
  111. pmpNext = pmp->GetNext();
  112. #if DBG == 1
  113. msfAssert(!pmp->IsInUse() &&
  114. aMsg("Active page left at page table destruct time."));
  115. #endif
  116. delete pmp;
  117. pmp = pmpNext;
  118. }
  119. delete pmp;
  120. }
  121. }
  122. //+---------------------------------------------------------------------------
  123. //
  124. // Member: CMSFPageTable::Init, public
  125. //
  126. // Synopsis: Initialize a CMSFPageTable
  127. //
  128. // Arguments: [cPages] -- Number of pages to preallocate.
  129. //
  130. // Returns: Appropriate status code
  131. //
  132. // Notes:
  133. //
  134. //----------------------------------------------------------------------------
  135. SCODE CMSFPageTable::Init(void)
  136. {
  137. SCODE sc = S_OK;
  138. msfDebugOut((DEB_ITRACE, "In CMSFPageTable::Init:%p()\n", this));
  139. for (ULONG i = 0; i < _cMinPages; i++)
  140. {
  141. CMSFPage *pmp;
  142. msfMem(pmp = GetNewPage());
  143. _pmpCurrent = pmp;
  144. }
  145. _cPages = _cMinPages;
  146. _cActivePages = 0;
  147. msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::Init\n"));
  148. Err:
  149. return sc;
  150. }
  151. //+---------------------------------------------------------------------------
  152. //
  153. // Member: CMSFPageTable::FlushPage, public
  154. //
  155. // Synopsis: Flush a page
  156. //
  157. // Arguments: [pmp] -- Pointer to page to flush
  158. //
  159. // Returns: Appropriate status code
  160. //
  161. //----------------------------------------------------------------------------
  162. SCODE CMSFPageTable::FlushPage(CMSFPage *pmp)
  163. {
  164. SCODE sc = S_OK;
  165. pmp->AddRef();
  166. CMStream *pms;
  167. pms = pmp->GetVector()->GetParent();
  168. //Flush the page, reset the dirty bit.
  169. msfAssert((pmp->GetSect() != ENDOFCHAIN) &&
  170. aMsg("Page location not set - don't know where to flush to."));
  171. ULONG ulRet;
  172. ILockBytes *pilb;
  173. ULARGE_INTEGER ul;
  174. ul.QuadPart = ConvertSectOffset(
  175. pmp->GetSect(),
  176. 0,
  177. pms->GetSectorShift());
  178. pilb = pms->GetILB();
  179. pmp->ByteSwap(); // convert to disk format
  180. // (if neccessary)
  181. msfHChk(pilb->WriteAt(
  182. ul,
  183. (BYTE *)(pmp->GetData()),
  184. _cbSector,
  185. &ulRet));
  186. pmp->ByteSwap(); // convert to back to machine format
  187. // (if neccessary)
  188. pmp->ResetDirty();
  189. Err:
  190. pmp->Release();
  191. return sc;
  192. }
  193. //+---------------------------------------------------------------------------
  194. //
  195. // Member: CMSFPageTable::GetFreePage, public
  196. //
  197. // Synopsis: Return a pointer to a free page.
  198. //
  199. // Arguments: [ppmp] -- Pointer to storage for return pointer
  200. //
  201. // Returns: Appropriate status code
  202. //
  203. // Notes:
  204. //
  205. //----------------------------------------------------------------------------
  206. SCODE CMSFPageTable::GetFreePage(CMSFPage **ppmp)
  207. {
  208. SCODE sc = S_OK;
  209. CMSFPage *pmp;
  210. if (_cPages > _cActivePages)
  211. {
  212. //We have some unused page already allocated. Find and return it.
  213. pmp = _pmpCurrent;
  214. do
  215. {
  216. pmp = pmp->GetNext();
  217. }
  218. while ((pmp != _pmpCurrent) && (pmp->GetSid() != NOSTREAM));
  219. msfAssert((pmp->GetSid() == NOSTREAM) &&
  220. aMsg("Expected empty page, none found."));
  221. *ppmp = pmp;
  222. _cActivePages++;
  223. }
  224. else if (_cPages == _cMaxPages)
  225. {
  226. msfMem(pmp = FindSwapPage());
  227. msfDebugOut((DEB_IERROR, "Got swap page %p\n",pmp));
  228. msfAssert((pmp->GetVector() != NULL) &&
  229. aMsg("FindSwapPage returned unowned page."));
  230. msfDebugOut((DEB_IERROR, "Freeing page %lu from vector %p\n",
  231. pmp->GetOffset(), pmp->GetVector()));
  232. if (pmp->IsDirty())
  233. {
  234. msfChk(FlushPage(pmp));
  235. msfAssert(!pmp->IsDirty() &&
  236. aMsg("Page remained dirty after flush call"));
  237. }
  238. pmp->GetVector()->FreeTable(pmp->GetOffset());
  239. #if DBG == 1
  240. pmp->SetVector(NULL);
  241. #endif
  242. *ppmp = pmp;
  243. }
  244. else
  245. {
  246. //Create a new page and return it.
  247. pmp = GetNewPage();
  248. if (pmp != NULL)
  249. {
  250. *ppmp = pmp;
  251. _cActivePages++;
  252. _cPages++;
  253. }
  254. else
  255. {
  256. msfMem(pmp = FindSwapPage());
  257. if (pmp->IsDirty())
  258. {
  259. msfChk(FlushPage(pmp));
  260. msfAssert(!pmp->IsDirty() &&
  261. aMsg("Page remained dirty after flush call"));
  262. }
  263. pmp->GetVector()->FreeTable(pmp->GetOffset());
  264. #if DBG == 1
  265. pmp->SetVector(NULL);
  266. #endif
  267. *ppmp = pmp;
  268. }
  269. }
  270. Err:
  271. return sc;
  272. }
  273. //+---------------------------------------------------------------------------
  274. //
  275. // Member: CMSFPageTable::FindPage, public
  276. //
  277. // Synopsis: Find and return a given page
  278. //
  279. // Arguments: [ppv] -- Pointer to vector of page to return
  280. // [sid] -- SID of page to return
  281. // [ulOffset] -- Offset of page to return
  282. // [ppmp] -- Location to return pointer
  283. //
  284. // Returns: Appropriate status code
  285. //
  286. // Notes:
  287. //
  288. //----------------------------------------------------------------------------
  289. SCODE CMSFPageTable::FindPage(
  290. CPagedVector *ppv,
  291. SID sid,
  292. ULONG ulOffset,
  293. CMSFPage **ppmp)
  294. {
  295. SCODE sc;
  296. CMSFPage *pmp = _pmpCurrent;
  297. do
  298. {
  299. if ((pmp->GetVector() == ppv) && (pmp->GetOffset() == ulOffset))
  300. {
  301. //Bingo!
  302. *ppmp = pmp;
  303. return STG_S_FOUND;
  304. }
  305. pmp = pmp->GetNext();
  306. }
  307. while (pmp != _pmpCurrent);
  308. //The page isn't currently in memory. Get a free page and
  309. //bring it into memory.
  310. msfChk(GetFreePage(&pmp));
  311. msfAssert((pmp->GetVector() == NULL) &&
  312. aMsg("Attempting to reassign owned page."));
  313. pmp->SetVector(ppv);
  314. pmp->SetSid(sid);
  315. pmp->SetOffset(ulOffset);
  316. pmp->SetSect(ENDOFCHAIN);
  317. *ppmp = pmp;
  318. Err:
  319. return sc;
  320. }
  321. //+---------------------------------------------------------------------------
  322. //
  323. // Member: CMSFPageTable::GetPage, public
  324. //
  325. // Synopsis: Find and return a given page
  326. //
  327. // Arguments: [sid] -- SID of page to return
  328. // [ulOffset] -- Offset of page to return
  329. // [ppmp] -- Location to return pointer
  330. //
  331. // Returns: Appropriate status code
  332. //
  333. // Notes:
  334. //
  335. //----------------------------------------------------------------------------
  336. SCODE CMSFPageTable::GetPage(
  337. CPagedVector *ppv,
  338. SID sid,
  339. ULONG ulOffset,
  340. CMSFPage **ppmp)
  341. {
  342. SCODE sc;
  343. *ppmp = NULL;
  344. msfChk(FindPage(ppv, sid, ulOffset, ppmp));
  345. (*ppmp)->AddRef();
  346. if (sc != STG_S_FOUND)
  347. {
  348. ULONG ulRet;
  349. SECT sect;
  350. msfChk(ppv->GetParent()->GetSect(sid, ulOffset, &sect));
  351. (*ppmp)->SetSect(sect);
  352. CMStream *pms = (*ppmp)->GetVector()->GetParent();
  353. ULARGE_INTEGER ul;
  354. ul.QuadPart = ConvertSectOffset(
  355. (*ppmp)->GetSect(),
  356. 0,
  357. pms->GetSectorShift());
  358. msfAssert(pms->GetILB() != NULL &&
  359. aMsg("NULL ILockBytes - missing SetAccess?"));
  360. msfHChk(pms->GetILB()->ReadAt(ul, (BYTE *)((*ppmp)->GetData()),
  361. _cbSector, &ulRet));
  362. (*ppmp)->ByteSwap();
  363. }
  364. Err:
  365. if (*ppmp != NULL)
  366. {
  367. (*ppmp)->Release();
  368. }
  369. return sc;
  370. }
  371. //+---------------------------------------------------------------------------
  372. //
  373. // Member: CMSFPageTable::ReleasePage, public
  374. //
  375. // Synopsis: Release a given page
  376. //
  377. // Arguments: [sid] -- SID of page to release
  378. // [ulOffset] -- Offset of page to release
  379. //
  380. //----------------------------------------------------------------------------
  381. void CMSFPageTable::ReleasePage(CPagedVector *ppv, SID sid, ULONG ulOffset)
  382. {
  383. SCODE sc;
  384. CMSFPage *pmp;
  385. sc = FindPage(ppv, sid, ulOffset, &pmp);
  386. if (SUCCEEDED(sc))
  387. {
  388. pmp->Release();
  389. }
  390. }
  391. //+---------------------------------------------------------------------------
  392. //
  393. // Member: CMSFPageTable::Flush, public
  394. //
  395. // Synopsis: Flush dirty pages to disk
  396. //
  397. // Returns: Appropriate status code
  398. //
  399. //----------------------------------------------------------------------------
  400. SCODE CMSFPageTable::Flush(void)
  401. {
  402. SCODE sc = S_OK;
  403. CMSFPage *pmp = _pmpCurrent;
  404. //We use pmpLast in case FlushPage changes _pmpCurrent.
  405. CMSFPage *pmpLast = _pmpCurrent;
  406. do
  407. {
  408. if ((pmp->IsDirty()) && !(pmp->IsInUse()))
  409. {
  410. msfChk(FlushPage(pmp));
  411. }
  412. pmp = pmp->GetNext();
  413. }
  414. while (pmp != pmpLast);
  415. Err:
  416. return sc;
  417. }
  418. //+---------------------------------------------------------------------------
  419. //
  420. // Member: CMSFPageTable::FreePages, public
  421. //
  422. // Synopsis: Free all the pages associated with a vector.
  423. //
  424. // Arguments: [ppv] -- Pointer to vector to free pages for.
  425. //
  426. //----------------------------------------------------------------------------
  427. void CMSFPageTable::FreePages(CPagedVector *ppv)
  428. {
  429. CMSFPage *pmp = _pmpCurrent;
  430. do
  431. {
  432. if (pmp->GetVector() == ppv)
  433. {
  434. pmp->SetSid(NOSTREAM);
  435. pmp->SetVector(NULL);
  436. pmp->ResetDirty();
  437. _cActivePages--;
  438. }
  439. pmp = pmp->GetNext();
  440. }
  441. while (pmp != _pmpCurrent);
  442. }
  443. //+---------------------------------------------------------------------------
  444. //
  445. // Member: CMSFPageTable::FindSwapPage, private
  446. //
  447. // Synopsis: Find a page to swap out.
  448. //
  449. // Arguments: None.
  450. //
  451. // Returns: Pointer to page to swap out.
  452. //
  453. //----------------------------------------------------------------------------
  454. CMSFPage * CMSFPageTable::FindSwapPage(void)
  455. {
  456. #if DBG == 1
  457. ULONG cpInUse = 0;
  458. #endif
  459. while (TRUE)
  460. {
  461. if (!_pmpCurrent->IsInUse())
  462. {
  463. DWORD dwFlags;
  464. dwFlags = _pmpCurrent->GetFlags();
  465. _pmpCurrent->SetFlags(dwFlags & ~FB_TOUCHED);
  466. _pmpCurrent = _pmpCurrent->GetNext();
  467. if (!(dwFlags & FB_TOUCHED))
  468. {
  469. return _pmpCurrent->GetPrev();
  470. }
  471. }
  472. else
  473. {
  474. _pmpCurrent = _pmpCurrent->GetNext();
  475. }
  476. #if DBG == 1
  477. cpInUse++;
  478. msfAssert((cpInUse < 3 * _cPages) &&
  479. aMsg("No swappable pages."));
  480. #endif
  481. }
  482. }