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 opensolaris-code@opensolaris.org http://mail.opensolaris.org/mailman/listinfo/opensolaris-code