Hi Darren, The program is doing data comparison when data write and read is miss-matched, all information such as drive, stripe, sector, LBAs, etc. are collected where the miss-matched data located and put into a log file or print out.
Attached are functions that used in linux to do a job. I copy these functions into one file Call_get_unit_lba_range.txt, hope that easier for you to review. The “tws_file_lba.cpp” contains all function that is doing with LBA, and LBA range where the mis-compare file located on drive. The whole files are long. However, I can send them to you if you need more info. - void DCA_MC_Log_Data::CreateStripeMapData() - void TWS_File_LBA::get_unit_lba_range(char *file_name, ULONGLONG byte_offset, ULONGLONG record_length, ULONGLONG &range_start_unit_lba, ULONGLONG &range_end_unit_lba, ULONGLONG &run_length) - unsigned long TWS_File_LBA::get_unit_lba(char *file_name, uint64_t byte_offset, std::string &device_name, FileSysType *fs_type, LONGLONG &vcn, LONGLONG &lcn, ULONG &cluster_size, bool verify_lba) Note: - wrc_dat_file_name: the file that miss-compare data occurred. - File Call_get_unit_lba_range.txt: contains 2 functions that call “get_unit_lba_range” and “get_unit_lba” - File “tws_file_lba.cpp” contains “get_unit_lba_range” and “get_unit_lba” to get LBA info. Thank you very much for your time. Thai. -- This message posted from opensolaris.org
// ==============================================================
// Analyze the mis-compare data file
// This function use "get_unit_lba_range"
void DCA_MC_Log_Data::CreateStripeMapData()
{
ULONGLONG CurUnitLBA=0;
ULONGLONG CurDriveLBA=0;
unsigned long CurDataDrive=0;
unsigned long NextDataDrive=0;
unsigned long CurNumSectors=0; // (in this miscompare details)
unsigned long CurStripeNum=0;
unsigned long StripeletSectorOffset=0;
unsigned long NumSectorsLeft=0;
ULONGLONG StripeStartUnitLBA=0;
ULONGLONG StripeletEndDriveLBA=0;
ULONGLONG StripeletStartDriveLBA=0;
ULONGLONG FileRangeEndUnitLBA=0;
ULONGLONG FileRangeStartUnitLBA=0;
ULONGLONG recordLength=0;
ULONGLONG runLength=0; // returned from getLBAandLengthByOffset (<
recordLength if more segments)
ULONGLONG CurFileOffset=0; // start of file block range according to file
offset (# of bytes)
ULONGLONG CurMCFileOffset=0; // keeps track of offset within the file
char wrc_dat_file_name[512]={0};
TWX_File_LBA FileLBA;
int StripeSizeSectors = the_unit_->GetStripeSize_Sectors();
DCA_MC_Log_Data::MCList::iterator curMC, endMC = miscompares_.end();
for (curMC = miscompares_.begin(); curMC != endMC; ++curMC)
{
strncpy(wrc_dat_file_name, curMC->WrcDatFileName_.c_str(), 512);
CurUnitLBA = curMC->unit_LBA_;
the_unit_->GetDriveLBA(CurUnitLBA, &CurDataDrive, &CurDriveLBA);
the_unit_->GetStripeNumFromDriveLBA(CurDriveLBA, &CurStripeNum,
&StripeletSectorOffset);
StripeletStartDriveLBA = CurStripeNum * StripeSizeSectors;
StripeletEndDriveLBA = StripeletStartDriveLBA + StripeSizeSectors - 1;
if (true == curMC->bLengthBytes_)
{
CurNumSectors = NumSectorsLeft = 1;
}
else // length is in sectors
{
CurNumSectors = NumSectorsLeft = curMC->length_;
}
CurFileOffset = curMC->FileOffset_;
CurMCFileOffset = curMC->FileOffset_;
recordLength = CurNumSectors * 512;
// runLength is in bytes
// CurFileOffset is in bytes
FileLBA.get_unit_lba_range(wrc_dat_file_name, CurFileOffset,
recordLength,
FileRangeStartUnitLBA, FileRangeEndUnitLBA, runLength);
// Map out how this miscompare is broken up among stripes and file
system block ranges
while (NumSectorsLeft > 0)
{
// We're either just starting out, or we reached the end of a file
block range,
// or we reached the end of a stripelet.
// Check for end of file-range (the filesystem writes a file on
different block ranges)
if (CurUnitLBA > FileRangeEndUnitLBA)
{
// If this assertion triggers, it means the file isn't split in
multiple block ranges
// so something is wrong.
assert(recordLength > runLength);
recordLength -= runLength;
CurFileOffset += runLength; // this line tells getLBAand.. the
next range (in bytes from file start)
FileLBA.get_unit_lba_range(wrc_dat_file_name, CurFileOffset,
recordLength,
FileRangeStartUnitLBA, FileRangeEndUnitLBA,
runLength);
CurUnitLBA = FileRangeStartUnitLBA;
the_unit_->GetDriveLBA(CurUnitLBA, &CurDataDrive, &CurDriveLBA);
the_unit_->GetStripeNumFromDriveLBA(CurDriveLBA, &CurStripeNum,
&StripeletSectorOffset);
StripeletStartDriveLBA = CurStripeNum * StripeSizeSectors;
StripeletEndDriveLBA = StripeletStartDriveLBA +
StripeSizeSectors - 1;
}
// Check for end of stripelet
else if (CurDriveLBA > StripeletEndDriveLBA)
{
// Get the next data drive #
NextDataDrive = (CurDataDrive + 1) % the_unit_->GetNumDrives();
// Compensate for parity/Q
while (the_unit_->IsDataDrive(NextDataDrive, CurStripeNum) ==
false)
{
NextDataDrive = (NextDataDrive + 1) %
the_unit_->GetNumDrives();
}
// If we wrapped to a lower logical drive #, we must have moved
to the next stripe.
if (NextDataDrive < CurDataDrive)
{
++CurStripeNum;
// Search for the first data drive in the stripe.
NextDataDrive = 0;
// Compensate for parity/Q in the new stripe
while (the_unit_->IsDataDrive(NextDataDrive, CurStripeNum)
== false)
{
NextDataDrive = (NextDataDrive + 1) %
the_unit_->GetNumDrives();
}
StripeletStartDriveLBA += StripeSizeSectors;
StripeletEndDriveLBA += StripeSizeSectors;
}
CurDataDrive = NextDataDrive;
CurDriveLBA = StripeletStartDriveLBA;
}
// Take the minimum number of sectors (stop at miscompare end, file
block range
// end, or stripelet end)
CurNumSectors = (unsigned long)min(NumSectorsLeft,
StripeletEndDriveLBA - CurDriveLBA + 1);
CurNumSectors = (unsigned long)min(CurNumSectors,
FileRangeEndUnitLBA - CurUnitLBA + 1);
assert(CurNumSectors > 0); // currently impossible, but in case the
code changes!
// if it doesn't exist yet
if (StripeMCs_.find(CurStripeNum) == StripeMCs_.end())
{
// Create a StripeMC (give it the stripe start drive LBA).
StripeStartUnitLBA = (ULONGLONG)CurStripeNum *
(StripeSizeSectors * the_unit_->GetNumDataDrives());
StripeMCs_[CurStripeNum] = StripeMC(CurStripeNum,
StripeletStartDriveLBA, StripeStartUnitLBA);
}
// Add miscompare details for CurNumSectors
StripeMCs_[CurStripeNum].AddSegment(StripeMCSegment((unsigned
long)(CurDriveLBA - StripeletStartDriveLBA),
CurNumSectors, CurDataDrive,
curMC->DataPattern_, CurMCFileOffset, curMC->ThreadStartTime_));
CurMCFileOffset += (CurNumSectors * 512);
NumSectorsLeft -= CurNumSectors;
CurUnitLBA += CurNumSectors;
CurDriveLBA += CurNumSectors;
} // end while more sectors in this miscompare to map
}
}
// ==============================================================
// Keep info into Log file
// This function use "get_unit_lba"
void DCA_WRC_Log_Importer1::ImportLog(DCA_MC_Log_Data *log_data)
{
// Create a MiscompareDetails instance for each miscompare
// Add each instance to the LogData
char pszTemp[512]={0};
char pszDatFileName[128]={0};
char pszMount[512]={0}; // In windows this is a drive letter, but in unix
it's a path.
char *pLine=0, *pEndLine=0; // a pointer into pszTemp for parsing
// struct tm start_tm = {0}; // this grabs program start time from tw_wrc.log
(not used because tw_wrc data uses thread start time)
int num_scanned=0;
DCA_MC_Details miscomp;
int *patterns=0;
int *thread_start_times=0;
int NumThreads=1;
int ThreadNum=0;
int Pattern=0;
int ThreadStart=0;
// Open the log file
FILE *fpLog = fopen(log_file_name_.cstring(), "r");
if (NULL == fpLog)
{
throw("Error opening log file.\n");
}
try
{
// skip any possible blank lines at the top of the file
do
{
fgets(pszTemp, 512, fpLog);
} while ('\n' == pszTemp[0]);
// The first line of the tw_wrc log file should be the tw_wrc command line
(with "tw_wrc -x -y -z")
ParseCheck(strstr(pszTemp, "tw_wrc") != NULL,
"This does not appear to be a valid tw_wrc log file. Could not find
\"tw_wrc\" on first line.\n");
// Now pszTemp is the first line of the file (must be the tw_wrc command
line)
// trim the newline (\n)
pszTemp[strlen(pszTemp)-1] = '\0';
log_data->tw_wrc_cmd_line_.assign(pszTemp);
// Get the number of threads
pLine = strstr(pszTemp, "-t ");
if (NULL == pLine)
{
pLine = strstr(pszTemp, "-T ");
}
if (pLine != NULL)
{
pLine += 3; // skip to the number
sscanf(pLine, "%d", &NumThreads);
}
// else NumThreads = 1
ParseCheck(NumThreads > 0, "Number of tw_wrc threads was less than 1");
patterns = new int[NumThreads];
thread_start_times = new int[NumThreads];
// Get the mount point of the data file
pLine = strstr(pszTemp, "-d ");
if (NULL == pLine)
{
pLine = strstr(pszTemp, "-D ");
}
ParseCheck(pLine != NULL, "Could not parse the drive option (-d tw_wrc
option)");
pLine += 3; // "-d_"
pEndLine = strchr(pLine, ' ');
ParseCheck(pLine != NULL, "Could not parse the drive letter or mount
point");
memcpy(pszMount, pLine, pEndLine - pLine);
#if defined(WIN32)
pszMount[pEndLine - pLine] = ':';
pszMount[pEndLine - pLine + 1] = '\0';
#else
pszMount[pEndLine - pLine] = '\0';
#endif
log_data->mount_point_ = pszMount;
while (!feof(fpLog))
{
fgets(pszTemp, 512, fpLog);
// Get the data pattern this thread is using
if (strstr(pszTemp, ": file ") != NULL &&
(pLine = strstr(pszTemp, "tw_wrc_")) != NULL)
{
pLine += strlen("tw_wrc_");
num_scanned = sscanf(pLine, "%d", &ThreadNum);
ParseCheck(1 == num_scanned, "Could not parse the thread number while
looking for the pattern");
pLine = strstr(pLine, ", pattern");
ParseCheck(pLine != NULL, "Could not find the thread's pattern");
pLine += strlen(", pattern ");
num_scanned = sscanf(pLine, "%X", &Pattern);
ParseCheck(1 == num_scanned, "Could not parse the pattern int");
patterns[ThreadNum] = Pattern;
pLine = strstr(pLine, ", thread start");
ParseCheck(pLine != NULL, "Could not find the thread's start time");
pLine += strlen(", thread start ");
num_scanned = sscanf(pLine, "%X", &ThreadStart);
ParseCheck(1 == num_scanned, "Could not parse the thread start time");
thread_start_times[ThreadNum] = ThreadStart;
}
else if ((pLine = strstr(pszTemp, "tw_wrc error e012: miscompare")) !=
NULL)
{
// get the tw_wrc data file name (tw_wrc_xxx.dat)
pLine = strstr(pLine, "in file");
ParseCheck(pLine != NULL, "Could not find the data file name section of
a miscompare (\"in file\")");
pLine += strlen("in file ");
pEndLine = strchr(pLine, ',');
ParseCheck(pEndLine != NULL, "Could not find the end of the data file
name for a miscompare");
ParseCheck(pEndLine - pLine < 512, "The miscompare data file name is >
512 bytes");
memcpy(pszDatFileName, pLine, pEndLine - pLine);
pszDatFileName[pEndLine - pLine] = '\0';
miscomp.WrcDatFileName_ = pszDatFileName;
// Search the dat file name for the thread num (tw_wrc_XXX.dat) XXX is
thread num
pLine = strstr(pszDatFileName, "tw_wrc_");
ParseCheck(pLine != NULL, "Could not find the first part of the data
file name (\"tw_wrc_\")");
pLine += strlen("tw_wrc_");
num_scanned = sscanf(pLine, "%d", &ThreadNum);
ParseCheck(1 == num_scanned, "Could not scan the thread number from the
data file name");
ParseCheck(ThreadNum >= 0, "The data file thread number was negative");
ParseCheck(ThreadNum < NumThreads, "The data file thread number was
greater the the number of threads");
// Get the pattern that the thread is using
miscomp.DataPattern_ = patterns[ThreadNum];
miscomp.ThreadStartTime_ = thread_start_times[ThreadNum];
// pszTemp still has the whole line
// Look for the file offset
pLine = strstr(pszTemp, "file offset");
ParseCheck(pLine != NULL, "Could not find the file offset section");
pLine += strlen("file offset ");
num_scanned = sscanf(pLine, FMT_BIG_HEX, &miscomp.FileOffset_);
ParseCheck(1 == num_scanned, "Could not scan the file offset for this
miscompare");
pLine = strchr(pLine, ',');
ParseCheck(pLine != NULL, "Could not find the comma after the file
offset");
++pLine; // past the comma to a space
++pLine; // past the space to the size of the miscompare
// Read the number and figure out if it's bytes or sectors
num_scanned = sscanf(pLine, "%d", &miscomp.length_);
ParseCheck(1 == num_scanned, "Could not scan the miscompare length");
pLine = strchr(pLine, ' ');
ParseCheck(pLine != NULL, "Did not find a space after the miscompare
length (before the units)");
++pLine;
if (strstr(pLine, "byte") != NULL)
{
miscomp.bLengthBytes_ = true; // miscomp_length is in bytes
}
else if (strstr(pLine, "sector") != NULL)
{
miscomp.bLengthBytes_ = false; // miscomp_length is in sectors
}
else
{
ParseCheck(false, "Could not figure out the units of length for the
miscompare");
}
// Find the unit LBA (it's on a different line)
do
{
fgets(pszTemp, 512, fpLog);
} while ((pLine = strstr(pszTemp, "Unit LBA")) == NULL &&
(strstr(pszTemp, "Error getting LBA") == NULL) &&
!feof(fpLog));
// This will happen if the user doesn't have file2lba while running
tw_wrc.
if (strstr(pszTemp, "Error getting LBA") != NULL)
{
char wrc_dat_file_name[512]={0};
strncpy(wrc_dat_file_name, miscomp.WrcDatFileName_.c_str(), 512);
// Find the Unit LBA ourself.
FileSysType FsType;
string DeviceName;
LONGLONG VCN;
LONGLONG LCN;
ULONG ClusterSize;
TWX_File_LBA FileLBA;
miscomp.unit_LBA_ = FileLBA.get_unit_lba(wrc_dat_file_name,
miscomp.FileOffset_, DeviceName, &FsType, VCN, LCN, ClusterSize, true);
}
else
{
// This saves us a little bit of time, and it's safer (in case the
tw_wrc data file
// changed (by running tw_wrc again before analysis)), and it's the
only way
// to do it if we're post-processing a log from a different computer
(they'll get
// this first LBA only).
ParseCheck(pLine != NULL, "Could not find the Unit LBA section (nor
Error getting LBA)");
num_scanned = sscanf(pLine, "Unit LBA 0x" FMT_BIG_HEX,
&miscomp.unit_LBA_);
ParseCheck(1 == num_scanned, "Could not scan the unit LBA");
}
log_data->AddMiscompareDetails(miscomp);
miscomp.Clear(); // make sure the next miscompare doesn't have stale
data
}
}
delete [] patterns;
fclose(fpLog);
}
catch (const char *ErrMsg)
{
string err2 = ErrMsg;
delete [] patterns;
fclose(fpLog);
throw err2.c_str();
}
}
tws_file_lba.cpp
Description: Binary data
_______________________________________________ opensolaris-code mailing list [email protected] http://mail.opensolaris.org/mailman/listinfo/opensolaris-code
