Changes to sector alignment policies and behavior when restoring a
backup fails
This commit is contained in:
19
CHANGELOG
19
CHANGELOG
@@ -1,3 +1,22 @@
|
||||
0.6.6 (?/?/2010):
|
||||
-----------------
|
||||
|
||||
- More alignment changes: GPT fdisk now attempts to determine the
|
||||
alignment value based on alignment of current partitions, if any are
|
||||
defined. If no partitions are defined, a default value of 2048 is
|
||||
set. If the computed value is less than 8 on drives over about 596GiB,
|
||||
it's reset to 8, since the drive might be a WD Advanced Format unit
|
||||
that requires an 8-sector (or larger power-of-2) alignment value
|
||||
for proper functioning. The 2048-sector default provides better
|
||||
alignment in some RAID configurations.
|
||||
|
||||
- Changed behavior when a backup restore fails. Previously, GPT fdisk
|
||||
would create a fresh blank set of partitions. Now it does so only
|
||||
if the failure occurs when interpreting the backup's contents; if the
|
||||
user typed the wrong filename, the in-memory data structures aren't
|
||||
touched.
|
||||
|
||||
|
||||
0.6.5 (3/7/2010):
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ void Attributes::ChangeAttributes(void) {
|
||||
do {
|
||||
response = GetNumber(0, 64, -1, (string) "Toggle which attribute field (0-63, 64 to exit): ");
|
||||
if (response != 64) {
|
||||
bitValue = PowerOf2(NUM_ATR - response - 1); // Find the integer value of the bit
|
||||
bitValue = PowerOf2(uint32_t (NUM_ATR - response - 1)); // Find the integer value of the bit
|
||||
if ((bitValue & attributes) == bitValue) { // bit is set
|
||||
attributes -= bitValue; // so unset it
|
||||
cout << "Have disabled the '" << atNames[response] << "' attribute.\n";
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "support.h"
|
||||
#include "diskio.h"
|
||||
#include "gpt.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -93,11 +94,12 @@ int DiskIO::OpenForWrite(const string & filename) {
|
||||
// returns 1-sector alignment for unusual sector sizes and drives smaller than
|
||||
// a size defined by SMALLEST_ADVANCED_FORMAT, and 8-sector alignment for
|
||||
// larger drives with 512-byte sectors.
|
||||
int DiskIO::FindAlignment(void) {
|
||||
int err, result;
|
||||
uint32_t DiskIO::FindAlignment(void) {
|
||||
int err;
|
||||
uint32_t result;
|
||||
|
||||
if ((GetBlockSize() == 512) && (DiskSize(&err) >= SMALLEST_ADVANCED_FORMAT)) {
|
||||
result = 8; // play it safe; align for 4096-byte sectors
|
||||
result = DEFAULT_ALIGNMENT; // play it safe; align for 4096-byte sectors
|
||||
} else {
|
||||
result = 1; // unusual sector size; assume it's the real physical size
|
||||
} // if/else
|
||||
|
||||
6
diskio.h
6
diskio.h
@@ -35,10 +35,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
|
||||
// cutoff
|
||||
#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
|
||||
|
||||
/***************************************
|
||||
* *
|
||||
* DiskIO class and related structures *
|
||||
@@ -71,7 +67,7 @@ class DiskIO {
|
||||
int Write(void* buffer, int numBytes);
|
||||
void DiskSync(void); // resync disk caches to use new partitions
|
||||
int GetBlockSize(void);
|
||||
int FindAlignment(void);
|
||||
uint32_t FindAlignment(void);
|
||||
int FindAlignment(const string & filename);
|
||||
int IsOpen(void) {return isOpen;}
|
||||
int IsOpenForWrite(void) {return openForWrite;}
|
||||
|
||||
2
gdisk.8
2
gdisk.8
@@ -458,7 +458,7 @@ important filesystem data structures can span physical sectors on the disk.
|
||||
To minimize such problems, GPT fdisk aligns the start of partitions on the
|
||||
boundary of presumed physical sectors. You can set the number of logical
|
||||
sectors per physical sector with this option. The default is 1 on disks
|
||||
smaller than 800GB and 8 on larger disks.
|
||||
smaller than 596 GiB and 8 on larger disks with 512\-byte logical sectors.
|
||||
|
||||
.TP
|
||||
.B m
|
||||
|
||||
7
gdisk.cc
7
gdisk.cc
@@ -318,6 +318,7 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
|
||||
uint32_t pn, temp1, temp2;
|
||||
int goOn = 1;
|
||||
GUIDData aGUID;
|
||||
ostringstream prompt;
|
||||
|
||||
do {
|
||||
cout << "\nExpert command (? for help): ";
|
||||
@@ -355,8 +356,10 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
temp1 = GetNumber(1, 128, 8, (string)
|
||||
"Enter the sector alignment value (1-128, default = 8): ");
|
||||
prompt.seekp(0);
|
||||
prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
|
||||
<< DEFAULT_ALIGNMENT << "): ";
|
||||
temp1 = GetNumber(1, MAX_ALIGNMENT, DEFAULT_ALIGNMENT, prompt.str());
|
||||
theGPT->SetAlignment(temp1);
|
||||
break;
|
||||
case 'm': case 'M':
|
||||
|
||||
68
gpt.cc
68
gpt.cc
@@ -14,6 +14,7 @@
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
@@ -641,6 +642,7 @@ int GPTData::LoadPartitions(const string & deviceFilename) {
|
||||
if (allOK)
|
||||
CheckGPTSize();
|
||||
myDisk.Close();
|
||||
ComputeAlignment();
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if/else
|
||||
@@ -1116,20 +1118,20 @@ int GPTData::LoadGPTBackup(const string & filename) {
|
||||
if (!LoadPartitionTable(mainHeader, backupFile, (uint64_t) (3 - shortBackup)))
|
||||
cerr << "Warning! Read error " << errno
|
||||
<< " loading partition table; strange behavior now likely!\n";
|
||||
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if/else
|
||||
// Something went badly wrong, so blank out partitions
|
||||
if (allOK == 0) {
|
||||
cerr << "Improper backup file! Clearing all partition data!\n";
|
||||
ClearGPTData();
|
||||
protectiveMBR.MakeProtectiveMBR();
|
||||
} // if
|
||||
} else {
|
||||
allOK = 0;
|
||||
cerr << "Unable to open file " << filename << " for reading! Aborting!\n";
|
||||
} // if/else
|
||||
|
||||
// Something went badly wrong, so blank out partitions
|
||||
if (allOK == 0) {
|
||||
ClearGPTData();
|
||||
protectiveMBR.MakeProtectiveMBR();
|
||||
} // if
|
||||
return allOK;
|
||||
} // GPTData::LoadGPTBackup()
|
||||
|
||||
@@ -2123,6 +2125,60 @@ int GPTData::IsFreePartNum(uint32_t partNum) {
|
||||
return retval;
|
||||
} // GPTData::IsFreePartNum()
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* Change how functions work or return information on them *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
// Set partition alignment value; partitions will begin on multiples of
|
||||
// the specified value
|
||||
void GPTData::SetAlignment(uint32_t n) {
|
||||
uint32_t l2;
|
||||
|
||||
sectorAlignment = n;
|
||||
l2 = (uint32_t) log2(n);
|
||||
if (PowerOf2(l2) != n)
|
||||
cout << "Information: Your alignment value is not a power of 2.\n";
|
||||
} // GPTData::SetAlignment()
|
||||
|
||||
// Compute sector alignment based on the current partitions (if any). Each
|
||||
// partition's starting LBA is examined, and if it's divisible by a power-of-2
|
||||
// value less than the maximum found so far (or 2^31 for the first partition
|
||||
// found), then the alignment value is adjusted down. If the computed
|
||||
// alignment is less than 8 and the disk is bigger than SMALLEST_ADVANCED_FORMAT,
|
||||
// resets it to 8. This is a safety measure for WD Advanced Format and
|
||||
// similar drives. If no partitions are defined, the alignment value is set
|
||||
// to DEFAULT_ALIGNMENT (2048). The result is that new drives are aligned to
|
||||
// 2048-sector multiples but the program won't complain about other alignments
|
||||
// on existing disks unless a smaller-than-8 alignment is used on small disks
|
||||
// (as safety for WD Advanced Format drives).
|
||||
// Returns the computed alignment value.
|
||||
uint32_t GPTData::ComputeAlignment(void) {
|
||||
uint32_t i = 0, found, exponent = 31;
|
||||
uint64_t align = DEFAULT_ALIGNMENT;
|
||||
|
||||
for (i = 0; i < mainHeader.numParts; i++) {
|
||||
if (partitions[i].IsUsed()) {
|
||||
found = 0;
|
||||
while (!found) {
|
||||
align = PowerOf2(exponent);
|
||||
if ((partitions[i].GetFirstLBA() % align) == 0) {
|
||||
found = 1;
|
||||
} else {
|
||||
exponent--;
|
||||
} // if/else
|
||||
} // while
|
||||
} // if
|
||||
} // for
|
||||
if ((align < 8) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
|
||||
align = 8;
|
||||
// cout << "Setting alignment to " << align << "\n";
|
||||
SetAlignment(align);
|
||||
return align;
|
||||
} // GPTData::ComputeAlignment()
|
||||
|
||||
/********************************
|
||||
* *
|
||||
* Endianness support functions *
|
||||
|
||||
19
gpt.h
19
gpt.h
@@ -16,7 +16,7 @@
|
||||
#ifndef __GPTSTRUCTS
|
||||
#define __GPTSTRUCTS
|
||||
|
||||
#define GPTFDISK_VERSION "0.6.5"
|
||||
#define GPTFDISK_VERSION "0.6.6-pre1"
|
||||
|
||||
// Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
|
||||
// numbered value to refer to partition numbers. (Most will be 0 or positive,
|
||||
@@ -24,6 +24,16 @@
|
||||
#define MBR_EFI_GPT -1
|
||||
#define MBR_EMPTY -2
|
||||
|
||||
// Default values for sector alignment
|
||||
#define DEFAULT_ALIGNMENT 2048
|
||||
#define MAX_ALIGNMENT 32768
|
||||
|
||||
// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
|
||||
// cutoff
|
||||
//#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
|
||||
// Now ~596GiB (640MB), since WD has introduced a smaller Advanced Format drive
|
||||
#define SMALLEST_ADVANCED_FORMAT UINT64_C(1250263728)
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PartNotes;
|
||||
@@ -79,7 +89,7 @@ protected:
|
||||
int secondPartsCrcOk;
|
||||
int apmFound; // set to 1 if APM detected
|
||||
int bsdFound; // set to 1 if BSD disklabel detected in MBR
|
||||
int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
|
||||
uint32_t sectorAlignment; // Start & end partitions at multiples of sectorAlignment
|
||||
int beQuiet;
|
||||
WhichToUse whichWasUsed;
|
||||
|
||||
@@ -177,8 +187,9 @@ public:
|
||||
int IsFreePartNum(uint32_t partNum);
|
||||
|
||||
// Change how functions work, or return information on same
|
||||
void SetAlignment(int n) {sectorAlignment = n;}
|
||||
int GetAlignment(void) {return sectorAlignment;}
|
||||
void SetAlignment(uint32_t n);
|
||||
uint32_t ComputeAlignment(void); // Set alignment based on current partitions
|
||||
uint32_t GetAlignment(void) {return sectorAlignment;}
|
||||
void JustLooking(int i = 1) {justLooking = i;}
|
||||
void BeQuiet(int i = 1) {beQuiet = i;}
|
||||
WhichToUse WhichWasUsed(void) {return whichWasUsed;}
|
||||
|
||||
5
mbr.cc
5
mbr.cc
@@ -85,7 +85,7 @@ int MBRData::ReadMBRData(const string & deviceFilename) {
|
||||
canDeleteMyDisk = 1;
|
||||
} // if
|
||||
if (myDisk->OpenForRead(deviceFilename)) {
|
||||
ReadMBRData(myDisk);
|
||||
allOK = ReadMBRData(myDisk);
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if
|
||||
@@ -101,7 +101,7 @@ int MBRData::ReadMBRData(const string & deviceFilename) {
|
||||
// Note that any extended partition(s) present will be explicitly stored
|
||||
// in the partitions[] array, along with their contained partitions; the
|
||||
// extended container partition(s) should be ignored by other functions.
|
||||
void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
|
||||
int MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
|
||||
int allOK = 1, i, j, logicalNum;
|
||||
int err = 1;
|
||||
TempMBR tempMBR;
|
||||
@@ -201,6 +201,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
|
||||
} // for
|
||||
} // if (hybrid detection code)
|
||||
} // no initial error
|
||||
return allOK;
|
||||
} // MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize)
|
||||
|
||||
// This is a recursive function to read all the logical partitions, following the
|
||||
|
||||
2
mbr.h
2
mbr.h
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
// File I/O functions...
|
||||
int ReadMBRData(const string & deviceFilename);
|
||||
void ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1);
|
||||
int ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1);
|
||||
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
||||
// or -1 if there was a problem....
|
||||
int ReadLogicalPart(uint32_t extendedStart, uint32_t diskOffset,
|
||||
|
||||
8
sgdisk.8
8
sgdisk.8
@@ -149,10 +149,10 @@ sibling. Options available in \fBsgdisk\fR are:
|
||||
.B \-a, \-\-set\-alignment=value
|
||||
Set the sector alignment multiple. GPT fdisk aligns the start of partitions
|
||||
to sectors that are multiples of this value, which defaults to 8 on disks
|
||||
larger than 800GiB with 512\-byte sectors and to 1 on smaller disks or those
|
||||
with non\-512\-byte sectors. This alignment value is necessary to obtain
|
||||
optimum performance with Western Digital Advanced Format and similar drives
|
||||
with larger physical than logical sector sizes.
|
||||
larger than 596 GiB with 512\-byte logical sectors and to 1 on smaller
|
||||
disks or those with non\-512\-byte sectors. This alignment value is
|
||||
necessary to obtain optimum performance with Western Digital Advanced
|
||||
Format and similar drives with larger physical than logical sector sizes.
|
||||
|
||||
.TP
|
||||
.B \-b, \-\-backup=file
|
||||
|
||||
@@ -33,7 +33,7 @@ int main(int argc, char *argv[]) {
|
||||
GPTData theGPT;
|
||||
int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
|
||||
int partNum = 0, deletePartNum = 0, infoPartNum = 0, bsdPartNum = 0, saveNonGPT = 1;
|
||||
int alignment = 8, retval = 0, pretend = 0;
|
||||
int alignment = DEFAULT_ALIGNMENT, retval = 0, pretend = 0;
|
||||
unsigned int hexCode;
|
||||
uint32_t tableSize = 128;
|
||||
uint64_t startSector, endSector;
|
||||
|
||||
@@ -246,11 +246,11 @@ void ReverseBytes(void* theValue, int numBytes) {
|
||||
|
||||
// Compute (2 ^ value). Given the return type, value must be 63 or less.
|
||||
// Used in some bit-fiddling functions
|
||||
uint64_t PowerOf2(int value) {
|
||||
uint64_t PowerOf2(uint32_t value) {
|
||||
uint64_t retval = 1;
|
||||
int i;
|
||||
uint32_t i;
|
||||
|
||||
if ((value < 64) && (value >= 0)) {
|
||||
if (value < 64) {
|
||||
for (i = 0; i < value; i++) {
|
||||
retval *= 2;
|
||||
} // for
|
||||
|
||||
@@ -55,6 +55,6 @@ string BytesToSI(uint64_t size);
|
||||
unsigned char StrToHex(const string & input, unsigned int position);
|
||||
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
|
||||
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
|
||||
uint64_t PowerOf2(int value);
|
||||
uint64_t PowerOf2(uint32_t value);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user