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

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

我正在使用 Debian Stretch。我的根分区已挂载read-only。仅当我安装或升级软件包时,才会/重新安装到read-write(通过使用 apt hook),然后重新安装回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没有列出任何文件。

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

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

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

更新

我已经停止了所有可以停止的进程,并且只有init并且getty仍在运行,但我仍然无法重新挂载/ro.

答案1

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

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

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

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

杀死以下进程可执行文件正在运行,根目录文件打开以供写入。, IE

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

这是在systemd评论之上,但有一个警告。如果systemdinit那么fuser就会看到它并且还有其他考虑因素。通过systemd运行,它可以在您背后(重新)启动进程,即使它们刚刚被识别并杀死fusersystemd比传统的先进很多sysvinit

B) 的更新描述中指出系统只有...initgetty仍在运行...

我看到评论说系统没有使用systemd,它正在使用init。在伸展时,systemd init。该评论没有明确指出sysvinit,所以我假设有问题的系统可能正在使用默认的systemd拉伸init。或者其他偶然发现这篇文章的人,正在使用拉伸的人systemd,发现这部分很有用。

根据Debian 维基,

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

自jessie以来,仅完全支持systemd;大多数情况下都支持 sysvinit,但 Debian 软件包不需要提供 sysvinit 启动脚本。 runit 也已打包,但尚未获得与其他程序相同级别的测试和支持,并且当前不支持 PID 1。

运行时systemd,应采取一些额外的步骤来释放/以便可以毫无问题地重新安装。

它可能system.slice正在保存systemd-journald.service或 的打开文件systemd-udevd.service(两者都具有套接字依赖性)。或者,如果NetworkManager正在运行它可以重生dhclient,并将租约写入/var/...(&/var/并不总是它自己的设备)等 fuser可能会找到并杀死它dhclient,但NetworkManager会立即启动它。

其寓意是,很多事情都是自动化的,可以“想要”/(对于 更是如此systemd)。

可以肯定的是,如果可行的话,运行级别 1 的等效项将与(并且是到 的符号链接)systemd相匹配。rescue.targetrunlevel1.targetrescue.target

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

# systemctl isolate rescue.target

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

2)在rescue shell中,找出想要的/。

# systemctl show -p Wants /

通常,它是system.slice;停止一切想要的/。例如

# systemctl stop system.slice

3)此时,重新挂载应该不是报告mount: / is busymount -o remount,ro / 应该工作。如果没有,请再次检查fuser

4)FWIW;我还看到过umount当/如果另一个设备安装在另一个安装的子目录(即嵌套安装)上时会失败。例如,umount /如果/var/或者/启动/位于另一台设备上(并已安装)。虽然mount -o remount,ro /在这种情况下应该仍然有效。

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

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

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

男人LSof(8)细节 ...

+|-L[l]

此选项启用(“+”)或禁用(“-”)文件链接计数列表,它们在可用的地方 - 例如,它们不适用于套接字或大多数 FIFO 和管道。

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

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

答案2

/proc装了吗?

/显然,作为一个大部分时间都注意挂载只读的人,我可以想象您也可能选择不挂载 procfs。但需要 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
    [...]

答案3

我只能重现这个问题一次,并通过使用解决了它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本身打开文件写作在根文件系统中对我来说听起来是一个合理的解释。毕竟,具体mount写入/etc/mtab通常/etc是根文件系统的一部分。然而,在我做了一次之后,我无法在同一台机器上再次重现它......

这可以解决您的问题吗?

答案4

如果不了解您的系统,就很难准确地告诉您问题是什么。评论和之前的答案是良好的开始。

也就是说,我会一路回顾 debian wiki,其中描述了安装/只读的先决条件。

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

最重要的是,我将引导您完成这里:

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

debian ro 根

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

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

  • 调整时间
  • init.d/alsa-utils
  • /etc/courier/shared/index
  • 任何 cups 状态文件、classes.conf、cupsd.conf、printers.conf、subscriptions.conf
  • /etc/lvm/lvm.conf
  • mtab(看起来您试图通过给 mount 添加 -n 标志来解决这个问题)
  • 网络/运行(由ifup和ifdown使用,在squeeze中。可能不适用于stretch、ymmv)
  • 诺登录
  • 解析配置文件
  • passwd 和影子文件
  • 桑巴/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)'

如果不知道确切的文件系统配置、分区和存储设备配置,就很难为您提供更多其他信息。我将首先返回并重新检查文档中的先决条件(以及上面概述的)。

相关内容