Added code to read physical block size on Linux.
diff --git a/NEWS b/NEWS
index 6ff81cc..5771634 100644
--- a/NEWS
+++ b/NEWS
@@ -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.
diff --git a/diskio-unix.cc b/diskio-unix.cc
index af71cdb..a7c4724 100644
--- a/diskio-unix.cc
+++ b/diskio-unix.cc
@@ -177,6 +177,27 @@
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) {
diff --git a/diskio-windows.cc b/diskio-windows.cc
index 5535f49..9cff0d7 100644
--- a/diskio-windows.cc
+++ b/diskio-windows.cc
@@ -144,6 +144,13 @@
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) {
diff --git a/diskio.h b/diskio.h
index 631a43a..26f113d 100644
--- a/diskio.h
+++ b/diskio.h
@@ -71,6 +71,7 @@
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;}
diff --git a/gpt.cc b/gpt.cc
index 015da65..a86dd2e 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -64,6 +64,7 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
// 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
diff --git a/gpt.h b/gpt.h
index 2528b92..2d7a1ce 100644
--- a/gpt.h
+++ b/gpt.h
@@ -68,8 +68,9 @@
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;