GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué el enlace de montaje de un archivo después de desvincular falla con ENOENT?

El mount(2) la llamada del sistema resolverá completamente sus rutas a través de montajes y enlaces simbólicos, pero a diferencia de open(2) , no aceptará una ruta a un archivo eliminado, es decir, una ruta que se resuelva en una entrada de directorio no vinculada.

(similar al <filename> (deleted) caminos de /proc/PID/fd/FD , procfs mostrará dentries no vinculados como <filename>//deleted en /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

Todo esto solía funcionar en kernels más antiguos, pero no desde la versión 4.19, introducida por primera vez con este cambio:

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);
+

Parece que este efecto no fue intencionado por el cambio. Desde entonces, se han acumulado otros cambios no relacionados, lo que lo confunde aún más.

Una consecuencia de esto es que también evita fijar un archivo eliminado en otro lugar del espacio de nombres a través de un fd abierto:

# 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

El último comando falla debido a la misma condición que los OP.

Incluso puedes volver a crear a , apuntando al mismo inodo exacto, pero obtienes lo mismo

Es lo mismo que con /proc/PID/fd/FD "enlaces simbólicos". El kernel es lo suficientemente inteligente como para seguir un archivo a través de cambios de nombre directos, pero no a través de 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 ...

Recorriendo el código fuente, encontré exactamente un ENOENT que era relevante, es decir, para una entrada de directorio no vinculada:

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() generalmente se aplica al objetivo, no a la fuente. En esta función, se llama debido a la propagación del montaje. Es necesario hacer cumplir la regla de que no puede agregar montajes encima de un archivo eliminado, durante la propagación del montaje. Pero la aplicación está ocurriendo con entusiasmo, incluso si no ocurre una propagación de montaje que requiera esto. Creo que es bueno que la verificación sea consistente como esta, solo que está codificada un poco más oscura de lo que preferiría idealmente.

De cualquier manera que lo mire, creo que es razonable hacer cumplir esto. Siempre y cuando ayude a reducir la cantidad de casos extraños para analizar y nadie tenga un contraargumento especialmente convincente.


Linux
  1. Monte sistemas de archivos NFS con autofs

  2. ¿Por qué git falla al empujar/buscar con demasiados archivos abiertos?

  3. ¿Por qué este ciclo de retardo comienza a ejecutarse más rápido después de varias iteraciones sin dormir?

  4. Para mostrar la ruta de origen del montaje vinculante para el montaje después de v2.25.2

  5. ¿Por qué mi sistema de archivos está montado como de solo lectura?

¿Por qué la sustitución del proceso Bash no funciona con algunos comandos?

¿Por qué Rsync falla con tubería rota (32), error en el zócalo Io (código 10) en Io.c (820)?

Vincular montar un usuario SFTP después de usar chroot

Comando de montaje de Linux con ejemplos

¿Por qué `xdg-mime query filetype...` no encuentra un nuevo tipo de archivo agregado?

¿Por qué rsync no puede copiar archivos de /sys en Linux?