sgdisk
命令是由
gdisk-0.8.6-4.el7.x86_64
程序包安装
sgdisk源码路径 https://github.com/Shihta/gdisk
本节主要描述sgdisk源码中关于命令-a --set-alignment=value
的边界对齐逻辑描述,借此各位可以看到sgdisk命令集
的其他参数源码白编写的逻辑
该参数使用方式一般是在创建分区过程中使用
sgdisk --set-alignment=8 --new=1:0:2G --mbrtogpt -- /dev/sdb
这个命令是在/dev/sdb上创建一个编号为1,大小为2G的gpt分区,且start_sector是4K对齐的。sgdisk
底层做分区是以扇区为单位,同时设置边界对齐时单位是扇区,默认以1M(2048个扇区)为单位进行对齐,最小只能设置8个扇区对齐
int main(int argc, char *argv[]) {
GPTDataCL theGPT;
#主要执行函数,对参数进行解析以及调用各个执行函数执行具体功能
return theGPT.DoOptions(argc, argv);
}
/*
该函数的返回值如下:
0 :执行命令成功
1:执行参数过少
2:读磁盘分区表错误
3:格式化磁盘分区格式为gpt时没有-g参数
4:无法保存sgdisk对磁盘的操作
8:备份磁盘分区表失败,-R参数failed
*/
int GPTDataCL::DoOptions(int argc, char* argv[]) {
...
#将参数长项和短项以及对应的描述封装为结构体
struct poptOption theOptions[] =
{
{"attributes", 'A', POPT_ARG_STRING, &attributeOperation, 'A', "operate on partition attributes",
"list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]"},
{"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
{"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
{"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
{"recompute-chs", 'C', POPT_ARG_NONE, NULL, 'C', "recompute CHS values in protective/hybrid MBR", ""},
{"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
{"display-alignment", 'D', POPT_ARG_NONE, NULL, 'D', "show number of sectors per allocation block", ""},
{"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
{"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
{"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
...
}
...
// 确保最后一个参数一定是设备名称(之前会做参数筛选)
device = (char*) poptGetArg(poptCon);
poptResetContext(poptCon);
//如果设备名称不为空的话开始进行具体的参数解析
if (device != NULL) {
JustLooking(); // reset as necessary
BeQuiet(); // Tell called functions to be less verbose & interactive
//加载磁盘分区表
if (LoadPartitions((string) device)) {
...
//开始进行具体的sgdisk参数解析
while ((opt = poptGetNextOpt(poptCon)) > 0) {
...
//设置分区边界对齐的短项参数 对应--set-alignment=value
case 'a':
//初始化分区边界对齐参数 ,会为全局变量 sectorAlignment 赋值
SetAlignment(alignment);
break;
...
//创建分区参数短项,对应--new=num:start_sector:end_sector
case 'n':
JustLooking(0);
//获取分区编号
newPartNum = (int) GetInt(newPartInfo, 1) - 1;
//如果分区编号小于零则选择第一个没有被使用的编号(最小的没有被使用的)
if (newPartNum < 0)
newPartNum = FindFirstFreePart();
//从磁盘的剩余空间中寻找最大的未被分配的块,取该块中的第一个可用的扇区作为起始扇区配置
low = FindFirstInLargest();
/*将该扇区调整为512字节,因为不通磁盘有自己的扇区大小设置,
这里会将这种类型的磁盘扇区大小设置为操作系统识别的512字节*/
Align(&low);
//依据该块空间的起始扇区位置寻找终止扇区位置
high = FindLastInFree(low);
//这里做一个转换,将我们创建分区在start和end处输入的IEEE-1541-2002 value(K,M,G,T,P,E)转换为扇区单位
startSector = IeeeToInt(GetString(newPartInfo, 2), sSize, low, high, low);
endSector = IeeeToInt(GetString(newPartInfo, 3), sSize, startSector, high, high);
//创建分区:成功返回1,失败返回0
if (CreatePartition(newPartNum, startSector, endSector)) {
saveData = 1;
} else {
cerr << "Could not create partition " << newPartNum + 1 << " from "
<< startSector << " to " << endSector << "\n";
neverSaveData = 1;
} // if/else
//释放存放参数列表的char *空间
free(newPartInfo);
break;
...
}
...
}
uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) {
int retval = 1; // assume there'll be no problems
uint64_t origSector = startSector;
if (IsFreePartNum(partNum)) {
//确保起始扇区是能够被我们设置的边界对齐参数整除(全局变量sectorAlignment)
/*
Align(&startSector)函数操作如下
1. 如果startSector % sectorAlignment == 0那么直接返回成功
2. 否则 假设startSector=2049,sectorAlignment=8
该函数会定位两个区间[2048,2049]和[2049-2056],先从该第一个区间起始扇区++查看是否未被占用,如未被占用,则用作起始扇区
否则从第二个区间2056扇区--查看是否未被占用,如未被占用,则用作起始扇区
详细可查看如下Align(&startSector)实现
*/
if (Align(&startSector)) {
cout << "Information: Moved requested sector from " << origSector << " to "
<< startSector << " in\norder to align on " << sectorAlignment
<< "-sector boundaries.\n";
} // if
if (IsFree(startSector) && (startSector <= endSector)) {
if (FindLastInFree(startSector) >= endSector) {
partitions[partNum].SetFirstLBA(startSector);
partitions[partNum].SetLastLBA(endSector);
partitions[partNum].SetType(DEFAULT_GPT_TYPE);
partitions[partNum].RandomizeUniqueGUID();
} else retval = 0; // if free space until endSector
} else retval = 0; // if startSector is free
} else retval = 0; // if legal partition number
return retval;
}
int GPTData::Align(uint64_t* sector) {
int retval = 0, sectorOK = 0;
uint64_t earlier, later, testSector;
if ((*sector % sectorAlignment) != 0) {
earlier = (*sector / sectorAlignment) * sectorAlignment;
later = earlier + (uint64_t) sectorAlignment;
// Check to see that every sector between the earlier one and the
// requested one is clear, and that it's not too early....
if (earlier >= mainHeader.firstUsableLBA) {
sectorOK = 1;
testSector = earlier;
do {
sectorOK = IsFree(testSector++);
} while ((sectorOK == 1) && (testSector < *sector));
if (sectorOK == 1) {
*sector = earlier;
retval = 1;
} // if
} // if firstUsableLBA check
// If couldn't move the sector earlier, try to move it later instead....
if ((sectorOK != 1) && (later <= mainHeader.lastUsableLBA)) {
sectorOK = 1;
testSector = later;
do {
sectorOK = IsFree(testSector--);
} while ((sectorOK == 1) && (testSector > *sector));
if (sectorOK == 1) {
*sector = later;
retval = 1;
} // if
} // if
} // if
return retval;
} // GPTData::Align()