partprobe源码分析
生活随笔
收集整理的這篇文章主要介紹了
partprobe源码分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
partprobe工具
操作系統(tǒng)目錄/usr/sbin/partprobe
程序安裝包parted-3.1-17.el7.x86_64.rpm
命令用法:
partprobe是用來告知操作系統(tǒng)內(nèi)核 分區(qū)表發(fā)生變化的工具,告知方式是請(qǐng)求內(nèi)核重讀分區(qū)表
選項(xiàng)如下:
-d 不會(huì)讓內(nèi)核重讀分區(qū)表,分區(qū)表發(fā)生變化后使用該命令partproe -d /dev/sdi不會(huì)告知內(nèi)核分區(qū)發(fā)生了變化
-s 先讓內(nèi)核重讀分區(qū)表,再顯示設(shè)備已擁有的分區(qū)信息
[root@node1 ~]# partprobe -s /dev/hda
/dev/hda: msdos partitions 1 2 3 4 <5 6 7 8 9> #4分區(qū)為擴(kuò)展分區(qū),符號(hào)<內(nèi)部的分區(qū)為邏輯分區(qū)
-h 顯示幫助選項(xiàng)信息
-v 顯示程序的版本信息
源碼分析
partprobe主要操作是 告知操作系統(tǒng)內(nèi)核 磁盤分區(qū)表發(fā)生了變化,接下來操作由內(nèi)核完成。內(nèi)核會(huì)先刪除當(dāng)前系統(tǒng)緩存中的磁盤分區(qū)表,然后重新從磁盤中讀取分區(qū)表,主要通過io驅(qū)動(dòng)函數(shù)ioctl來完成
執(zhí)行partprobe命令基本代碼流程如下:
- 正常的
getopt_long函數(shù)的命令行解析 - 根據(jù)是否傳入磁盤進(jìn)行判斷,如果傳入磁盤,如
partprobe /dev/sdb則進(jìn)行磁盤處理;如未傳入制定磁盤,則先獲取到當(dāng)前設(shè)備所有的磁盤,并加入到鏈表中,然后順序執(zhí)行分區(qū)表處理
partprobe.c中的主函數(shù)處理如下int n_dev = argc - optind; //獲取是否傳入磁盤參數(shù) if (n_dev != 0) {//如果傳入則一個(gè)一個(gè)處理int i;for (i = optind; i < argc; i++) { PedDevice *dev = ped_device_get (argv[i]);if (dev == NULL || process_dev (dev) == 0) //process_dev分區(qū)處理的主函數(shù)status = 1;} } else {//否則先獲取當(dāng)前設(shè)備所有磁盤ped_device_probe_all ();//將獲取到的磁盤加入到全局鏈表中PedDevice *dev;for (dev = ped_device_get_next (NULL); dev;//遍歷鏈表,一個(gè)一個(gè)順序執(zhí)行分區(qū)檢測(cè)dev = ped_device_get_next (dev))if (process_dev (dev) == 0)status = 1; } - 從磁盤將分區(qū)表讀到內(nèi)存中,并告知操作系統(tǒng)內(nèi)核分區(qū)表的布局
static int process_dev (PedDevice* dev) {PedDiskType* disk_type;PedDisk* disk;disk_type = ped_disk_probe (dev); //獲取分區(qū)類型,gpt?msdos?if (!disk_type || !strcmp (disk_type->name, "loop"))return 1;/*創(chuàng)建一個(gè)新的分區(qū)表,并存放在內(nèi)存中。當(dāng)調(diào)用ped_disk_commit_to_dev函數(shù),由內(nèi)核決定是否寫入磁盤*/disk = ped_disk_new (dev);if (!disk)goto error;/*該參數(shù)為我們的-d參數(shù),即partprobe -d /dev/sdb 表示不會(huì)執(zhí)行告知內(nèi)核磁盤分區(qū)情況的操作,如傳入-d參數(shù),則當(dāng)前數(shù)值為1*/if (!opt_no_inform) { if (!ped_disk_commit_to_os (disk)) //內(nèi)核操作的主函數(shù)goto error_destroy_disk;}/*該參數(shù)表示 partprobe -s參數(shù),執(zhí)行是否打印磁盤分區(qū)信息的操作*/if (opt_summary)/*打印當(dāng)前磁盤分區(qū)的情況*/summary (disk);ped_disk_destroy (disk);return 1;error_destroy_disk:ped_disk_destroy (disk); error:return 0; } - 內(nèi)核操作分區(qū)表版本如下,
ped_disk_commit_to_os函數(shù)操作- 在內(nèi)核版本為2.4之前,partprobe會(huì)調(diào)用BLKRRPART ioctl函數(shù)讓內(nèi)核重讀分區(qū)表
- 在2.4.x之后的內(nèi)核已經(jīng)更改為使用新的blkpg接口告訴內(nèi)核每一個(gè)磁盤分區(qū)的起始,結(jié)束地址。所以,在新版本內(nèi)核中,不會(huì)因?yàn)榉謪^(qū)表類型不同而無法讀取磁盤分區(qū)表
//通過ped_disk_commit_to_os 函數(shù)調(diào)用的回掉函數(shù)disk_commit(disk)進(jìn)行內(nèi)核分區(qū)的處理 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 //通過改數(shù)據(jù)結(jié)構(gòu)調(diào)用linux_disk_commit函數(shù)進(jìn)行處理 };/*告知內(nèi)核磁盤分區(qū)的布局*/ static int linux_disk_commit (PedDisk* disk) {if (!_has_partitions (disk))return 1; /*若系統(tǒng)支持邏輯卷方式管理磁盤,且磁盤分區(qū)類型為支持dm,一般為msdos格式即mbr分區(qū),則重讀分區(qū)表。一半存放在/dev/mapper目錄*/ #ifdef ENABLE_DEVICE_MAPPER if (disk->dev->type == PED_DEVICE_DM)return _dm_reread_part_table (disk); #endif/*如果設(shè)備類型為普通文件類型,即文件形式存放的,一般為我們的gpt分區(qū)類型的磁盤*/if (disk->dev->type != PED_DEVICE_FILE) {/*要求當(dāng)前內(nèi)核支持blkpg的新特性,即使用blkpg接口告知內(nèi)核磁盤分區(qū)表的起始地址,不需要內(nèi)核自己去讀。如果當(dāng)前內(nèi)核不支持該特性,或者這里發(fā)現(xiàn)有斷言退出,可以直接將改行注釋掉*/assert (_have_blkpg ());/*內(nèi)核同步磁盤分區(qū)表的主函數(shù)*/if (!_disk_sync_part_table (disk)) return 0;}return 1; } - 內(nèi)核同步磁盤分區(qū)表的操作,即我們partprobe的主要操作
- 通過io設(shè)備驅(qū)動(dòng)程序的通道管理函數(shù)ioctl,先從內(nèi)核移除所有的分區(qū)表。但是當(dāng)ioctl執(zhí)行失敗時(shí),不會(huì)對(duì)此時(shí)失敗的分區(qū)表進(jìn)行移除
- 從我們遍歷到的磁盤中添加分區(qū)表。如果我們因?yàn)榈谝徊揭瞥謪^(qū)表的失敗無法添加(因?yàn)槭褂玫氖莃lkpg新特性,移除以及添加需要保證分區(qū)表的起始結(jié)束地址一直才能確定執(zhí)行成功),則進(jìn)行告警
static int _disk_sync_part_table (PedDisk* disk) {.../*從/sys/block/dev_name/range文件中獲取當(dāng)前系統(tǒng)支持的單個(gè)磁盤最大分區(qū)數(shù)量,如果獲取不到,則使用默認(rèn)的64*/lpn = _device_get_partition_range(disk->dev);.../*對(duì)當(dāng)前磁盤執(zhí)行分區(qū)刪除操作通過調(diào)用_blkpg_part_command(disk->dev, &linux_part,BLKPG_DEL_PARTITION)函數(shù)執(zhí)行ioctl (arch_specific->fd, BLKPG, &ioctl_arg)的分區(qū)刪除操作*/_blkpg_remove_partition (disk, j + 1);.../*同樣通過_blkpg_part_command (disk->dev, &linux_part,BLKPG_ADD_PARTITION)函數(shù)執(zhí)行ioctl (arch_specific->fd, BLKPG, &ioctl_arg)的分區(qū)添加操作*/_blkpg_add_partition (disk, part);/*根據(jù)執(zhí)行的結(jié)果是否拋出異常進(jìn)行告警*/ }
關(guān)于常見的兩種問題的告警描述如下:
- "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.
該問題為內(nèi)核向磁盤添加分區(qū)過程中ioctl程序執(zhí)行失敗,一般為當(dāng)前分區(qū)表x相關(guān)元數(shù)據(jù)信息錯(cuò)誤 - 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.
該問題為內(nèi)核刪除分區(qū)表時(shí)出現(xiàn),因?yàn)榉謪^(qū)仍然被占用,無法從緩存中清除該分區(qū)的起始和結(jié)束地址導(dǎo)致。
總結(jié)
以上是生活随笔為你收集整理的partprobe源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ceph-deploy rpm包的制作
- 下一篇: 漂亮女生租房的二三事,看脸的世界太荒谬(