首页 > 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命令基本代码流程如下:

  1. 正常的getopt_long函数的命令行解析
  2. 根据是否传入磁盘进行判断,如果传入磁盘,如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;
    }
    
  3. 从磁盘将分区表读到内存中,并告知操作系统内核分区表的布局
    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;
    }
    
  4. 内核操作分区表版本如下,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;
    }
    
  5. 内核同步磁盘分区表的操作,即我们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);/*根据执行的结果是否抛出异常进行告警*/
      }
      

关于常见的两种问题的告警描述如下:

  1. "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相关元数据信息错误
  2. 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.

    该问题为内核删除分区表时出现,因为分区仍然被占用,无法从缓存中清除该分区的起始和结束地址导致。

更多相关:

  • lsblk命令(列出块设备)用于列出所有可用的块设备的信息,但是, 它并没有列出有关的RAM磁盘的信息。块设备的例子是硬盘,闪存驱动器,CD-ROM等等,一般可以和blkid命令搭配,blkid可以查看更详细的磁盘信息:uuid,label等 该命令存在于util-linux-2.23.2-26.el7.x86_64的包里 lsb...

  • 将数据库中所有表的所有的内容选一遍:   IF object_id('tempdb..#temp')   is   not   null      BEGIN DROP TABLE #temp END DECLARE @index int DECLARE @count int   DECLARE @schemaname varch...

  • 1.Tcpdive的基本原理 Tcpdive是基于linux内核的探测点机制,使用systemtap脚本语言和内嵌C代码来实现的。  通过定义几类相互关联的探测点和库函数,来收集和处理运行中内核的数据,以及修改内核的处理逻辑。 2.源码目录 https://github.com/fastos/tcpdive 目前的代码基...

  • 下面是我结合网上资料摸索出的可行的操作方法,记录在这样,以备后面继续研究。操作系统是CentOS 6.6 x86_64。 1.将内核版本升级到最新版 因为我机器上CentOS 6.6的内核版本号是2.6.32-573.12.1.el6.x86_64,网上根本找不到对应的kernel-devel,kernel-debuginfo和k...

  • 在基于CentOS平台的工作过程中,难免有时需要升级或者降级内核以验证功能、调试性能或者更新整个系统。 如果从头重新编译一个内核费时费力,另外加之现在内核特性越来越复杂,依赖的库或者工具也不少,找到一种简单的升级内核方法将非常必要。 下面是我实践过的最简单方法。 系统环境: CentOS 6.6 x86_64 1:查看系统版...

  • 关于系统目录树和源码目录树的结构图如下 内核版本: centos 7.0 升级内核之后 3.10.0-957-5.1.e17...

  • 下述为UCloud资深工程师邱模炯在InfoQ架构师峰会上的演讲——《UCloud云平台的内核实践》中非常受关注的内核热补丁技术的一部分。给大家揭开了UCloud云平台内核技术的神秘面纱。   如何零代价修复海量服务器的Linux内核缺陷?   对于一个拥有成千上万台服务器的公司,Linux内核缺陷导致的死机屡见不鲜。让工程师们纠结的...

  •   在config/index.js找到dev:{}里面的autoOpenBrowser: 设置为true,重新npm run dev一次就自动弹出浏览器页面啦!  ...

  • 工作中需要用到批量修改文件用户和组的情况,特记录以下便捷用法。 1.批量修改多个文件的user和group chown ats:ats /dev/sdc /dev/sdd /dev/sde /dev/sdf /dev/sdg /dev/sdh /dev/sdi /dev/sdj /dev/sdk /dev/sdl /dev/sdm...

  • ceph环境:12.2.1 使用古老的ceph-disk工具部署osd,仅仅prepare过程中就出现如上所示问题 Device is in use by a device-mapper mapping md127 解决方法如下: 由于device-mapper为系统自己的磁盘映射器,此时检查系统是否有逻辑卷 pvs lvs v...

  • 环境: ceph L版本12.2.1升级到12.2.12 这个问题是由于升级后进行12.2.12环境中的使用ceph-disk 进行osd部署时出现如下问题,执行命令 ceph-disk -v prepare /dev/sdb;ceph-disk -v activate /dev/sdb1 出现如下问题,出现这个问题之前我的磁盘用作...

  • 划分磁盘分区 sgdisk -n 1:+2G:+50G /dev/sda 划分磁盘分区,一号分区划分为50G,同时预留2G的空间 磁盘格式化 sgdisk -z -og /dev/sda 查看分区详情 sgdisk -i 1 /dev/hda查看hda第一分区的详情信息 [root@node3 ~]# sgdisk...