sl@0: // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32test\demandpaging\t_fragment.cpp sl@0: // This test exercises the fragmentation of write requests carried out sl@0: // by the Local Media subsystem, when the request is for a partition sl@0: // driven by a Media driver that supports paging. sl@0: // 002 Check if LFFS drive (Mount LFFS if required) sl@0: // 003 Testing Fragmentation of writes to writable drives in paging media sl@0: // 004 Testing concurrent Fragmentation of writes on the same media sl@0: // 005 Check Disk sl@0: // sl@0: // sl@0: sl@0: //! @SYMTestCaseID KBASE-T_FRAGMENTDP-0333 sl@0: //! @SYMTestType UT sl@0: //! @SYMPREQ PREQ1110 sl@0: //! @SYMTestCaseDesc Demand Paging Page cache fragmentation tests. sl@0: //! @SYMTestActions 001 Starting tests... sl@0: //! @SYMTestExpectedResults All tests should pass. sl@0: //! @SYMTestPriority High sl@0: //! @SYMTestStatus Implemented sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "t_server.h" sl@0: #include sl@0: #include sl@0: #include sl@0: #include "testdefs.h" sl@0: sl@0: #ifdef __VC32__ sl@0: // Solve compilation problem caused by non-English locale sl@0: #pragma setlocale("english") sl@0: #endif sl@0: sl@0: const TInt KMuliplySize=10; sl@0: const TInt KFileSizeInBytes=302498; sl@0: sl@0: LOCAL_D TBuf8 Buffer; sl@0: LOCAL_D RSemaphore WriteSemaphore; sl@0: sl@0: GLDEF_D RTest test(_L("T_FRAGMENTDP")); sl@0: sl@0: void DoTestF(TInt aDrvNum, TBool aNand); // may want to do something weird on NAND later (e.g. trigger Garbage Collection) sl@0: void DoTestC(TInt aDrvNum, TInt aNotherDrvNum, TBool aNand); // may want to do something weird on NAND later (e.g. trigger Garbage Collection) sl@0: TInt CreateEmptyFile(RFs& aFs, const TDesC& aFileName, TUint aFileSize); sl@0: TInt GetLocDrvNumber(TInt aDrvNo); sl@0: sl@0: /* sl@0: This plain looking test exercises the fragmentation of write requests carried out by the Local sl@0: Media subsystem, when the request is for a partition driven by a Media driver that supports sl@0: paging. sl@0: It indirectly tests that the ELOCD fragmentation and EKERN locking mechanisms work as specified sl@0: to prevent deadlocks. It also causes an awful lot of paging activity. sl@0: */ sl@0: sl@0: LOCAL_C TBool TestSimpleFragmentation() sl@0: // sl@0: // Find ROM address of file and write from it to another file in writable partition in the same media as the backing store for ROM sl@0: // sl@0: sl@0: { sl@0: TDriveInfo driveInfo; sl@0: TBool tested=EFalse; sl@0: sl@0: TFileName path; sl@0: TInt r=TheFs.SessionPath(path); sl@0: test(r==KErrNone); sl@0: TInt drv; sl@0: r=RFs::CharToDrive(path[0],drv); sl@0: test(r==KErrNone); sl@0: sl@0: test(TheFs.Drive(driveInfo, drv) == KErrNone); sl@0: sl@0: //-- select a suitable drive for the testing. It shall be a writable drive on a media that services paging sl@0: if(driveInfo.iMediaAtt&KMediaAttPageable) sl@0: { sl@0: TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected; // skip ROFS partitions sl@0: if(!readOnly) sl@0: { sl@0: DoTestF(drv, (driveInfo.iType==EMediaNANDFlash)?(TBool)ETrue:(TBool)EFalse); sl@0: tested=ETrue; sl@0: } sl@0: } sl@0: if(!tested) sl@0: test.Printf(_L("Skipped T_FRAGMENTDP on drive %c\n"), path[0]); sl@0: return tested; sl@0: } sl@0: sl@0: sl@0: void DoTestF(TInt aDrvNum, TBool aNand) sl@0: { sl@0: TInt pos=0; sl@0: TInt size, size1; sl@0: TInt r; sl@0: TFileName fileName; sl@0: sl@0: test.Next(_L("Testing Fragmentation of writes to writable drives in paging media")); sl@0: if(aNand) sl@0: test.Printf(_L("Testing on NAND\n")); sl@0: sl@0: fileName.Format(_L("Testing drive %c:\n"), 'A'+aDrvNum); sl@0: test.Printf(fileName); sl@0: sl@0: _LIT(KTPagedCpp, "Z:\\test\\TEST_PAGED.cpp"); sl@0: _LIT(KTUnpagedCpp, "Z:\\test\\TEST_UNPAGED.CPP"); sl@0: sl@0: if(TheFs.IsFileInRom(KTPagedCpp) != NULL && TheFs.IsFileInRom(KTUnpagedCpp) != NULL) // .oby must include these files sl@0: { sl@0: RFile f; sl@0: r=f.Open(TheFs,KTUnpagedCpp,EFileStream); sl@0: test(r==KErrNone); sl@0: r=f.Seek(ESeekAddress,pos); sl@0: test(r==KErrNone); sl@0: TText8* ptrPos=*(TText8**)&pos; // start address of unpaged file in ROM sl@0: test.Printf(_L("Start address of section to copy 0x%x\n"), ptrPos); sl@0: sl@0: r=f.Size(size); // size of unpaged file sl@0: test(r==KErrNone); sl@0: size+=((~(size&0xf)&0xf)+1); // adjust for ROM alignement (EABI, 8 bytes) sl@0: f.Close(); sl@0: sl@0: r=f.Open(TheFs,KTPagedCpp,EFileStream); sl@0: test(r==KErrNone); sl@0: r=f.Size(size1); // size of paged file sl@0: test(r==KErrNone); sl@0: size1+=((~(size1&0xf)&0xf)+1); // adjust for ROM alignement (EABI, 8 bytes) sl@0: f.Close(); sl@0: sl@0: size+=size1; sl@0: test.Printf(_L("Set descriptor with size %d (paged+unpaged sections+ROMFS padding)\n"), size); sl@0: TPtrC8 ptr(ptrPos,size); sl@0: sl@0: fileName.Format(_L("%c:\\TestFragFile.bin"), aDrvNum+'A'); sl@0: TheFs.Delete(fileName); //-- just in case sl@0: sl@0: test.Printf(_L("Create and open destination file\n")); sl@0: r = CreateEmptyFile(TheFs, fileName, (size)); // create file to hold both sizes sl@0: test(r == KErrNone); sl@0: r=f.Open(TheFs,fileName,EFileRead|EFileWrite); sl@0: test(r == KErrNone); sl@0: sl@0: test.Printf(_L("Attempt to flush paged section\n")); sl@0: TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); sl@0: if(r==KErrNotSupported) sl@0: test.Printf(_L("Not Supported\n")); sl@0: sl@0: test.Printf(_L("Write paged and unpaged sections, synchronoulsy\n")); sl@0: r=f.Write(ptr); sl@0: test(r==KErrNone); sl@0: sl@0: test.Printf(_L("Read back and compare\n")); sl@0: pos=0; sl@0: r=f.Seek(ESeekStart,pos); sl@0: test(r==KErrNone); sl@0: TUint end=(TUint)ptrPos+(size); sl@0: TBuf8<1024> readBuf; sl@0: TPtrC8 memBuf(ptrPos,1024); sl@0: sl@0: while((TUint)ptrPos+1024 driveBuf=_L("?:\\"); sl@0: RFormat format; sl@0: TInt count; sl@0: sl@0: driveBuf[0] = (TText)(driveNo + 'A'); sl@0: sl@0: TInt r = format.Open(TheFs, driveBuf, EHighDensity, count); sl@0: test(r == KErrNone); sl@0: sl@0: while(count) sl@0: { sl@0: r=format.Next(count); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: format.Close(); sl@0: } sl@0: sl@0: sl@0: void DoTestC(TInt aDrvNum, TInt aNotherDrvNum, TBool aNand) sl@0: { sl@0: TInt pos=0; sl@0: TInt size=0; sl@0: TInt r; sl@0: TRequestStatus logonStat; sl@0: RThread concurrThread; sl@0: TInt locDriveNumber; sl@0: TBusLocalDrive drive; sl@0: TLocalDriveCapsV4 driveCaps; sl@0: SDeferStats stats; sl@0: sl@0: test.Next(_L("Testing concurrent Fragmentation of writes on the same media")); sl@0: if(aNand) sl@0: test.Printf(_L("Testing on NAND\n")); sl@0: test.Printf(_L("Testing on writable drives %c and %c\n"), 'A'+aDrvNum,'A'+aNotherDrvNum); sl@0: sl@0: _LIT(KTPagedCpp, "Z:\\test\\TEST_PAGED.cpp"); sl@0: _LIT(KTPaged1Cpp, "Z:\\test\\TEST_PAGED1.cpp"); sl@0: sl@0: if(TheFs.IsFileInRom(KTPagedCpp) != NULL && TheFs.IsFileInRom(KTPaged1Cpp) != NULL) // .oby must include these files sl@0: { sl@0: RFile f; sl@0: r=f.Open(TheFs,KTPagedCpp,EFileStream); // source 1 sl@0: test(r==KErrNone); sl@0: r=f.Seek(ESeekAddress,pos); sl@0: test(r==KErrNone); sl@0: TText8* ptrPos=*(TText8**)&pos; // start address of paged file 1 in ROM sl@0: test.Printf(_L("Main thread->Start address of paged out file 1 0x%x\n"), ptrPos); sl@0: r=f.Size(size); // size of paged file 1 sl@0: test(r==KErrNone); sl@0: f.Close(); sl@0: sl@0: TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); sl@0: TUint fsize=Min(KMuliplySize*size,romHeader->iPageableRomSize); sl@0: sl@0: test.Printf(_L("Main thread->Set descriptor with size %d to point to paged out file 1 +...\n"), fsize); sl@0: TPtrC8 ptr(ptrPos,fsize); sl@0: sl@0: Buffer.SetLength(fsize); sl@0: TPtr8 readBuf(&Buffer[0],fsize,fsize); sl@0: sl@0: test.Printf(_L("Create and resume concurrent thread\n")); sl@0: const TInt KHeapSize=0x2000; sl@0: sl@0: locDriveNumber = GetLocDrvNumber(aNotherDrvNum); sl@0: TInt r = concurrThread.Create(_L("ConcurrentWriteThread"),ConcurrThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)locDriveNumber); sl@0: test(r==KErrNone); sl@0: concurrThread.Logon(logonStat); sl@0: sl@0: locDriveNumber = GetLocDrvNumber(aDrvNum); sl@0: test.Printf(_L("Connect to local drive %d\n"),locDriveNumber); sl@0: TBool changeFlag = EFalse; sl@0: r = drive.Connect(locDriveNumber,changeFlag); sl@0: TPckg capsPack(driveCaps); sl@0: drive.Caps(capsPack); sl@0: test(r == KErrNone); sl@0: sl@0: test(WriteSemaphore.CreateLocal(0)==KErrNone); sl@0: sl@0: // try to ensure there is no other thread activity as this may prevent the sl@0: // large write from being pre-empted by the ConcurrentWriteThread sl@0: test.Printf(_L("Waiting 2 secs for file server threads to quieten down....")); sl@0: User::After(2000000); sl@0: sl@0: concurrThread.Resume(); sl@0: sl@0: WriteSemaphore.Wait(); sl@0: WriteSemaphore.Signal(); sl@0: sl@0: // long write... sl@0: // test.Printf(_L("Starting file 1 write\n")); sl@0: r = drive.Write(0,ptr); sl@0: test(r==KErrNone); sl@0: sl@0: test.Printf(_L("Main thread->Write 1 completed\n")); sl@0: sl@0: if(aNand) sl@0: { sl@0: test.Printf(_L("Read stats\n")); sl@0: TPtr8 statsBuf((TUint8*) &stats, sizeof(stats)); sl@0: test(drive.ControlIO(KNandGetDeferStats, statsBuf, 0)==KErrNone); sl@0: test.Printf(_L("Fragmentation clashes %d Fragmentation deferrals %d Page In deferrals %d Other deferrals %d\n"),stats.iClashFragmenting, stats.iNormalFragmenting, stats.iPageOther, stats.iNormalOther); sl@0: } sl@0: sl@0: test.Printf(_L("Read back file 1 and compare\n")); sl@0: r = drive.Read(0,fsize,readBuf); sl@0: test(r==KErrNone); sl@0: test(ptr==readBuf); sl@0: test.Printf(_L("Verify file 1 OK\n")); sl@0: drive.Disconnect(); sl@0: sl@0: WriteSemaphore.Signal(); sl@0: User::WaitForRequest(logonStat); sl@0: test(logonStat==KErrNone); sl@0: concurrThread.Close(); sl@0: WriteSemaphore.Close(); sl@0: sl@0: silentFormat(aDrvNum); sl@0: silentFormat(aNotherDrvNum); sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("Required test files not present\n")); sl@0: test(0); sl@0: } sl@0: } sl@0: sl@0: sl@0: GLDEF_D RFs TheFsT; sl@0: GLDEF_D RTest testT(_L("T_CONCURRENT_WRITE_THREAD")); sl@0: sl@0: LOCAL_C TInt ConcurrThread(TAny* aArg) sl@0: { sl@0: // the whole test is dodgy and hangs if this thread fails an assert, sl@0: // so at least make sure thread panic takes out whole test process... sl@0: User::SetCritical(User::EProcessCritical); sl@0: sl@0: RFile f; sl@0: TInt pos=0; sl@0: TInt size=0; sl@0: TInt locDriveNumber; sl@0: TBusLocalDrive drive; sl@0: TLocalDriveCapsV4 driveCaps; sl@0: SDeferStats stats; sl@0: RThread thisThread; sl@0: sl@0: TInt r = TheFsT.Connect(); sl@0: _LIT(KTPaged1Cpp, "Z:\\test\\TEST_PAGED1.cpp"); sl@0: r=f.Open(TheFsT,KTPaged1Cpp,EFileStream); // source 2 sl@0: testT(r==KErrNone); sl@0: r=f.Seek(ESeekAddress,pos); sl@0: testT(r==KErrNone); sl@0: TText8* ptrPos=*(TText8**)&pos; // start address of paged file 2 in ROM sl@0: testT.Printf(_L("ConcurrThread->Start address of paged out file 2 0x%x\n"), ptrPos); sl@0: r=f.Size(size); // size of paged file 2 sl@0: testT(r==KErrNone); sl@0: f.Close(); sl@0: sl@0: testT.Printf(_L("ConcurrThread->Set descriptor with size %d to point to paged out file 2\n"), size); sl@0: TPtrC8 ptr(ptrPos,size); sl@0: sl@0: TPtr8 readBuf(&Buffer[0],size,size); sl@0: sl@0: locDriveNumber = (TInt)aArg; sl@0: testT.Printf(_L("Connect to local drive %d\n"),locDriveNumber); sl@0: TBool changeFlag = EFalse; sl@0: r = drive.Connect(locDriveNumber,changeFlag); sl@0: TPckg capsPack(driveCaps); sl@0: drive.Caps(capsPack); sl@0: testT(r == KErrNone); sl@0: sl@0: if (driveCaps.iType == EMediaNANDFlash) sl@0: { sl@0: testT.Printf(_L("Zero stats\n")); sl@0: TPtr8 statsBuf((TUint8*) &stats, sizeof(stats)); sl@0: testT(drive.ControlIO(KNandGetDeferStats, statsBuf, 0)==KErrNone); sl@0: } sl@0: sl@0: r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); sl@0: if(r==KErrNotSupported) sl@0: testT.Printf(_L("ConcurrThread->Flushing of paging not Supported\n")); sl@0: sl@0: // pause one second to make sure main thread has executed WriteSemaphore.Wait(); sl@0: User::After(1000000); sl@0: sl@0: WriteSemaphore.Signal(); sl@0: WriteSemaphore.Wait(); sl@0: // up our priority sl@0: thisThread.SetPriority(EPriorityMore); sl@0: sl@0: // wait a very short time to give the other thread a better chance to initiate the write sl@0: User::After(1); sl@0: // testT.Printf(_L("Starting file 2 write\n")); sl@0: sl@0: // write sl@0: r = drive.Write(0,ptr); sl@0: testT(r==KErrNone); sl@0: // read back sl@0: r = drive.Read(0,size,readBuf); sl@0: testT(r==KErrNone); sl@0: // erase sl@0: r=drive.Format(0,size); sl@0: testT(r==KErrNone); sl@0: sl@0: testT.Printf(_L("ConcurrThread->Write of file 2 completed\n")); sl@0: sl@0: WriteSemaphore.Wait(); sl@0: testT.Printf(_L("Read back file 2 and compare\n")); sl@0: testT(ptr==readBuf); sl@0: testT.Printf(_L("Verify file 2 OK\n")); sl@0: sl@0: drive.Disconnect(); sl@0: TheFsT.Close(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: #endif // #if defined(_DEBUG) || defined(_DEBUG_RELEASE) sl@0: sl@0: //-------------------------------------------------------- sl@0: sl@0: /** sl@0: Create an empty file of specified size. sl@0: @param aFs ref. to the FS sl@0: @param aFileName name of the file sl@0: @param aFileSize size of the file to be created sl@0: @return KErrNone on success, system-wide error code otherwise sl@0: */ sl@0: TInt CreateEmptyFile(RFs& aFs, const TDesC& aFileName, TUint aFileSize) sl@0: { sl@0: RFile file; sl@0: TInt nRes; sl@0: sl@0: nRes = file.Create(aFs, aFileName, EFileWrite); sl@0: if(nRes != KErrNone) sl@0: return nRes; sl@0: sl@0: nRes = file.SetSize(aFileSize); sl@0: if(nRes != KErrNone) sl@0: return nRes; sl@0: sl@0: file.Close(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt GetLocDrvNumber(TInt aDrvNo) sl@0: { sl@0: test.Printf(_L("GetLocDrvNumber\r\n")); sl@0: TInt locDriveNumber; sl@0: RFile file; sl@0: TBuf<256> fileName; sl@0: fileName.Append((TChar)('A'+aDrvNo)); sl@0: fileName+=_L(":\\f32-tst\\"); sl@0: TInt r=TheFs.MkDirAll(fileName); sl@0: test(r==KErrNone || r== KErrAlreadyExists); sl@0: fileName += _L("maggots.txt"); sl@0: r=file.Replace(TheFs,fileName,EFileWrite|EFileWriteDirectIO); sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName); sl@0: test(r==KErrNone); sl@0: r=file.Write(_L8("Writhing bundles of maggots, this was truly their finest hour")); sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error %d: could not write to file\n"),r); sl@0: test(r==KErrNone); sl@0: sl@0: SBlockMapInfo info; sl@0: TInt64 start=0; sl@0: r=file.BlockMap(info,start, -1,ETestDebug); sl@0: if (r!=KErrNone && r!=KErrCompletion) sl@0: test.Printf(_L("Error %d: could not obtain block map\n"),r); sl@0: test(r==KErrNone || r==KErrCompletion); sl@0: locDriveNumber=info.iLocalDriveNumber; sl@0: test.Printf(_L("From drive: %c to Local drive %d\r\n"), aDrvNo+'A',locDriveNumber); sl@0: file.Close(); sl@0: return locDriveNumber; sl@0: } sl@0: sl@0: GLDEF_C void CallTestsL() sl@0: { sl@0: TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); sl@0: if(!romHeader->iPageableRomStart) sl@0: { sl@0: test.Printf(_L("Test not supported (not a paged ROM)\n")); sl@0: return; // Not a paged ROM, skip test sl@0: } sl@0: test.Title(); sl@0: sl@0: TBool r=TestSimpleFragmentation(); sl@0: if(!r) sl@0: return; sl@0: #if defined(_DEBUG) || defined(_DEBUG_RELEASE) sl@0: TestConcurrentFragmentation(); sl@0: #endif sl@0: }