GNU/Linux >> Belajar Linux >  >> Linux

Mengapa mengikat pemasangan file setelah tautan gagal dengan ENOENT?

mount(2) panggilan sistem akan sepenuhnya menyelesaikan jalurnya melalui tunggangan dan symlink, tetapi tidak seperti open(2) , tidak akan menerima jalur ke file yang dihapus, yaitu jalur yang memutuskan entri direktori yang tidak tertaut.

(mirip dengan <filename> (deleted) jalur /proc/PID/fd/FD , procfs akan menampilkan gigi palsu yang tidak tertaut sebagai <filename>//deleted dalam /proc/PID/mountinfo )

# unshare -m
# echo foo > foo; touch bar baz quux
# mount -B foo bar
# mount -B bar baz
# grep foo /proc/self/mountinfo
56 38 8:7 /tmp/foo /tmp/bar ...
57 38 8:7 /tmp/foo /tmp/baz ...

# rm foo
# grep foo /proc/self/mountinfo
56 38 8:7 /tmp/foo//deleted /tmp/bar ...
57 38 8:7 /tmp/foo//deleted /tmp/baz ...
# mount -B baz quux
mount: mount(2) failed: /tmp/quux: No such file or directory

Semua ini dulu berfungsi di kernel lama, tetapi tidak sejak v4.19, pertama kali diperkenalkan oleh perubahan ini:

commit 1064f874abc0d05eeed8993815f584d847b72486
Author: Eric W. Biederman <[email protected]>
Date:   Fri Jan 20 18:28:35 2017 +1300

    mnt: Tuck mounts under others instead of creating shadow/side mounts.
...
+       /* Preallocate a mountpoint in case the new mounts need
+        * to be tucked under other mounts.
+        */
+       smp = get_mountpoint(source_mnt->mnt.mnt_root);
+       if (IS_ERR(smp))
+               return PTR_ERR(smp);
+

Tampaknya efek ini tidak disengaja oleh perubahan tersebut. Sejak saat itu, perubahan lain yang tidak terkait telah menumpuk, membuatnya semakin bingung.

Konsekuensinya adalah ia juga mencegah menyematkan file yang dihapus di tempat lain di namespace melalui fd terbuka untuknya:

# exec 7>foo; touch bar
# rm foo
# mount -B /proc/self/fd/7 bar
mount: mount(2) failed: /tmp/bar: No such file or directory

Perintah terakhir gagal karena kondisi yang sama dengan OP.

Anda bahkan dapat membuat ulang a , menunjuk ke inode yang persis sama, tetapi Anda mendapatkan hal yang sama

Ini sama dengan /proc/PID/fd/FD "symlink". Kernel cukup pintar untuk mengikuti file melalui penggantian nama langsung, tetapi tidak melalui ln + rm (link(2) + unlink(2) ):

# unshare -m
# echo foo > foo; touch bar baz
# mount -B foo bar
# mount -B bar baz
# grep foo /proc/self/mountinfo
56 38 8:7 /tmp/foo /tmp/bar ...
57 38 8:7 /tmp/foo /tmp/baz ...

# mv foo quux
# grep bar /proc/self/mountinfo
56 38 8:7 /tmp/quux /tmp/bar ...

# ln quux foo; rm quux
# grep bar /proc/self/mountinfo
56 38 8:7 /tmp/quux//deleted /tmp/bar ...

Berjalan melalui kode sumber, saya menemukan satu ENOENT itu relevan, yaitu untuk entri direktori yang tidak ditautkan:

static int attach_recursive_mnt(struct mount *source_mnt,
            struct mount *dest_mnt,
            struct mountpoint *dest_mp,
            struct path *parent_path)
{
    [...]

    /* Preallocate a mountpoint in case the new mounts need
     * to be tucked under other mounts.
     */
    smp = get_mountpoint(source_mnt->mnt.mnt_root);
static struct mountpoint *get_mountpoint(struct dentry *dentry)
{
    struct mountpoint *mp, *new = NULL;
    int ret;

    if (d_mountpoint(dentry)) {
        /* might be worth a WARN_ON() */
        if (d_unlinked(dentry))
            return ERR_PTR(-ENOENT);

https://elixir.bootlin.com/linux/v5.2/source/fs/namespace.c#L3100

get_mountpoint() umumnya diterapkan pada target, bukan sumbernya. Dalam fungsi ini, ini disebut karena mount propagation. Penting untuk menegakkan aturan bahwa Anda tidak dapat menambahkan mount di atas file yang dihapus, selama propagasi mount. Tetapi penegakan terjadi dengan penuh semangat, bahkan jika tidak ada propagasi mount terjadi yang membutuhkan ini. Menurut saya bagus bahwa pemeriksaannya konsisten seperti ini, kodenya sedikit lebih tidak jelas daripada yang saya inginkan.

Bagaimanapun saya melihatnya, saya pikir masuk akal untuk menegakkan ini. Selama itu membantu mengurangi jumlah kasus aneh untuk dianalisis, dan tidak ada yang memiliki argumen tandingan yang sangat meyakinkan.


Linux
  1. Mengapa git gagal saat Push/fetch dengan Terlalu banyak file terbuka

  2. Mengapa delay-loop ini mulai berjalan lebih cepat setelah beberapa iterasi tanpa tidur?

  3. Dua titik pemasangan berbeda dengan satu perangkat

  1. Pasang sistem file NFS dengan autofs

  2. Untuk menampilkan jalur sumber mount pengikat untuk mount setelah v2.25.2

  3. Mengapa `xdg-mime query filetype ...` gagal menemukan jenis file baru yang ditambahkan?

  1. Mengapa Substitusi Proses Bash Tidak Bekerja Dengan Beberapa Perintah?

  2. Ssh – Mengapa Upaya Penerusan X11 Gagal Dengan “connect /tmp/.x11-unix/x0:No Such File or Directory”?

  3. Mengapa Rsync Gagal Dengan Pipa Rusak (32), Kesalahan Di Soket Io (kode 10) Di Io.c (820)??