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();
  }
}




Attachment: tws_file_lba.cpp
Description: Binary data

_______________________________________________
opensolaris-code mailing list
opensolaris-code@opensolaris.org
http://mail.opensolaris.org/mailman/listinfo/opensolaris-code

Reply via email to