kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp
branchRCL_3
changeset 43 c1f20ce4abcf
parent 42 a179b74831c9
child 44 3e88ff8f41d5
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Thu Aug 19 11:14:22 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Tue Aug 31 16:34:26 2010 +0300
@@ -67,7 +67,7 @@
 	enum TSwapState
 		{
 		EStateUnreserved = 0,	///< swap space not yet reserved, or page is being decommitted
-		EStateBlank      = 1,	///< swap page has never been written
+		EStateBlank      = 1,	///< swap page has never been written or the last write failed
 		EStateWritten    = 2,	///< swap page has been written out at least once
 		EStateWriting    = 3	///< swap page is in the process of being written out
 		};
@@ -157,26 +157,26 @@
 
 private:
 	/**
-	   The paging device used for accessing the backing store.
-	   This is set by #InstallPagingDevice.
+	The paging device used for accessing the backing store.
+	This is set by #InstallPagingDevice.
 	*/
 	DPagingDevice* iDevice;
 
 	/**
-	   The instance of #DSwapManager being used by this manager.
+	The instance of #DSwapManager being used by this manager.
 	*/
 	DSwapManager* iSwapManager;
 
 	/**
-	   Whether to read and write pages by physical address without mapping them first.
+	Whether to read and write pages by physical address without mapping them first.
 
-	   Set if the paging media driver supports it.
+	Set if the paging media driver supports it.
 	*/
 	TBool iUsePhysicalAccess;
 
 public:
 	/**
-	   The single instance of this manager class.
+	The single instance of this manager class.
 	*/
 	static DDataPagedMemoryManager TheManager;
 	};
@@ -187,9 +187,9 @@
 
 
 /**
-   Create a swap manager.
+Create a swap manager.
 
-   @param	aDevice	The demand paging device for access to the swap.
+@param	aDevice	The demand paging device for access to the swap.
 */
 TInt DSwapManager::Create(DPagingDevice* aDevice)
 	{
@@ -231,7 +231,7 @@
 inline DSwapManager::TSwapState DSwapManager::SwapState(TUint aSwapData)
 	{
 	TSwapState state = (TSwapState)(aSwapData & ESwapStateMask);
-	__NK_ASSERT_DEBUG(state >= EStateWritten || (aSwapData & ~ESwapStateMask) == 0);
+	__NK_ASSERT_DEBUG(state >= EStateBlank || aSwapData == 0);
 	return state;
 	}
 
@@ -244,18 +244,19 @@
 
 inline TUint DSwapManager::SwapData(TSwapState aSwapState, TInt aSwapIndex)
 	{
+	__NK_ASSERT_DEBUG(aSwapIndex < (1 << (32 - ESwapIndexShift)));
 	return (aSwapIndex << ESwapIndexShift) | aSwapState;
 	}
 
 
 /**
-   Allocate one or more page's worth of space within the swap area.
+Allocate one or more page's worth of space within the swap area.
 
-   The location is represented by a page-based index into the swap area.
+The location is represented by a page-based index into the swap area.
 
-   @param aCount The number of page's worth of space to allocate.
+@param aCount The number of page's worth of space to allocate.
 
-   @return The swap index of the first location allocated.
+@return The swap index of the first location allocated.
 */
 TInt DSwapManager::AllocSwapIndex(TUint aCount)
 	{
@@ -313,9 +314,9 @@
 
 
 /**
-   Free one page's worth of space within the swap area.
+Free one page's worth of space within the swap area.
 
-   The index must have been previously allocated with AllocSwapIndex().
+The index must have been previously allocated with AllocSwapIndex().
 */
 void DSwapManager::FreeSwapIndex(TInt aSwapIndex)
 	{
@@ -328,15 +329,15 @@
 
 
 /**
-   Reserve some swap pages for the requested region of the memory object
+Reserve some swap pages for the requested region of the memory object
 
-   @param aMemory		The memory object to reserve pages for.
-   @param aStartIndex	The page index in the memory object of the start of the region.
-   @param aPageCount	The number of pages to reserve.
+@param aMemory		The memory object to reserve pages for.
+@param aStartIndex	The page index in the memory object of the start of the region.
+@param aPageCount	The number of pages to reserve.
 
-   @return KErrNone on success, KErrNoMemory if not enough swap space available.
-   @pre aMemory's lock is held.
-   @post aMemory's lock is held.
+@return KErrNone on success, KErrNoMemory if not enough swap space available.
+@pre aMemory's lock is held.
+@post aMemory's lock is held.
 */
 TInt DSwapManager::ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
 	{
@@ -369,15 +370,15 @@
 
 
 /**
-   Unreserve swap pages for the requested region of the memory object.
+Unreserve swap pages for the requested region of the memory object.
 
-   @param aMemory		The memory object to unreserve pages for.
-   @param aStartIndex	The page index in the memory object of the start of the region.
-   @param aPageCount	The number of pages to unreserve.
+@param aMemory		The memory object to unreserve pages for.
+@param aStartIndex	The page index in the memory object of the start of the region.
+@param aPageCount	The number of pages to unreserve.
 
-   @return The number of pages freed.
-   @pre aMemory's lock is held.
-   @post aMemory's lock is held.
+@return The number of pages freed.
+@pre aMemory's lock is held.
+@post aMemory's lock is held.
 */
 TInt DSwapManager::UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
 	{
@@ -424,13 +425,13 @@
 
 
 /**
-   Determine whether the specified pages in the memory object have swap reserved for them.
+Determine whether the specified pages in the memory object have swap reserved for them.
 
-   @param aMemory		The memory object that owns the pages.
-   @param aStartIndex	The first index of the pages to check.
-   @param aPageCount	The number of pages to check.
+@param aMemory		The memory object that owns the pages.
+@param aStartIndex	The first index of the pages to check.
+@param aPageCount	The number of pages to check.
 
-   @return ETrue if swap is reserved for all the pages, EFalse otherwise.
+@return ETrue if swap is reserved for all the pages, EFalse otherwise.
 */
 TBool DSwapManager::IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
 	{// MmuLock required to protect manager data.
@@ -451,20 +452,19 @@
 
 
 /**
-   Read from the swap the specified pages associated with the memory object.
+Read from the swap the specified pages associated with the memory object.
 
-   @param aMemory 	The memory object to read the pages for
-   @param aIndex	The index of the first page within the memory object.
-   @param aCount	The number of pages to read.
-   @param aLinAddr	The address to copy the pages to.
-   @param aRequest	The request to use for the read.
-   @param aPhysAddrs	An array of the physical addresses for each page to read in.
+@param aMemory 	The memory object to read the pages for
+@param aIndex	The index of the first page within the memory object.
+@param aCount	The number of pages to read.
+@param aLinAddr	The address to copy the pages to.
+@param aRequest	The request to use for the read.
+@param aPhysAddrs	An array of the physical addresses for each page to read in.
 */
 TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs)
 	{
 	__ASSERT_CRITICAL;
 	
-	TInt r = KErrNone;
 	const TUint readUnitShift = iDevice->iReadUnitShift;
 	TUint readSize = KPageSize >> readUnitShift;
 	TThreadMessage message;
@@ -477,24 +477,36 @@
 		MmuLock::Lock();	// MmuLock required for atomic access to manager data.
 		TUint swapData = aMemory->PagingManagerData(index);
 		TSwapState state = SwapState(swapData);
+		TUint swapPage = SwapIndex(swapData);
 
 		if (state == EStateUnreserved)
-			{// This page is not committed to the memory object
+			{
+			// This page is not committed to the memory object
 			MmuLock::Unlock();
 			return KErrNotFound;			
 			}
 		else if (state == EStateBlank)
-			{// This page has not been written to yet so don't read from swap 
-			// just wipe it if required.
-			TUint allocFlags = aMemory->RamAllocFlags();
-			MmuLock::Unlock();
-			TBool wipePages = !(allocFlags & Mmu::EAllocNoWipe);
-			if (wipePages)
+			{
+			if (swapPage != 0)
+				{
+				// An error occured while writing the page out, so report it now
+				MmuLock::Unlock();
+				return -swapPage; 
+				}
+			else
 				{
-				TUint8 wipeByte = (allocFlags & Mmu::EAllocUseCustomWipeByte) ?
-					(allocFlags >> Mmu::EAllocWipeByteShift) & 0xff :
-					0x03;
-				memset((TAny*)aLinAddr, wipeByte, KPageSize);
+				// This page has not been written to yet so don't read from swap 
+				// just wipe it if required.
+				TUint allocFlags = aMemory->RamAllocFlags();
+				MmuLock::Unlock();
+				TBool wipePages = !(allocFlags & Mmu::EAllocNoWipe);
+				if (wipePages)
+					{
+					TUint8 wipeByte = (allocFlags & Mmu::EAllocUseCustomWipeByte) ?
+						(allocFlags >> Mmu::EAllocWipeByteShift) & 0xff :
+						0x03;
+					memset((TAny*)aLinAddr, wipeByte, KPageSize);
+					}
 				}
 			}
 		else
@@ -506,33 +518,35 @@
 			// OK to release as if the object's data is decommitted the pager 
 			// will check that data is still valid before mapping it.
 			MmuLock::Unlock();
-			TUint readStart = (SwapIndex(swapData) << KPageShift) >> readUnitShift;
+			TUint readStart = (swapPage << KPageShift) >> readUnitShift;
 			START_PAGING_BENCHMARK;
-			r = iDevice->Read(&message, aLinAddr, readStart, readSize, DPagingDevice::EDriveDataPaging);
+			TInt r = iDevice->Read(&message, aLinAddr, readStart, readSize, DPagingDevice::EDriveDataPaging);
+			END_PAGING_BENCHMARK(EPagingBmReadDataMedia);
+			__NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore shouldn't fail with KErrNoMemory
 			if (r != KErrNone)
-				__KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::ReadSwapPages: error reading media at %08x + %x: %d", readStart << readUnitShift, readSize << readUnitShift, r));				
-			__NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory
-			END_PAGING_BENCHMARK(EPagingBmReadDataMedia);
-			__NK_ASSERT_ALWAYS(r == KErrNone);
+				__KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::ReadSwapPages: error reading media at %08x + %x: %d", readStart << readUnitShift, readSize << readUnitShift, r));
+			r = ThePager.EmbedErrorContext(EPagingErrorContextDataRead, r);
+			if (r != KErrNone)
+				return r;
 			}
 		END_PAGING_BENCHMARK(EPagingBmReadDataPage);
 		}
-
-	return r;
+	
+	return KErrNone;
 	}
 
 
 /**
-   Write the specified memory object's pages from the RAM into the swap.
+Write the specified memory object's pages from the RAM into the swap.
 
-   @param	aMemory		The memory object who owns the pages.
-   @param	aIndex		The index within the memory object.
-   @param 	aCount		The number of pages to write out.
-   @param	aLinAddr	The location of the pages to write out.
-   @param  aBackground Whether this is being called in the background by the page cleaning thread
-   as opposed to on demand when a free page is required.
+@param	aMemory		The memory object who owns the pages.
+@param	aIndex		The index within the memory object.
+@param 	aCount		The number of pages to write out.
+@param	aLinAddr	The location of the pages to write out.
+@param  aBackground Whether this is being called in the background by the page cleaning thread
+                    as opposed to on demand when a free page is required.
 
-   @pre Called with page cleaning lock held
+@pre Called with page cleaning lock held
 */
 TInt DSwapManager::WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs, TBool aBackground)
 	{
@@ -626,14 +640,16 @@
 		r = iDevice->WritePhysical(&msg, aPhysAddrs, aCount, writeOffset, aBackground);
 	else
 		r = iDevice->Write(&msg, aLinAddr + (aPageIndex << KPageShift), writeOffset, writeSize, aBackground);
+	END_PAGING_BENCHMARK(EPagingBmWriteDataMedia);
 		
 	if (r != KErrNone)
 		{
 		__KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::WriteSwapPages: error writing media from %08x to %08x + %x: %d", aLinAddr, writeOffset << readUnitShift, writeSize << readUnitShift, r));
+		if (r > 0)
+			r = KErrGeneral;
 		}
 	__NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory
-	__NK_ASSERT_ALWAYS(r == KErrNone);
-	END_PAGING_BENCHMARK(EPagingBmWriteDataMedia);
+	r = ThePager.EmbedErrorContext(EPagingErrorContextDataWrite, r); 
 
 	TUint i;
 	TUint swapData[KMaxPagesToClean];
@@ -647,8 +663,12 @@
 		__NK_ASSERT_DEBUG(s == EStateUnreserved || s == EStateWriting);
 		if (s == EStateWriting)
 			{
-			// Store the new swap location and mark the page as saved.
-			aMemory[i]->SetPagingManagerData(aIndex[i], SwapData(EStateWritten, aSwapIndex + i));
+			// Store the new swap location and mark the page as saved, or if an error occured then
+			// record the error code instead
+			TUint swapData = (r == KErrNone) 
+				? SwapData(EStateWritten, aSwapIndex + i)
+				: SwapData(EStateBlank, -r);
+			aMemory[i]->SetPagingManagerData(aIndex[i], swapData);
 			}
 		}
 	MmuLock::Unlock();
@@ -656,15 +676,17 @@
 	for (i = 0 ; i < aCount ; ++i)
 		{
 		TSwapState s = SwapState(swapData[i]);
-		if (s == EStateUnreserved)
+		if (s == EStateUnreserved || s == EStateBlank)
 			{
-			// The page was decommitted while we were cleaning it, so free the swap page we
-			// allocated and continue, leaving this page in the unreserved state.
+			// The page was either decommitted while we were cleaning it, or an error occured while
+			// writing.  Free the swap page and don't modify the state.
 			FreeSwapIndex(aSwapIndex + i);
 			}
 		}
 
-	return KErrNone;
+	// write errors are not reported at this point as this will just kill a thread unrelated to the
+	// one whose data has been lost
+	return KErrNone;  
 	}