當塊設備被parted
寫入後關閉時,udevd
守護程序將調用BLKRRPART ioctl
(通知內核重新讀取分區表),同時parted
會自行調用BLKPG_DEL_PARTITION
和BLKPG_ADD_PARTITION
。這通常沒有問題,但當udevd
設法在分區DEL
和ADD
調用之間調用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