使用flock来解决parted与udev竞争的问题

当块设备被parted写入后关闭时,udevd守护程序将调用BLKRRPART ioctl(通知内核重新读取分区表),同时parted会自行调用BLKPG_DEL_PARTITIONBLKPG_ADD_PARTITION。这通常没有问题,但当udevd设法在分区DELADD调用之间调用BLKRRPART时,有时会导致分区失败,如下所示:

Error: Error informing the kernel about modifications to partition /dev/sda1 -- Device or resource busy.  This means Linux won't know about any changes you made to /dev/sda1 until you reboot -- so you shouldn't mount it or use it in any way before rebooting.
Error: Failed to add partition 1 (Device or resource busy)

或者在重新格式化分区的时候遇到另外一个报错:

mkfs.vfat: unable to open /dev/vdc1p1: No such file or directory

跟踪udev源码可以看到:如果udev无法获取排他锁(flock(fd,LOCK_EX | LOCK_NB)),那么就不会触发BLKRRPART ioctl,反之就会触发该ioctl
相关信息也更新在systemd/NEWS:

CHANGES WITH 214
  * As an experimental feature, udev now tries to lock the
       disk device node (flock(LOCK_SH|LOCK_NB)) while it
       executes events for the disk or any of its partitions.
       Applications like partitioning programs can lock the
       disk device node (flock(LOCK_EX)) and claim temporary
       device ownership that way; udev will entirely skip all event
       handling for this disk and its partitions. If the disk
       was opened for writing, the close will trigger a partition
       table rescan in udev's "watch" facility, and if needed
       synthesize "change" events for the disk and all its partitions.
       This is now unconditionally enabled, and if it turns out to
       cause major problems, we might turn it on only for specific
       devices, or might need to disable it entirely. Device Mapper
       devices are excluded from this logic.

翻译成中文意思是:

  *作为一项实验性功能,udev现在尝试在执行磁盘或其任何分区的事件时,
       锁定磁盘设备节点(flock(LOCK_SH | LOCK_NB)),
       分区程序之类的应用程序可以锁定
       磁盘设备节点(flock(LOCK_EX))并声明为临时
       设备所有权的方式;udev将完全跳过
       处理该磁盘及其分区的所有事件。如果磁盘
       被打开进行写操作,关闭时将触发一个
       在udev的“监视”工具中的分区重新扫描,如果需要的话
       请自行同步磁盘及其所有分区的“更改”事件。
       现在已无条件启用此功能,如果结果
       造成重大问题,我们可能仅针对特定情况将其打开
       设备,或者根据需要完全禁用它。设备映射器
       设备不具备这个功能。

所以针对之前遇到的parted(或者partprobe)与udev竞争的问题,在运行打开写入模式设备的进程之前,获取独占锁是一种有效的解决方法,比如在脚本里面添加如下代码就可以解决该问题:

    udevadm settle --timeout=150
    while [[ true ]]; do
        flock -s /dev/sdb parted -s -a minimal /dev/sdb mkpart primary 1s 7500000s && break
        sleep 1
    done
    udevadm settle --timeout=150
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章