por que as montagens de ligação do Linux desaparecem se o inode do ponto de montagem for alterado?

4

Em resumo: se você vincular a montar um arquivo /tmp/a na parte superior de /tmp/b em um novo namespace de montagem, mas o inode de /tmp/b mudar no namespace pai, a montagem da ligação desaparecerá no namespace filho. Estou tentando entender o porquê.

mount (8) não expõe a capacidade de ligar arquivos individuais (apenas diretórios), portanto, a reprodução requer um executável adicional que possa emitir o syscall mount (2) necessário. Aqui está um exemplo simples (referido como bmount abaixo):

#include <sys/mount.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("requires exactly 2 args\n");
        return 1;
    }

    int err = mount(argv[1], argv[2], "none", MS_BIND, NULL);
    if (err == 0) {
        return 0;
    } else {
        printf("mount error (%d): %s\n", errno, strerror(errno));
        return 1;
    }
}

Configure o caso de teste:

# echo a > /tmp/a; echo b > /tmp/b; echo c > /tmp/c;
# ls -ldi /tmp/a /tmp/b /tmp/c
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a                                                               
11403422 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/c

Agora, em um shell separado:

# unshare -m /bin/bash
# bmount /tmp/a /tmp/b
# ls -ldi /tmp/a /tmp/b /tmp/c
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/c
# cat /tmp/b
a
# grep "\/tmp\/" /proc/self/mounts
[redacted] /tmp/b ext4 rw,relatime,errors=remount-ro,data=ordered 0 0

No shell original:

# mv /tmp/c /tmp/b
# ls -ldi /tmp/a /tmp/b /tmp/c
ls: cannot access '/tmp/c': No such file or directory                                                               
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a                                                               
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b

No unshare shell:

# ls -ldi /tmp/a /tmp/b /tmp/c
ls: cannot access '/tmp/c': No such file or directory
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
# cat /tmp/b
c
# grep "\/tmp\/" /proc/self/mounts
#

A montagem da ligação desapareceu silenciosamente, e o arquivo /tmp/b do sistema de arquivos subjacente agora está visível dentro do namespace.

Eu encontrei um artigo do lwn.net que descreve uma mudança na semântica aqui: antes de 2013,%% do comando mv rename(2) no ponto de montagem falharia com EBUSY , mas o comportamento foi alterado para que fosse bem-sucedido e, em seguida, a montagem seria removida. O commit do kernel relevante parece ser 8ed936b5671 .

As perguntas que tenho são:

  1. Por que a montagem é removida em qualquer mudança de inode? É apenas um detalhe de implementação do sistema de montagem, em que o ponto de montagem é identificado por um dentário em vez de um caminho simples?
  2. Existe uma maneira de fazer montagens de bind que sejam menos "frágeis" no sentido de que elas não podem ser substituídas ou removidas por operações do sistema de arquivos fora de seu namespace?

Um caso em que isso é relevante na prática é ip-netns (8) ; ip netns exec funciona pela montagem de ligação /etc/netns/${NAMESPACE}/resolv.conf na parte superior de /etc/resolv.conf . Se o inode de /etc/resolv.conf for alterado por resolvconf (8) ou systemd-resolved, o /etc/resolv.conf atualizado será visível para o processo em execução dentro do namespace.

    
por Shivaram Lingamneni 19.01.2018 / 20:02

1 resposta

4

Isso é propagação de montagem. O Linux não o habilita por padrão, mas o systemd faz isso. Se você não quiser que as montagens e desmontagens se propaguem para o novo namespace, você pode, por exemplo, execute mount --make-rprivate / dentro dele. . Narrador: isso não é propagação de montagem.

Why is the mount removed on any inode change? Is it just an implementation detail of the mount system, where the mount point is identified by a dentry rather than a simple path?

Eu diria que a única diferença que você pode esperar entre rm b; mv c b e mv c b é que não é possível observar b como inexistente a qualquer momento. Eu descreveria isso como um recurso que foi deliberadamente projetado ou mantido ... Não tenho certeza até que ponto isso é verdade para o sistema multiusuário histórico do Unix, mas certamente dependeu de, por exemplo, para suportar atualizações de software em um sistema em execução.

Eu ... posso pensar em exatamente um outro recurso específico que foi implementado para o que você chama de "mudança de inode" - isso foi feito a contragosto e é específico do sistema de arquivos.

    
por 19.01.2018 / 20:20