partprobe源码分析
生活随笔
收集整理的這篇文章主要介紹了
partprobe源码分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
partprobe工具
操作系統目錄/usr/sbin/partprobe
程序安裝包parted-3.1-17.el7.x86_64.rpm
命令用法:
partprobe是用來告知操作系統內核 分區表發生變化的工具,告知方式是請求內核重讀分區表
選項如下:
-d 不會讓內核重讀分區表,分區表發生變化后使用該命令partproe -d /dev/sdi不會告知內核分區發生了變化
-s 先讓內核重讀分區表,再顯示設備已擁有的分區信息
[root@node1 ~]# partprobe -s /dev/hda
/dev/hda: msdos partitions 1 2 3 4 <5 6 7 8 9> #4分區為擴展分區,符號<內部的分區為邏輯分區
-h 顯示幫助選項信息
-v 顯示程序的版本信息
源碼分析
partprobe主要操作是 告知操作系統內核 磁盤分區表發生了變化,接下來操作由內核完成。內核會先刪除當前系統緩存中的磁盤分區表,然后重新從磁盤中讀取分區表,主要通過io驅動函數ioctl來完成
執行partprobe命令基本代碼流程如下:
- 正常的
getopt_long函數的命令行解析 - 根據是否傳入磁盤進行判斷,如果傳入磁盤,如
partprobe /dev/sdb則進行磁盤處理;如未傳入制定磁盤,則先獲取到當前設備所有的磁盤,并加入到鏈表中,然后順序執行分區表處理
partprobe.c中的主函數處理如下int n_dev = argc - optind; //獲取是否傳入磁盤參數 if (n_dev != 0) {//如果傳入則一個一個處理int i;for (i = optind; i < argc; i++) { PedDevice *dev = ped_device_get (argv[i]);if (dev == NULL || process_dev (dev) == 0) //process_dev分區處理的主函數status = 1;} } else {//否則先獲取當前設備所有磁盤ped_device_probe_all ();//將獲取到的磁盤加入到全局鏈表中PedDevice *dev;for (dev = ped_device_get_next (NULL); dev;//遍歷鏈表,一個一個順序執行分區檢測dev = ped_device_get_next (dev))if (process_dev (dev) == 0)status = 1; } - 從磁盤將分區表讀到內存中,并告知操作系統內核分區表的布局
static int process_dev (PedDevice* dev) {PedDiskType* disk_type;PedDisk* disk;disk_type = ped_disk_probe (dev); //獲取分區類型,gpt?msdos?if (!disk_type || !strcmp (disk_type->name, "loop"))return 1;/*創建一個新的分區表,并存放在內存中。當調用ped_disk_commit_to_dev函數,由內核決定是否寫入磁盤*/disk = ped_disk_new (dev);if (!disk)goto error;/*該參數為我們的-d參數,即partprobe -d /dev/sdb 表示不會執行告知內核磁盤分區情況的操作,如傳入-d參數,則當前數值為1*/if (!opt_no_inform) { if (!ped_disk_commit_to_os (disk)) //內核操作的主函數goto error_destroy_disk;}/*該參數表示 partprobe -s參數,執行是否打印磁盤分區信息的操作*/if (opt_summary)/*打印當前磁盤分區的情況*/summary (disk);ped_disk_destroy (disk);return 1;error_destroy_disk:ped_disk_destroy (disk); error:return 0; } - 內核操作分區表版本如下,
ped_disk_commit_to_os函數操作- 在內核版本為2.4之前,partprobe會調用BLKRRPART ioctl函數讓內核重讀分區表
- 在2.4.x之后的內核已經更改為使用新的blkpg接口告訴內核每一個磁盤分區的起始,結束地址。所以,在新版本內核中,不會因為分區表類型不同而無法讀取磁盤分區表
//通過ped_disk_commit_to_os 函數調用的回掉函數disk_commit(disk)進行內核分區的處理 ped_disk_commit_to_os(PedDisk* disk){...if (!ped_architecture->disk_ops->disk_commit (disk)) }PedDiskArchOps linux_disk_ops = {partition_get_path: linux_partition_get_path,partition_is_busy: linux_partition_is_busy,disk_commit: linux_disk_commit //通過改數據結構調用linux_disk_commit函數進行處理 };/*告知內核磁盤分區的布局*/ static int linux_disk_commit (PedDisk* disk) {if (!_has_partitions (disk))return 1; /*若系統支持邏輯卷方式管理磁盤,且磁盤分區類型為支持dm,一般為msdos格式即mbr分區,則重讀分區表。一半存放在/dev/mapper目錄*/ #ifdef ENABLE_DEVICE_MAPPER if (disk->dev->type == PED_DEVICE_DM)return _dm_reread_part_table (disk); #endif/*如果設備類型為普通文件類型,即文件形式存放的,一般為我們的gpt分區類型的磁盤*/if (disk->dev->type != PED_DEVICE_FILE) {/*要求當前內核支持blkpg的新特性,即使用blkpg接口告知內核磁盤分區表的起始地址,不需要內核自己去讀。如果當前內核不支持該特性,或者這里發現有斷言退出,可以直接將改行注釋掉*/assert (_have_blkpg ());/*內核同步磁盤分區表的主函數*/if (!_disk_sync_part_table (disk)) return 0;}return 1; } - 內核同步磁盤分區表的操作,即我們partprobe的主要操作
- 通過io設備驅動程序的通道管理函數ioctl,先從內核移除所有的分區表。但是當ioctl執行失敗時,不會對此時失敗的分區表進行移除
- 從我們遍歷到的磁盤中添加分區表。如果我們因為第一步移除分區表的失敗無法添加(因為使用的是blkpg新特性,移除以及添加需要保證分區表的起始結束地址一直才能確定執行成功),則進行告警
static int _disk_sync_part_table (PedDisk* disk) {.../*從/sys/block/dev_name/range文件中獲取當前系統支持的單個磁盤最大分區數量,如果獲取不到,則使用默認的64*/lpn = _device_get_partition_range(disk->dev);.../*對當前磁盤執行分區刪除操作通過調用_blkpg_part_command(disk->dev, &linux_part,BLKPG_DEL_PARTITION)函數執行ioctl (arch_specific->fd, BLKPG, &ioctl_arg)的分區刪除操作*/_blkpg_remove_partition (disk, j + 1);.../*同樣通過_blkpg_part_command (disk->dev, &linux_part,BLKPG_ADD_PARTITION)函數執行ioctl (arch_specific->fd, BLKPG, &ioctl_arg)的分區添加操作*/_blkpg_add_partition (disk, part);/*根據執行的結果是否拋出異常進行告警*/ }
關于常見的兩種問題的告警描述如下:
- "Error informing the kernel about modifications to "
"partition %s – %s. This means Linux won’t know "
"about any changes you made to %s until you reboot "
"-- so you shouldn’t mount it or use it in any way "
"before rebooting.
該問題為內核向磁盤添加分區過程中ioctl程序執行失敗,一般為當前分區表x相關元數據信息錯誤 - Partition(s) %s on %s have been written, but we have "
"been unable to inform the kernel of the change, "
"probably because it/they are in use. As a result, "
"the old partition(s) will remain in use. You "
"should reboot now before making further changes.
該問題為內核刪除分區表時出現,因為分區仍然被占用,無法從緩存中清除該分區的起始和結束地址導致。
總結
以上是生活随笔為你收集整理的partprobe源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ceph-deploy rpm包的制作
- 下一篇: 漂亮女生租房的二三事,看脸的世界太荒谬(