Added code to read physical block size on Linux.

This commit is contained in:
Rod Smith
2017-07-25 21:33:18 -04:00
parent 2a6daafeda
commit fc0e014bea
6 changed files with 62 additions and 7 deletions

6
NEWS
View File

@@ -1,6 +1,12 @@
1.0.2 (?/??/2017):
------------------
- GPT fdisk can now report both the physical and logical sector sizes of
disks, but only on 2.6.32 and later Linux kernels. The verify feature now
uses the larger of the set alignment and physical/logical block sizes for
testing alignment, and setting alignment to something other than an exact
multiple of the physical/logical block size results in a warning.
- Addition of new verification checks, mostly (but not exclusively) related
to the new j/-j/--move-main-table option.

View File

@@ -177,6 +177,27 @@ int DiskIO::GetBlockSize(void) {
return (blockSize);
} // DiskIO::GetBlockSize()
// Returns the physical block size of the device, if possible. If this is
// not supported, or if an error occurs, this function returns 0.
// TODO: Get this working in more OSes than Linux.
int DiskIO::GetPhysBlockSize(void) {
int err = -1, physBlockSize = 0;
// If disk isn't open, try to open it....
if (!isOpen) {
OpenForRead();
} // if
if (isOpen) {
#if defined __linux__ && !defined(EFI)
err = ioctl(fd, BLKPBSZGET, &physBlockSize);
#endif
} // if (isOpen)
if (err == -1)
physBlockSize = 0;
return (physBlockSize);
} // DiskIO::GetPhysBlockSize(void)
// Returns the number of heads, according to the kernel, or 255 if the
// correct value can't be determined.
uint32_t DiskIO::GetNumHeads(void) {

View File

@@ -144,6 +144,13 @@ int DiskIO::GetBlockSize(void) {
return (blockSize);
} // DiskIO::GetBlockSize()
// In theory, returns the physical block size. In practice, this is only
// supported in Linux, as of yet.
// TODO: Get this working in Windows.
int DiskIO:GetPhysBlockSize(void) {
return 0;
} // DiskIO::GetPhysBlockSize()
// Returns the number of heads, according to the kernel, or 255 if the
// correct value can't be determined.
uint32_t DiskIO::GetNumHeads(void) {

View File

@@ -71,6 +71,7 @@ class DiskIO {
int Write(void* buffer, int numBytes);
int DiskSync(void); // resync disk caches to use new partitions
int GetBlockSize(void);
int GetPhysBlockSize(void);
uint32_t GetNumHeads(void);
uint32_t GetNumSecsPerTrack(void);
int IsOpen(void) {return isOpen;}

29
gpt.cc
View File

@@ -64,6 +64,7 @@ static inline uint32_t log2_32(uint32_t v) {
// Default constructor
GPTData::GPTData(void) {
blockSize = SECTOR_SIZE; // set a default
physBlockSize = 0; // 0 = can't be determined
diskSize = 0;
partitions = NULL;
state = gpt_valid;
@@ -125,6 +126,7 @@ GPTData & GPTData::operator=(const GPTData & orig) {
protectiveMBR = orig.protectiveMBR;
device = orig.device;
blockSize = orig.blockSize;
physBlockSize = orig.physBlockSize;
diskSize = orig.diskSize;
state = orig.state;
justLooking = orig.justLooking;
@@ -166,7 +168,7 @@ GPTData & GPTData::operator=(const GPTData & orig) {
// problems identified.
int GPTData::Verify(void) {
int problems = 0, alignProbs = 0;
uint32_t i, numSegments;
uint32_t i, numSegments, testAlignment = sectorAlignment;
uint64_t totalFree, largestSegment;
// First, check for CRC errors in the GPT data....
@@ -355,10 +357,15 @@ int GPTData::Verify(void) {
// Check that partitions are aligned on proper boundaries (for WD Advanced
// Format and similar disks)....
if ((physBlockSize != 0) && (blockSize != 0))
testAlignment = physBlockSize / blockSize;
testAlignment = max(testAlignment, sectorAlignment);
if (testAlignment == 0) // Should not happen; just being paranoid.
testAlignment = sectorAlignment;
for (i = 0; i < numParts; i++) {
if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() % sectorAlignment) != 0) {
if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() % testAlignment) != 0) {
cout << "\nCaution: Partition " << i + 1 << " doesn't begin on a "
<< sectorAlignment << "-sector boundary. This may\nresult "
<< testAlignment << "-sector boundary. This may\nresult "
<< "in degraded performance on some modern (2009 and later) hard disks.\n";
alignProbs++;
} // if
@@ -722,6 +729,7 @@ int GPTData::SetDisk(const string & deviceFilename) {
// store disk information....
diskSize = myDisk.DiskSize(&err);
blockSize = (uint32_t) myDisk.GetBlockSize();
physBlockSize = (uint32_t) myDisk.GetPhysBlockSize();
} // if
protectiveMBR.SetDisk(&myDisk);
protectiveMBR.SetDiskSize(diskSize);
@@ -801,6 +809,7 @@ int GPTData::LoadPartitions(const string & deviceFilename) {
// store disk information....
diskSize = myDisk.DiskSize(&err);
blockSize = (uint32_t) myDisk.GetBlockSize();
physBlockSize = (uint32_t) myDisk.GetPhysBlockSize();
device = deviceFilename;
PartitionScan(); // Check for partition types, load GPT, & print summary
@@ -1478,6 +1487,8 @@ void GPTData::DisplayGPTData(void) {
cout << "Disk " << device << ": " << diskSize << " sectors, "
<< BytesToIeee(diskSize, blockSize) << "\n";
cout << "Logical sector size: " << blockSize << " bytes\n";
if (physBlockSize > 0)
cout << "Physical sector size: " << physBlockSize << " bytes\n";
cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n";
cout << "Partition table holds up to " << numParts << " entries\n";
cout << "Main partition table begins at sector " << mainHeader.partitionEntriesLBA
@@ -2334,10 +2345,18 @@ int GPTData::IsUsedPartNum(uint32_t partNum) {
// Set partition alignment value; partitions will begin on multiples of
// the specified value
void GPTData::SetAlignment(uint32_t n) {
if (n > 0)
if (n > 0) {
sectorAlignment = n;
else
if ((physBlockSize > 0) && (n % (physBlockSize / blockSize) != 0)) {
cout << "Warning: Setting alignment to a value that does not match the disk's\n"
<< "physical block size! Performance degradation may result!\n"
<< "Physical block size = " << physBlockSize << "\n"
<< "Logical block size = " << blockSize << "\n"
<< "Optimal alignment = " << physBlockSize / blockSize << " or multiples thereof.\n";
} // if
} else {
cerr << "Attempt to set partition alignment to 0!\n";
} // if/else
} // GPTData::SetAlignment()
// Compute sector alignment based on the current partitions (if any). Each

5
gpt.h
View File

@@ -68,8 +68,9 @@ protected:
MBRData protectiveMBR;
string device; // device filename
DiskIO myDisk;
uint32_t blockSize; // device block size
uint64_t diskSize; // size of device, in blocks
uint32_t blockSize; // device logical block size
uint32_t physBlockSize; // device physical block size (or 0 if it can't be determined)
uint64_t diskSize; // size of device, in logical blocks
GPTValidity state; // is GPT valid?
int justLooking; // Set to 1 if program launched with "-l" or if read-only
int mainCrcOk;