qemu对ofd锁的支持
概述这是一个issue驱动的问题探究涉及ubuntu20、24systemd、qemu、docker、buildx等系统组件。问题我在ubuntu20的x86服务器上构建arm的docker使用qemu来进行虚拟化运行。报错Failed to take/etc/passwd lock: Invalid argumentdpkg: error processing package systemd (--configure):installed systemd package post-installation script subprocess returned error exit status 1Processing triggers for libc-bin (2.39-0ubuntu8.2) ...Errors were encountered while processing:systemdE: Sub-process /usr/bin/dpkg returned an error code (1)我在wsl2 ubuntu24上执行相同的命令则没问题需要进行分析为什么分析一步一步拆分在qemu上运行 flock是没问题的执行postinst是有问题的。bash脚本单行执行bash -x /var/lib/dpkg/info/systemd.postinst configure 255.4-1ubuntu8.16 21 | tee postinst.log然后 看到是 systemd-sysusers basic.conf systemd-journal.conf systemd-network.conf 的 报错。问题在systemd-sysusers然后查看对应的源码这里默认使用的是ofd锁。if (!arg_dry_run) { lock take_etc_passwd_lock(arg_root); if (lock 0) return log_error_errno(lock, Failed to take /etc/passwd lock: %m); } take_etc_passwd_lock int unposix_lock(int fd, int operation) { return fcntl_lock(fd, operation, /*ofd*/ true); } static int fcntl_lock(int fd, int operation, bool ofd) { int cmd, type, r; assert(fd 0); if (ofd) cmd (operation LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW; else cmd (operation LOCK_NB) ? F_SETLK : F_SETLKW; switch (operation ~LOCK_NB) { case LOCK_EX: type F_WRLCK; break; case LOCK_SH: type F_RDLCK; break; case LOCK_UN: type F_UNLCK; break; default: assert_not_reached(); } r RET_NERRNO(fcntl(fd, cmd, (struct flock) { .l_type type, .l_whence SEEK_SET, .l_start 0, .l_len 0, })); if (r -EACCES) /* Treat EACCESS/EAGAIN the same as per man page. */ r -EAGAIN; return r; }知道是ofd锁的问题然后就是写了一个最简单使用ofd锁的程序#define _GNU_SOURCE #include stdio.h #include fcntl.h #include unistd.h int main() { int fd open(/tmp/test.lock, O_WRONLY | O_CREAT, 0600); if (fd 0) { perror(open); return 1; } struct flock fl { .l_type F_WRLCK, .l_whence SEEK_SET, .l_start 0, .l_len 0 }; if (fcntl(fd, F_OFD_SETLK, fl) 0) printf(OFD lock succeeded\n); else perror(OFD lock failed); close(fd); return 0; }静态编译这个程序然后 用来测试。对比了一下火山云和wsl2环境的区别主要是ubuntu24然后 qemu 版本也有差别qemu 4.2.1对比 qemu 8.2.2查看了一下开源社区的issueBug #2069555 “Failed to take /etc/passwd lock: Invalid argument ...” : Bugs : systemd package : UbuntuFailed to take /etc/passwd lock on latest qemu-aarch64-static environment. · Issue #214 · multiarch/qemu-user-static · GitHub然后在相同的环境尝试下载不同版本的qemu进行对比wget https://github.com/multiarch/qemu-user-static/releases/download/v5.2.0-1/qemu-aarch64-static最终解决方案在ubuntu20的环境中手动替换 qemu-aarch64-static 二进制。替换完之后就ok了。后续探究qemu与binfmts之间的关系qemu的源码学习ofd锁的创新点