为什么文件系统已卸载但仍在使用?

为什么文件系统已卸载但仍在使用?

我使用 ext4 文件系统很长时间了,这是我第一次看到 ext4 文件系统的奇怪行为。 底层设备中发生 I/O 错误,并且该文件系统被重新挂载为只读,
其中存在 ext4 文件系统。这很好,符合配置的预期。但由于某种未知的原因,现在不可能完全卸载文件系统。 命令成功返回。进一步运行该命令会显示“未安装”。 安装条目已从命令输出中消失。文件系统未安装在其他任何地方。 但。 第一:我在 dmesg 中看不到通常的文本。事实上,dmesg 中什么也没有。 第二件事(它本身就说明出了问题):/dev/dm-2



umount /the/mount/point
mount

EXT4-fs: unmounting filesystem

root# cat /proc/meminfo | grep dirty
Dirty:           9457728 kB
root# time sync

real    0m0.012s                                                                                
user    0m0.000s                                                                                
sys     0m0.002s
root# cat /proc/meminfo | grep dirty
Dirty:           9453632 kB

第三件事:调试目录/sys/fs/ext4/dm-2仍然存在。尝试写入“1”,希望/sys/fs/ext4/dm-2/simulate_fail它能关闭文件系统。但它什么也没做,在 dmesg 中什么也不显示。
最后,第四件事导致设备无法使用:

root# e2fsck -fy /dev/dm-2
e2fsck 1.46.5 (30-Dec-2021)
/dev/dm-2 is in use.
e2fsck: Cannot continue, aborting.

我知道可以重新启动等。这个问题不是为了解决一些简单的新手问题。我希望有 ext4 文件系统经验的人帮助我了解导致此行为的原因。
dm-2设备没有安装在其他任何地方,没有绑定安装,也没有被其他任何东西使用。
在用 进行测量时,没有其他任何东西使用脏缓存cat /proc/meminfo | grep dirty
成功的卸载调用不是MNT_DETACH(未-l使用标志)。尽管如此,它几乎立即成功了(这很奇怪)。挂载点不再挂载:但正如我上面所描述的,可以很容易地看出文件系统没有卸载。

更新:正如 AB 指出的,我尝试检查文件系统是否仍然安装在不同的命名空间中。我没有将它安装在不同的命名空间中,所以我没想到会看到任何东西。但是,令人惊讶的是,它被安装在不同的命名空间中,令人惊讶的是(用户名已更改):

4026533177 mnt       1 3411291 an-unrelated-nonroot-user       xdg-dbus-proxy --args=43

我尝试进入该命名空间并使用它卸载它,nsenter -t 3411291 -m -- umount /the/mount/point
这导致了分段错误(核心转储),这在 dmesg 中

[970130.866738] Buffer I/O error on dev dm-2, logical block 0, lost sync page write
[970130.867925] EXT4-fs error (device dm-2): ext4_mb_release_inode_pa:4846: group 9239, free 2048, pa_free 4
[970130.870291] Buffer I/O error on dev dm-2, logical block 0, lost sync page write
[970130.949466] divide error: 0000 [#1] PREEMPT SMP PTI
[970130.950677] CPU: 49 PID: 4118804 Comm: umount Tainted: P        W  OE      6.1.68-missmika #1
[970130.953056] Hardware name: OEM X79G/X79G, BIOS 4.6.5 08/02/2022
[970130.953121] RIP: 0010:mb_update_avg_fragment_size+0x35/0x120
[970130.953121] Code: 41 54 53 4c 8b a7 98 03 00 00 41 f6 44 24 7c 80 0f 84 9a 00 00 00 8b 46 14 48 89 f3 85 c0 0f 84 8c 00 00 00 99 b9 ff ff ff ff <f7> 7e 18 0f bd c8 41 89 cd 41 83 ed 01 0f 88 ce 00 00 00 0f b6 47
[970130.957139] RSP: 0018:ffffb909e3123a28 EFLAGS: 00010202
[970130.957139] RAX: 000000000000082a RBX: ffff91140ac554d8 RCX: 00000000ffffffff
[970130.957139] RDX: 0000000000000000 RSI: ffff91140ac554d8 RDI: ffff910ead74f800
[970130.957139] RBP: ffffb909e3123a40 R08: 0000000000000000 R09: 0000000000004800
[970130.957139] R10: ffff910ead74f800 R11: ffff9114b7126000 R12: ffff910eb31d2000
[970130.957139] R13: 0000000000000007 R14: ffffb909e3123b80 R15: ffff911d732beffc
[970130.957139] FS:  00007f6d94ab4800(0000) GS:ffff911d7fcc0000(0000) knlGS:0000000000000000
[970130.957139] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[970130.957139] CR2: 00003d140602f000 CR3: 0000000365690002 CR4: 00000000001706e0
[970130.957139] Call Trace:
[970130.957139]  <TASK>
[970130.957139]  ? show_regs.cold+0x1a/0x1f
[970130.957139]  ? __die_body+0x24/0x70
[970130.957139]  ? __die+0x2f/0x3b
[970130.957139]  ? die+0x34/0x60
[970130.957139]  ? do_trap+0xdf/0x100
[970130.957139]  ? do_error_trap+0x73/0xa0
[970130.957139]  ? mb_update_avg_fragment_size+0x35/0x120
[970130.957139]  ? exc_divide_error+0x3f/0x60
[970130.957139]  ? mb_update_avg_fragment_size+0x35/0x120
[970130.957139]  ? asm_exc_divide_error+0x1f/0x30
[970130.957139]  ? mb_update_avg_fragment_size+0x35/0x120
[970130.957139]  ? mb_set_largest_free_order+0x11c/0x130
[970130.957139]  mb_free_blocks+0x24d/0x5e0
[970130.957139]  ? ext4_validate_block_bitmap.part.0+0x29/0x3e0
[970130.957139]  ? __getblk_gfp+0x33/0x3b0
[970130.957139]  ext4_mb_release_inode_pa.isra.0+0x12e/0x350
[970130.957139]  ext4_discard_preallocations+0x22e/0x490
[970130.957139]  ext4_clear_inode+0x31/0xb0
[970130.957139]  ext4_evict_inode+0xba/0x750
[970130.989137]  evict+0xd0/0x180
[970130.989137]  dispose_list+0x39/0x60
[970130.989137]  evict_inodes+0x18e/0x1a0
[970130.989137]  generic_shutdown_super+0x46/0x1b0
[970130.989137]  kill_block_super+0x2b/0x60
[970130.989137]  deactivate_locked_super+0x39/0x80
[970130.989137]  deactivate_super+0x46/0x50
[970130.989137]  cleanup_mnt+0x109/0x170
[970130.989137]  __cleanup_mnt+0x16/0x20
[970130.989137]  task_work_run+0x65/0xa0
[970130.989137]  exit_to_user_mode_prepare+0x152/0x170
[970130.989137]  syscall_exit_to_user_mode+0x2a/0x50
[970130.989137]  ? __x64_sys_umount+0x1a/0x30
[970130.989137]  do_syscall_64+0x6d/0x90
[970130.989137]  ? syscall_exit_to_user_mode+0x38/0x50
[970130.989137]  ? __x64_sys_newfstatat+0x22/0x30
[970130.989137]  ? do_syscall_64+0x6d/0x90
[970130.989137]  ? exit_to_user_mode_prepare+0x3d/0x170
[970130.989137]  ? syscall_exit_to_user_mode+0x38/0x50
[970130.989137]  ? __x64_sys_close+0x16/0x50
[970130.989137]  ? do_syscall_64+0x6d/0x90
[970130.989137]  ? exc_page_fault+0x8b/0x180
[970130.989137]  entry_SYSCALL_64_after_hwframe+0x64/0xce
[970130.989137] RIP: 0033:0x7f6d94925a3b
[970130.989137] Code: fb 43 0f 00 f7 d8 64 89 01 48 83 c8 ff c3 90 f3 0f 1e fa 31 f6 e9 05 00 00 00 0f 1f 44 00 00 f3 0f 1e fa b8 a6 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 05 c3 0f 1f 40 00 48 8b 15 c1 43 0f 00 f7 d8
[970130.989137] RSP: 002b:00007ffdd60f7d08 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
[970130.989137] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00007f6d94925a3b
[970130.989137] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 000055ca1c6f7d60
[970130.989137] RBP: 000055ca1c6f7b30 R08: 0000000000000000 R09: 00007ffdd60f6a90
[970130.989137] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
[970130.989137] R13: 000055ca1c6f7d60 R14: 000055ca1c6f7c40 R15: 000055ca1c6f7b30
[970130.989137]  </TASK>
[970130.989137] Modules linked in: 88x2bu(OE) erofs dm_zero zram ext2 hfs hfsplus xfs kvdo(OE) dm_bufio mikasecfs(OE) simplefsplus(OE) melon(OE) mikatest(OE) iloveaki(OE) tls vboxnetadp(OE) vboxnetflt(OE) vboxdrv(OE) ip6t_REJECT nf_reject_ipv6 ip6t_rt ipt_REJECT nf_reject_ipv4 xt_recent xt_tcpudp nft_limit xt_limit xt_addrtype xt_pkttype nft_chain_nat xt_MASQUERADE xt_nat nf_nat xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nft_compat nf_tables binfmt_misc nfnetlink nvidia_uvm(POE) nvidia_drm(POE) intel_rapl_msr intel_rapl_common nvidia_modeset(POE) sb_edac nls_iso8859_1 x86_pkg_temp_thermal intel_powerclamp coretemp nvidia(POE) snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio snd_hda_codec_hdmi cfg80211 joydev snd_hda_intel input_leds snd_intel_dspcfg snd_intel_sdw_acpi snd_hda_codec kvm_intel snd_hda_core snd_hwdep kvm snd_pcm snd_seq_midi rapl snd_seq_midi_event snd_rawmidi intel_cstate serio_raw pcspkr snd_seq video wmi snd_seq_device snd_timer drm_kms_helper fb_sys_fops snd syscopyarea sysfillrect sysimgblt soundcore
[970130.989137]  ioatdma dca mac_hid sch_fq_codel dm_multipath scsi_dh_rdac scsi_dh_emc scsi_dh_alua msr parport_pc ppdev lp parport drm efi_pstore ip_tables x_tables autofs4 raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear crct10dif_pclmul hid_generic crc32_pclmul ghash_clmulni_intel sha512_ssse3 sha256_ssse3 sha1_ssse3 usbhid cdc_ether aesni_intel usbnet uas hid crypto_simd r8152 cryptd usb_storage mii psmouse ahci i2c_i801 r8169 lpc_ich libahci i2c_smbus realtek [last unloaded: 88x2bu(OE)]
[970131.024615] ---[ end trace 0000000000000000 ]---
[970131.203209] RIP: 0010:mb_update_avg_fragment_size+0x35/0x120
[970131.204344] Code: 41 54 53 4c 8b a7 98 03 00 00 41 f6 44 24 7c 80 0f 84 9a 00 00 00 8b 46 14 48 89 f3 85 c0 0f 84 8c 00 00 00 99 b9 ff ff ff ff <f7> 7e 18 0f bd c8 41 89 cd 41 83 ed 01 0f 88 ce 00 00 00 0f b6 47
[970131.207841] RSP: 0018:ffffb909e3123a28 EFLAGS: 00010202
[970131.209048] RAX: 000000000000082a RBX: ffff91140ac554d8 RCX: 00000000ffffffff
[970131.210284] RDX: 0000000000000000 RSI: ffff91140ac554d8 RDI: ffff910ead74f800
[970131.211512] RBP: ffffb909e3123a40 R08: 0000000000000000 R09: 0000000000004800
[970131.212749] R10: ffff910ead74f800 R11: ffff9114b7126000 R12: ffff910eb31d2000
[970131.213977] R13: 0000000000000007 R14: ffffb909e3123b80 R15: ffff911d732beffc
[970131.215181] FS:  00007f6d94ab4800(0000) GS:ffff911d7fcc0000(0000) knlGS:0000000000000000
[970131.216370] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[970131.217553] CR2: 00003d140602f000 CR3: 0000000365690002 CR4: 00000000001706e0
[970131.218740] note: umount[4118804] exited with preempt_count 1

机器仍然可以工作,可以同步其他文件系统:

root# sync -f /
root#

但不是全局同步:

root# sync
(goes D state forever)

与该 Ghost 文件系统相关的脏缓存没有消失,文件系统仍然“挂载”
这些问题的原因是什么?

答案1

免责声明:我不能也不会在这个答案中解释为什么会触发内核部分故障。这看起来像是一个内核错误,可能是由 I/O 错误条件触发的。

长话短说

当新的挂载命名空间从原始挂载命名空间继承挂载的文件系统时,可能会出现文件系统仍在使用中的情况,但两者之间的传播设置并未使原始命名空间中的卸载将其传播到新命名空间中。该命令findmnt -A -o +PROPAGATION还在其输出中显示每个可见安装点的传播状态。

通常这不应该发生在系统环境,因为系统很早就进行/共享挂载(而不是内核默认的private),从而允许卸载在其共享组内传播。因此,我希望这种情况在非 systemd 环境中更容易发生,或者无论如何,如果工具--make-private在某些安装中明确使用的话。--make-private仍然有其用途,特别是对于虚拟伪文件系统。

防止这种情况发生的一种方法可能是,在创建新的挂载命名空间之前更改与 共享的挂载点 mount --make-shared ...

我做了一个实验来说明共享挂载与非共享挂载会发生什么情况。我试图确保实验在 systemd 或非 systemd 环境中都能同样工作。

实验

这可以像下面一样复制(某些值必须/dev/loop0进行调整):

# truncate -s $((2**20)) /tmp/test.raw
# mkfs.ext4 -Elazy_itable_init=0,lazy_journal_init=0 -L test /tmp/test.raw
mke2fs 1.47.0 (5-Feb-2023)

Filesystem too small for a journal
Discarding device blocks: done                            
Creating filesystem with 1024 1k blocks and 128 inodes

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

# losetup -f --show /tmp/test.raw 
/dev/loop0
# mkdir -p /mnt/propagation/test

这将允许稍后更改实验的传播,而无需通过将目录转变为挂载点来更改整个系统:

# mount --bind /mnt/propagation /mnt/propagation

现在,不同的实验可能会产生不同的结果。

unshare(1)告诉:

unshare因为 util-linux 版本 2.27 会自动将传播设置到private新的挂载命名空间中,以确保新的命名空间确实是非共享的。可以使用选项禁用此功能--propagation unchanged。请注意,这private是内核默认值。

其他工具可能会这样做。在这里,我们将更改底层/mnt/propagation安装点并始终使用--propagation unchanged.这可以避免在非 systemd(内核默认值:/是私有的)和 systemd(systemd 默认值:/是共享的)系统上获得不同的实验结果。

  1. shared

    # mount --make-shared /mnt/propagation
    # mount /dev/loop0 /mnt/propagation/test
    # ls /mnt/propagation/test
    lost+found
    # cat /proc/self/mountinfo | grep /mnt/propagation/test
    862 854 7:0 / /mnt/propagation/test rw,relatime shared:500 - ext4 /dev/loop0 rw
    

    有第二个(根)shell 并取消共享到新的安装命名空间(我将提示符更改为 NMNS# 以区分它):

    # unshare -m --propagation unchanged --
    NMNS# cat /proc/self/mountinfo | grep /mnt/propagation/test
    1454 1453 7:0 / /mnt/propagation/test rw,relatime shared:500 - ext4 /dev/loop0 rw
    NMNS# cd /mnt/propagation/test
    

    同样shared:500链接两个命名空间中的挂载:从一个命名空间卸载将从另一个命名空间卸载它。

    在原始 shell 中(在原始挂载命名空间中)卸载它:

    # umount /mnt/propagation/test
    umount: /mnt/propagation/test: target is busy.
    

    释放资源使用:

    NMNS# cd /
    
    # umount /mnt/propagation/test
    # 
    

    这次成功了。

    观察它也消失在新的挂载命名空间中。

    NMNS# cat /proc/self/mountinfo | grep /mnt/propagation/test
    NMNS# 
    

    内核dmesg将记录文件系统已卸载(到处),例如:

    EXT4-fs (loop0): unmounting filesystem e74e0353-ace0-4eff-86ae-30e288db853e.
    

    退出新安装命名空间中的 shell 进行清理。

  2. private

    # mount --make-private /mnt/propagation
    # mount /dev/loop0 /mnt/propagation/test
    # cat /proc/self/mountinfo | grep /mnt/propagation/test
    857 854 7:0 / /mnt/propagation/test rw,relatime - ext4 /dev/loop0 rw
    

    不再分享了。

    别处:

    # unshare -m --propagation unchanged --
    NMNS# cat /proc/self/mountinfo | grep /mnt/propagation/test
    1454 1453 7:0 / /mnt/propagation/test rw,relatime - ext4 /dev/loop0 rw
    NMNS# echo $$
    232529
    
    # umount /mnt/propagation/test
    # e2fsck /dev/loop0
    e2fsck 1.47.0 (5-Feb-2023)
    /dev/loop0 is in use.
    e2fsck: Cannot continue, aborting.
    
    
    
    # 
    

    文件系统保持安装在新的安装命名空间中。

    要从原始名称空间中找到这个恶意名称空间,可以运行如下命令:

    # for pid in $(lsns --noheadings -t mnt -o PID); do nsenter -t "$pid" -m -- findmnt /mnt/propagation/test && echo $pid; done
    nsenter: failed to execute findmnt: No such file or directory
    TARGET                SOURCE     FSTYPE OPTIONS
    /mnt/propagation/test /dev/loop0 ext4   rw,relatime
    232529
    # 
    

    注意:nsenter: failed to execute findmnt: No such file or directory发生的情况是正在运行的 LXC 容器的挂载命名空间findmnt不可用。循环确实在具有挂载点的新命名空间中找到了进程的 PID(注意:在实际情况下,这可能是同一挂载命名空间中的其他 PID,这并不重要。)。在极端情况下,需要一个能够更改挂载命名空间、检查挂载和执行 (u)挂载一体的专用命令。

    可以通过删除剩余的持有资源(PID 232529)来删除此安装,如果进程主动使用已安装的文件系统(防止umount成功),则可能需要该资源,或者在此命名空间中卸载它:

    # nsenter -t 232529 -m -- umount /mnt/propagation/test
    # e2fsck /dev/loop0
    e2fsck 1.47.0 (5-Feb-2023)
    test: clean, 11/128 files, 58/1024 blocks
    

有用的参考:

相关内容