软件包升级后无法重新安装/恢复为只读


13

我正在使用Debian Stretch。我的根分区已安装read-only。仅当我安装或升级软件包时,才/重新安装到read-write(通过使用apt钩子),然后重新安装回ro

有时在软件包升级后,我无法重新安装/回只读状态:

mount -o remount,ro /
mount: / is busy

在较旧的Debian版本(Wheezy)上,我可以列出已与取消链接的打开文件lsof

 lsof +L1

或者,更具体地说,是防止阻止/重新安装到ro的文件:

{ lsof +L1 ; lsof|sed -n '/SYSV/d; /DEL|(path /p;' ; } | grep -Ev '/(dev|home|tmp|var)'

但是,在Debian Stretch上,lsof +L1不会列出任何文件。

我没有看到任何改变+|-Lman lsof这可以解释为什么它停止工作。

为什么lsof + L1不再列出已取消链接的打开文件?

如何列出阻止/重新挂载为只读的文件?

更新

我已经停止了所有可以停止的进程,只有它们可以运行,init并且getty仍在运行,但是仍然无法重新安装/ro


未链接的打开文件不是唯一的障碍。例如,在输出的列中查找w或,或在的输出中查找。不过,我无法提供详尽的清单。您可能还需要安装needrestart软件包。uFDlsofFfuser -vm /
FerencWágner17年

愚蠢的问题,但您是否将lsof执行为root
Kiwy,

1
Kiwy-是的,我以root身份执行lsof。
Martin Vegter

1
fuser -m / 知道用root做什么?
Rui F Ribeiro

1
@Marcus Linsner-我没有使用systemd。我正在使用init。
Martin Vegter

Answers:


2

如何列出阻止/重新挂载为只读的文件?

A)fuser可以在psmisc包装中找到;这是一个用例,我发现fuser它比&更有用lsof

# fuser -v -m / 2>&1 | grep '[Ff]r.e'

这将显示所有在/上打开文件以供读取(f)和写入(F)的进程。阻止/重新挂载为只读的文件是那些已打开以进行写入(F)的文件。

杀死正在运行可执行文件,其中打开了用于写入的根目录文件的进程,即

# for fupid in $(fuser -v -m / 2>&1 | grep Fr.e | awk '{print $2}'); do kill $fupid; done

这是systemd带有警告的注释之上的内容。如果systemd是,init那么fuser将会看到它,并且还有其他注意事项。通过systemd运行,它可以(重新)启动背后的进程,即使它们只是被识别和杀死fusersystemd比传统的要先进得多sysvinit

B)说明中的UPDATE表示系统仅具有... init并且getty仍在运行 ...

我看到评论说系统未使用systemd,正在使用init。顺带一提,systemd init。注释没有明确说sysvinit,所以我假设有问题的系统可以使用默认拉伸systemdinit。或其他偶然systemd发现使用Stretch's的人发现此部分很有用。

根据Debian Wiki

系统初始化过程由init守护程序处理。在squeeze和早期版本中,该守护进程由sysvinit软件包提供,并且不支持任何替代方法。wheezy中,默认的init守护进程仍然是sysvinit,但是systemd的“技术预览”可用。jessieStretch中,默认的初始化系统是systemd,但是支持切换到sysvinit。

从jessie开始,仅完全支持systemd。sysvinit大部分受支持,但是提供sysvinit启动脚本不需要Debian软件包。runit也已打包,但未获得与其他级别相同的测试和支持,并且当前不作为PID 1支持。

随着systemd运行,也有应采取腾出/以便它可以没有问题地重新安装一些额外的步骤。

可能system.slice正在为systemd-journald.servicesystemd-udevd.service(两者都具有套接字依赖项)保存打开的文件。或者,如果NetworkManager正在运行,可以重生dhclient其写入契约,以在/ var / ...在/ var /并非总是自己的设备)等 fuser可能会发现与你杀了dhclient,但NetworkManager启动时,它马上站起来。

道德是,很多事情都是自动化的,可能会“ /”(甚至更是如此systemd)。

可以肯定的是,如果可行,则systemd运行级别1 的等效项由匹配rescue.target(并且runlevel1.target是的符号链接rescue.target)。

1)首先将系统隔离到 rescue.target

# systemctl isolate rescue.target

它会提示您输入root密码。按照屏幕上的说明进行操作。

2)在救援壳上,找出要/的内容。

# systemctl show -p Wants /

通常情况下,它的system.slice; 停止一切想要的。例如

# systemctl stop system.slice

3)在这一点上,重新装入应该报告mount: / is busymount -o remount,ro / 工作。如果不是,请使用再次检查fuser

4)FWIW;我还看到了umount何时/如果将另一个设备安装在另一个安装的子目录(即嵌套安装)上而失败的情况。例如,umount /如果/ var // boot /在另一台设备上(并已挂载),则失败。虽然mount -o remount,ro /在这种情况下仍然可以使用。

lsblk 有助于可视化嵌套的安装座。

为什么lsof + L1不再列出已取消链接的打开文件?

因为它们不可用(套接字或大多数FIFO和管道),所以它们不再打开文件(父进程关闭了文件描述符),或者它们(仍然)的链接数大于1。

man lsof(8)的详细信息...

+ | -L [l]

此选项启用('+')或禁用('-')文件链接计数的列表(如果有)-例如,套接字,大多数FIFO和管道不可用。

如果指定+ L而没有后面的数字,则将列出所有链接计数。如果指定-L(默认值),则不会列出任何链接计数。

当+ L后跟一个数字时,只会列出链接数少于该数字的文件。(-L后面不能有数字。)格式为“ + L1”的规范将选择已取消链接的打开文件。表单的规范+aL1 <file_system>将在指定的文件系统上选择未链接的打开文件。


0

/proc装好了吗?

显然,/大多数人都是照顾只读的人,我可以想象您可能还选择不装载procfs。但是lsof,查找打开的文件需要它。

内核通过procfs中的符号链接公开由进程打开的文件。目录/proc/<pid>/fd包含每个保持打开状态的文件的符号链接。符号链接的名称是文件描述符号,符号链接引用的路径是文件路径。

悬挂的符号链接仍然保留在/proc已删除的打开文件中。并且文件的引用路径被重命名为以“(已删除)”结尾。

什么lsof +L1确实是一个快速班轮一样本质上没有不同:

stat -c%N /proc/[0-9]*/fd/* | grep deleted

因此,您可以使用类似的单行代码列出所有打开的文件,这些文件可能会阻止重新挂载根文件系统(前提是工作正常/proc)。

但是,如果您确实已经/proc安装了它,那么我能想到的唯一其他原因就是错误……总之,老实说,在我当前的Debian Stretch系统上。lsof +L1可以正常工作。

bash# lsb_release -d
Description:    Debian GNU/Linux 9.5 (stretch)

bash# uname -a
Linux bwp-249-8 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u4 (2018-08-21) x86_64 GNU/Linux

bash# lsof -v
lsof version information:
    revision: 4.89
    [...]

是的,我已经/proc坐骑了。我不遵循您的理由,为什么我可能没有。无论如何,stat -c%N /proc/[0-9]*/fd/* | grep deleted什么也没给我显示。
Martin Vegter '18

0

我只能重现此问题一次,并且仅通过mount-n选项一起使用即可解决。

报价人坐骑

-n, --no-mtab
      Mount without writing in /etc/mtab.  This is necessary for example when /etc is on a read-only filesystem.

mount打开文件(S)程序本身编写的根文件系统听起来像一个合理的解释给我。毕竟,专门mount写操作通常是根文件系统的一部分。但是,我做完一次之后就无法在同一台机器上再次再现它。/etc/mtab/etc

这样可以解决您的问题吗?


不,-n与mount一起使用没有区别。
Martin Vegter '18

0

没有对系统的可见性,很难准确地告诉您问题出在哪里。评论和以前的答案是一个好的开始。

就是说,我将一路追溯到Debian Wiki,该Wiki描述了安装/只读的prereq。

文档的链接在这里:https : //wiki.debian.org/ReadonlyRoot

最重要的是,我将带您了解这里:

1-/下的特定位置必须是可读写的。根据文档,它看起来像这样:

德比安根

您的块设备可能会有所不同,具体取决于您的存储堆栈配置(分区,无分区的lvm等)。但是主要思想是,您需要这4个挂载点才能使它们的后续挂载文件系统具有RW挂载选项。

2-/ etc中有许多特殊文件,您需要为它们创建符号链接或实施一些其他更改(在链接的文章中有详细说明)。这些可能根据您的linux服务器正在运行的应用程序而适用,也可能不适用。您的计算机上甚至可能不存在某些文件,但是我将所有内容都包含在文档中。请记住,即使您杀死了该过程的进程,我也强烈建议进行这些更改。以下是直接来自debian Wiki的路径:

  • adjtime
  • init.d / alsa-utils
  • / etc / courier / shared / index
  • 任何杯子状态文件,classes.conf,cupsd.conf,printers.conf subscriptions.conf
  • /etc/lvm/lvm.conf
  • mtab(看起来像您尝试通过挂载-n标志来解决)
  • 网络/运行(在压缩中由ifup和ifdown使用,可能不适用于拉伸,ymmv)
  • Nologin
  • resolv.conf
  • 密码和影子文件
  • 桑巴/dhcp.conf
  • 乌德夫

检查完所有上述内容并确认它们符合Wiki规范后,接下来要检查的是/etc/apt/apt.conf。

DPkg {
// Auto re-mounting of a readonly /
Pre-Invoke { "mount -o remount,rw /"; };
Post-Invoke { "test ${NO_APT_REMOUNT:-no} = yes || mount -o remount,ro / || true"; };
}; 

根据您的错误,您可以根据文档检查的最终内容来自以下内容:

“升级软件包后,您可能会遇到安装拒绝以只读方式告诉您“ /很忙”的文件系统挂载的问题。这是由删除的文件引起的,它们仍被进程使用。要找出使用删除文件的进程,请使用软件包debian-goodies中的checkrestart(1)工具或使用以下命令。通常这些是使用升级库的守护程序。必须重新启动它们才能释放文件。”

文档中提供的命令:

{lsof +L1; lsof|sed -n '/SYSV/d; /DEL\|(path /p;'} |grep -Ev '/(dev|home|tmp|var)'

在不知道您的确切文件系统配置,分区和存储设备配置的情况下,很难为您提供其他帮助。我将首先返回并重新检查文档中的前提条件(并在上面概述)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.