在系统日志中,偶尔看到很多device appeared twice with different sysfs paths
的错误提示,类似如下
Aug 1 06:32:34 dev21 systemd: Device dev-disk-by\x2dpartlabel-xxx.device appeared twice with different sysfs paths /sys/devices/pci0000:00/0000:00:0e.0/virtio11/block/vdj/vdj2 and /sys/devices/pci0000:00/0000:00:0e.0/virtio11/block/vdj/vdj1
这种日志可以有多种方式触发产生,读者的日志可能和我的不太一样,触发原因也可能不同,不过没关系,搞清楚产生原因说不定就能帮你定位问题。首先通过上面的日志,需要先看清3个东西:
dev-disk-by\x2dpartlabel-xxx => /dev/disk/by-partlabel/xxx
/sys/devices/pci0000:00/0000:00:0e.0/virtio11/block/vdj/vdj2 => /dev/vdj2
/sys/devices/pci0000:00/0000:00:0e.0/virtio11/block/vdj/vdj1 => /dev/vdj1
字面解释,就是/dev/disk/by-partlabel/xxx被不同的sysfs路径的设备添加,这两个设备对应的是/dev/vdj1和/dev/vdj2
先说下/dev/disk/by-partlabel/xxx
这个是怎么产生的, 直接看命令
# 首先确认xxx这个文件是不存在的
# ll /dev/disk/by-partlabel/xxx
ls: cannot access /dev/disk/by-partlabel/xxx: No such file or directory
# 将vdj的分区表类型改成gpt
# parted -s /dev/vdj mklabe gpt
# 对vdj进行分区,同时指定part-name,就是xxx
# parted -s /dev/vdj mkpart xxx 2048s 10g
# 此时发现/dev/disk/by-partlabel/xxx链接已经产生的,说明xxx是在分区的时候产生的,此文件只是一个指向分区的链接
# ll /dev/disk/by-partlabel/xxx
lrwxrwxrwx. 1 root root 10 8月 1 06:51 /dev/disk/by-partlabel/xxx -> ../../vdj1
# 当再次使用xxx这个名字继续分区的时候,发现/dev/disk/by-partlabel/xxx指向的还是vdj1
# 而此时系统日志里面报出了device appeared twice with different sysfs paths的错误
# parted -s /dev/vdj mkpart xxx 10g 20g
lrwxrwxrwx. 1 root root 10 8月 1 06:51 /dev/disk/by-partlabel/xxx -> ../../vdj1
# 再次分区,使用新的名字xxx2,发现xxx2指向vdj3
# parted -s /dev/vdj mkpart xxx2 20g 30g
# ll /dev/disk/by-partlabel/xxx*
lrwxrwxrwx. 1 root root 10 8月 1 06:52 /dev/disk/by-partlabel/xxx -> ../../vdj1
lrwxrwxrwx. 1 root root 10 8月 1 06:52 /dev/disk/by-partlabel/xxx2 -> ../../vdj3
通过上面的复现方法,原因已经比较明了了,当创建分区时,系统(实际是systemd)会在/dev/disk/by-partlabel/下创建分区时自定的name,当使用相同name分区时,系统检测到/dev/disk/by-partlabel/name已经存在,就会报device appeared twice with different sysfs paths
这个日志了,解决我的问题方式就是每次使用不同的name
分区即可。
具体的systemd的代码块如下, 完整的代码在这里
if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) {
/* This unit is in plugged state: we're sure it's
* attached to a device. */
if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
log_unit_error(u, "Dev %s appeared twice with different sysfs paths %s and %s",
e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
}
}
其实这只是一个告警,在最新的systemd代码里面,作者已经将log_unit_error
改成了log_unit_debug
,diff在这里
总结:
当系统产生新的dev设备时,systemd会在/dev下创建对应的设备,同时还会在对应的目录下创建该设备的符号链接,可能的目录如下,如果出现不同设备创建了相同的符号链接,系统日志就会报此错误。
# 常见的是这4个,可能还有其他位置
/dev/disk/by-id
/dev/disk/by-path
/dev/disk/by-uuid
/dev/disk/by-partlabel
对于其他原因触发该日志,解决的方式类似,先找是哪个deivce冲突了(本例中的/dev/disk/by-partlabel/xxx),找出是谁产生的该device(本例中的parted),再找出两个设备(本例中的/dev/vdj1和/dev/vdj2)产生相同device的原因。
需要强调的是,在一些应用上这个日志是避免不掉的,比如当使用多路径(multipath)功能时,多个scsi设备通过不同路径过来,产生不同的scsi设备,但他们的scsi-id是一样的,systemd会在/dev/disk/by-id下产生相同的/dev/disk/by-id/scsi-xxxxx符号链接,此时也会报此日志,且无法避免。
所以只要明确日志产生原因,确认上层业务不会用到这个冲突的device链接,那就不用关心此日志。
补充:
本例中使用parted分区的时候,使用的是如下命令,而和parted的帮助文档描述的用法不一样:mkpart PART-TYPE [FS-TYPE] START END
,这是因为分区表类型为gpt时,parted的帮助文档描述有误,具体的出处在这里
# parted -s /dev/vdj mkpart xxx 2048s 10g