如何确保在卸载文件系统之前杀死所有进程?

如何确保在卸载文件系统之前杀死所有进程?

我正在尝试卸载一个繁忙的文件系统,该文件系统上的多线程程序正在发生连续的 I/O 读取和写入,因此 umount 命令失败。

root@ubuntu:~ # umount /mount/v1
umount: /mount/v1: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))

现在,我尝试使用以下命令终止所有进程

/sbin/fuser -m /mount/v1 -k

但根据定影命令

fusionr -k 或 -K 可能无法检测并终止程序开始运行后立即创建的新进程。

这就是我的情况,因为某些线程可能同时发出 IO 请求。当我再次卸载文件系统时,它再次说它正忙,这变成了一个循环。

我的问题是,如何确保没有新进程能够对文件系统进行一次读/写操作

/sbin/fuser -m /mount/v1 -k

发出命令以便可以正常卸载文件系统。

答案1

这里有两种方法,如果您不信任您的应用程序,可以直接转到第二种方法。

1.umount --lazy

如果那些干扰进程没有chdir())进入安装点(例如使用绝对路径)并且您知道它们最终会放弃,那么在 Linux 上您可以使用umount --lazy:内核将从目录树状结构中取消文件系统的映射,使其无法访问新的访问并在最后一个引用消失时自动卸载它。引用可以是一个打开的 fd、一个 cwd、一个内部挂载点(最后一个可能会很糟糕)...

但这不会影响进程/线程将引用保留在“内部”,例如仍然打开文件描述符或具有西德里面。那么这将变得更加困难,因为现在文件系统不再可访问,并且跟踪违规进程/线程变得更加困难(例如:fuser -m将不再找到它们)。因此,您需要进程才能正确执行此方法。

2.冷冻机组

应该适用的替代解决方案行为不好进程:将所有这些进程(和线程)分组到同一个冷冻机 cgroup 中。将它们全部冻结,防止它们将资源使用添加到挂载点(通过分叉/克隆/打开新的 fd)。即使您在第一次循环中错过了一些,您最终也会在后续迭代中捕获所有新内容。由于它们现在已被冻结,因此不会发生新的活动:您现在可以将它们全部杀死。对于 cgroups v1,已经由操作系统初始化(例如:通过系统或者CG经理,否则你必须弄清楚如何安装 freeze cgroup 子系统),这样的东西应该有效。请注意,显然写入cgroup.procs应该包括应该出现的所有线程,tasks但有不可靠行为的报告,所以以防万一我也迭代线程,即使这可能不需要(即:tasks可能已经正确填充了线程,所以循环for t是多余的)。

mkdir -p /sys/fs/cgroup/freezer/prepareumount

echo FROZEN > /sys/fs/cgroup/freezer/prepareumount/freezer.state

for i in $(seq 1 10); do
    for p in $(fuser -m /mount/v1 2>/dev/null); do
        echo $p > /sys/fs/cgroup/freezer/prepareumount/cgroup.procs
        for t in $(ps -L -o tid= -p $p); do
            echo $t > /sys/fs/cgroup/freezer/prepareumount/tasks
        done
    done
done

#give time to an overloaded kernel to freeze everything (FREEZING->FROZEN)
while ! cat /sys/fs/cgroup/freezer/prepareumount/freezer.state | grep -q FROZEN; do
    sleep 0.1
done

# kills, delayed
for i in $(cat /sys/fs/cgroup/freezer/prepareumount/cgroup.procs); do
    kill -KILL $i
done

# actual kills happen now, at once
echo THAWED > /sys/fs/cgroup/freezer/prepareumount/freezer.state

sleep 1
umount /mount/v1

如果使用 cgroups v2,则必须对此进行调整。

相关内容