Por que a montagem acontece em um diretório existente?

52

Um diretório existente é necessário como um ponto de montagem .

$ ls
$ sudo mount /dev/sdb2 ./datadisk
mount: mount point ./datadisk does not exist
$ mkdir datadisk
$ sudo mount /dev/sdb2 ./datadisk
$

Acho confuso, pois sobrepõe o conteúdo existente do diretório. Existem dois conteúdos possíveis do diretório do ponto de montagem que podem ser alternados inesperadamente (para um usuário que não está executando a montagem).

Por que não mountacontece em um diretório recém-criado? É assim que os sistemas operacionais gráficos exibem mídia removível. Ficaria claro se o diretório está montado (existe) ou não está montado (não existe). Tenho certeza de que existe um bom motivo, mas ainda não o descobri.

Melebius
fonte
11
Se você deseja esse comportamento, use udisksctl. Por que usar mount?
Muru
11
Porque é o caminho do Unix. Como é mais flexível, você pode montá-lo em qualquer lugar. Como montá-los em qualquer lugar, você pode estender seus servidores conforme necessário, por exemplo, obtendo um novo disco para a partição de banco de dados, movendo os dados na partição de banco de dados para o novo disco e montando-os no lugar certo para permitir que os dados do banco de dados crescer mais.
Rui F Ribeiro
8
Como uma nota histórica, antes que o Windows e o LInux basicamente esmagassem todos os outros sistemas operacionais, havia uma empresa chamada Apollo. Eles escreveram um sistema operacional unix-like (melhor design que o Unix!). Ele criou os diretórios nos quais as exportações do NFS foram montadas automaticamente. Na verdade, você não pode montar em um diretório pré-existente. A HP comprou a Apollo, jogou fora o sistema operacional e usou a CPU de 64 bits da Apollo como HP-PA. O sistema de chamadas de procedimento remoto da Apollo se tornou o DCE da OSF, que aparentemente vive dentro do Windows. O saber é metade da batalha!
precisa
de alguma forma, isso acontece no meu sistema ubuntu 14.04,3. Ainda não investiguei. Quando meu cartão SD é montado, ele termina em um caminho que não tem nada por baixo. se eu desmontá-lo e tentar montá-lo manualmente de volta, o erro que recebo é que não há diretório no ponto de montagem.
Skaperen
2
@BruceEdiger better design than Unix![citação necessário]
Ruslan

Respostas:

51

Este é um caso de um detalhe de implementação que vazou.

Em um sistema UNIX, todo diretório consiste em uma lista de nomes mapeados para números de inode . Um inode contém metadados que informam ao sistema se é um arquivo, diretório, dispositivo especial, pipe nomeado etc. Se for um arquivo ou diretório, também informa ao sistema onde encontrar o conteúdo do arquivo ou diretório no disco. A maioria dos inodes são arquivos ou diretórios. A -iopção para lslistar os números dos inodes.

A montagem de um sistema de arquivos pega um inode de diretório e define um sinalizador na cópia em memória do kernel para dizer "na verdade, ao procurar o conteúdo desse diretório, observe esse outro sistema de arquivos" (consulte o slide 10 desta apresentação ). Isso é relativamente fácil, pois altera um único item de dados.

Por que ele não cria uma entrada de diretório para você apontar para o novo inode? Há duas maneiras de implementar isso, ambas com desvantagens. Uma é escrever fisicamente um novo diretório no sistema de arquivos - mas isso falhará se o sistema de arquivos for somente leitura! A outra é adicionar a cada processo de listagem de diretórios uma lista de coisas "extras" que realmente não existem. Isso é complicado e potencialmente gera um pequeno impacto no desempenho em todas as operações de arquivo.

Se você deseja pontos de montagem criados dinamicamente, o automountsistema pode fazer isso. Sistemas de arquivos não-disco especiais também podem criar diretórios à vontade, por exemplo proc, sys, devfse assim por diante.

Editar: veja também a resposta para O que acontece quando você 'monta' uma pasta existente com conteúdo?

pjc50
fonte
Exceto que ele não define um sinalizador no inode. sudo mount --bind / /mnt ; ls /mnt/proc-> vazio. Eu me pergunto como isso funciona.
sourcejedi
A operação exata está fs/namespace.c, eu acho; Não estou familiarizado com a fonte e não queria gastar muito tempo detalhando os detalhes. A "bandeira no inode" recebi da apresentação vinculada.
Pjc50
2
@sourcejedi: montagens de ligação vinculam apenas o sistema de arquivos a que você realmente se refere. Eles não ligam recursivamente outros sistemas de arquivos montados sob ele. Esta é uma maneira útil de encontrar lixo oculto por montagens. (por exemplo, se algumas coisas acabarem no FS raiz em /var/cachealgum momento quando /varnão for possível montar.) Veja também path_resolution(7). (As linux-manpages antigas tinham essa página de manual na seção 2, como die.net) IDK como o Linux realmente funciona internamente, para otimizar a verificação de cada componente do diretório como uma possível montagem. Talvez fixar essa entrada VFS no cache?
Peter Cordes
2
Certo, esse é o meu ponto ... Então fs/namei.c(caminho -> pesquisa de inode) chama o namespace.c lookup_mnt(). Há um sinalizador no dentry (entrada no cache do diretório). Mas isso é apenas uma otimização, também conhecida como detalhe da implementação. Ele não informa qual sistema de arquivos está montado lá; você tem que olhar na mesa de montagem. (Veja m_hash (), para obter mais detalhes da implementação. O Linux, pelo menos, evita comparações adicionais de cadeias de caracteres, e o AFAICS ao mesmo tempo consegue reutilizar os dentrys em, por exemplo, montagens de bind, porque é escrito por assistentes).
sourcejedi
11
@PeterCordes man 8 mount:: mount --bind foo foo. A mountchamada de ligação anexa apenas (parte de) um único sistema de arquivos, não é possível enviar submontagens. Toda a hierarquia de arquivos, incluindo submontagens, é anexada em um segundo lugar usando :mount --rbind olddir newdir
mikeserv
19

Se mount(2) necessário, a criação de um novo diretório para ser o ponto de montagem, você não poderá montar nada em um sistema de arquivos somente leitura. Isso seria idiota, para que possamos descartar isso.

Se mount opcionalmente criou um novo diretório para ser o ponto de montagem, isso seria estranho. Não é como montar / desmontar acontecer o tempo todo, portanto, colocar lógica extra no kernel para executar essas duas etapas com uma única chamada do sistema não seria uma aceleração importante. Apenas deixe espaço para o usuário fazer uma mkdir(2)chamada do sistema, se desejar. A resposta de Dmitry aponta que mount(2)fazer as duas coisas a tornaria não atômica. E você iria querer um argumento extra para mount(2)com bandeiras do modo como open(2)toma, para O_CREAT, O_EXCL, etc. Seria apenas ser bobo em comparação a deixar o espaço do usuário fazê-lo.

Ou talvez você estivesse perguntando sobre ter mount(8)(o programa tradicional que faz mount(2)chamadas do sistema) fazer isso? Isso seria possível, mas já existe algo perfeitamente bom mkdir(1)para o trabalho, e o design do Unix é sobre boas ferramentas pequenas que podem ser combinadas. Se você deseja uma ferramenta que faça as duas coisas, é fácil escrever um script de shell para criar essa ferramenta com duas ferramentas mais simples. (Ou, como muru comentou, udisksctljá faz isso, para que você não precise escrevê-lo.) Além disso, o normal do Linux a mount(8)partir do util-linux suporta o mount -o x-mount.mkdir[=mode]uso de sua x-sintaxe para opções de espaço do usuário, em vez de opções a serem passadas para o sistema de arquivos.


Agora, a pergunta mais interessante: por que deve haver um diretório no sistema de arquivos pai?

Como a resposta de pjc50 aponta (sem relação, mesmo que ele tenha minhas iniciais!), Ter pontos de montagem exibidos nas listagens de diretório exigiria uma verificação extra em todos os itens readdir().

Ter pontos de montagem como diretórios no diretório que os contém (no FS pai) é um bom truque. readdir()não precisa perceber que é um ponto de montagem. Isso só acontece se o ponto de montagem for usado como um componente do caminho. É claro que a resolução do caminho precisa verificar a tabela de montagem para todos os componentes de diretório de um caminho.

Peter Cordes
fonte
11
If mount(2) required the creation of a new directory to be the mount point, you couldn't mount anything under a read-only filesystem. That would be dumb- Eu diria que mais inteligente: Da perspectiva do usuário, um read-only sistema de arquivos não deve mudar, mas permitindo que monta significa que ele pode
Izkata
2
@ Izkata: Criar um sistema de arquivos somente leitura não significa que toda a subárvore do VFS esteja congelada. Poderia ter links simbólicos apontando para diretórios de leitura e gravação ou já ter pontos de montagem de leitura e gravação quando o pai fs foi remontado ro. Existem muitos casos de uso para sistemas de arquivos somente leitura em que seu argumento não faz sentido.
Peter Cordes
2
man 8 mount: x-mount.mkdir[=mode] Permite criar um diretório de destino (ponto de montagem). O modo de argumento opcional especifica o modo de acesso ao sistema de arquivos usado mkdir(2)na notação octal. O modo padrão é 0755. Essa funcionalidade é suportada apenas para usuários root.
mikeserv
Não vejo nenhum caso de uso importante de sistemas de arquivos somente leitura com sistemas de arquivos de leitura e gravação montados, principalmente no início do Unix. @PeterCordes
kubanczyk
@kubanczyk: sistema de arquivos raiz somente leitura, com leitura e gravação /tmpe /home. Ou montado em NFS somente leitura /usrcom um local /usr/localmontado nele. Ou, geralmente, qualquer imagem somente leitura compartilhada com uma parte modificável montada sobre ela. (mods locais para uma imagem somente leitura também podem ser feitos por arquivo com sistemas de arquivos personalizados, como overlayfs ou outros sistemas de arquivos de união para Linux, usados ​​em imagens inicializáveis ​​do LiveCD.) Eu estava inicialmente pensando no RO raiz inicialmente montado no inicializar, mas torná-lo rw pode acontecer antes de outras montagens.
Peter Cordes
12

A montagem no diretório existente faz uma chamada para mountpraticamente atômica: ela é bem-sucedida ou falha, pelo menos da perspectiva do usuário. Se mountfosse necessário criar o ponto de montagem, ele teria dois pontos de falha, tornando impossível garantir uma reversão limpa. Imagine o seguinte cenário:

  1. mount cria com êxito o ponto de montagem
  2. mount tenta montar um novo sistema de arquivos nesse diretório, mas falha
  3. mount tenta remover o ponto de montagem, mas falha

O sistema acaba com um efeito colateral de uma falha mount.

Aqui está mais um:

  1. umount desmonta com sucesso um sistema de arquivos
  2. umount tenta remover o ponto de montagem, mas falha

Agora, deve umountretornar sucesso ou fracasso?

Dmitry Grigoryev
fonte
5
mountpossui 8 códigos de retorno diferentes para erros que também podem ser combinados. Ele poderia apenas adicionar outro quando a remoção do diretório falhar. man7.org/linux/man-pages/man8/mount.8.html#RETURN_CODES
caos
8
Eu acho que o OP está perguntando por que o ponto de montagem precisa ser um diretório existente, e não por que a mountchamada do sistema não o cria. Embora talvez fosse apenas minha interpretação / expectativa do que eu pensava que o OP queria perguntar, ou o que eu teria perguntado se estivesse perguntando.
22615 Peter Cordes
3

Outro caso que pode ocorrer:

Quando você inicializa, uma imagem básica somente leitura é carregada no diretório raiz. Então, você gostaria de substituí-lo quando quiser montar uma raiz real. Então você pode imaginar que o mount syscall apenas troque o roponto de montagem para rw.

Aqui, vamos imaginar que você tenha um problema no sistema de arquivos no ponto de montagem raiz, você gostaria de tentar consertá-lo. Com a sobreposição de montagem, é possível desmontar o sistema de arquivos e usar fscka imagem básica para resolvê-lo.

Esse recurso também pode ser útil em sistemas que precisam de segurança forte para rastrear as alterações entre uma ropartição e uma rw.

alexises
fonte
11
Não tenho certeza de como isso responde à pergunta. Você está apontando que, se mount necessário, criando um novo diretório no local do ponto de montagem, não foi possível montar nada sobre um sistema de arquivos somente leitura? O parágrafo de abertura é confuso: não é assim que o Linux initrd funciona. Ele usa a pivot_rootchamada do sistema para alterar o root fs, e não apenas montar mais coisas sobre ele. Isso tornou difícil seguir sua lógica nos próximos parágrafos, porque eu pensei que você estava falando pivot_root(2).
Peter Cordes
2
@PeterCordes - linux não usou um initrd por muitos anos : Ao ligar outro dispositivo raiz, initrd faria pivot_roote, em seguida, umounto disco RAM. Mas initramfs é rootfs: você não pode nem pivot_rootrootfs nem desmontá-lo . Tudo em vez de exclusão fora de rootfs para liberar o espaço ( find -xdev / -exec rm {} \;), rootfs Overmount com a nova raiz ( cd /newmount; mount --move . /; chroot .), anexar stdin / stdout / stderr para o novo / dev / console, e execo novoinit
mikeserv
@mikeserv: Neat! Eu não tinha percebido que o mecanismo básico para mudar raízes mudou quando começamos a usar o initramfs em vez do initrd. Do ponto de vista de administração "certifique-se de que os módulos do kernel corretos terminem", eles são idênticos>. <. Ainda acho que isso realmente não responde muito bem à pergunta . Parece assumir que a interpretação "montar sob um rofs é impossível" e fornece um caso de problema muito específico (o que parece improvável porque o initramfs não é montado somente leitura na inicialização. E mesmo se for, pode simplesmente ser remontado como leitura -WRITE sem afetar a imagem cpio.gz).
Peter Cordes
@ PeterCordes - eu realmente não entendo esta resposta. Acabei de ver seu comentário - o initramfs é um sistema de arquivos - ele não pode realmente ser somente leitura - seu cache fs encarnado.
mikeserv
2

Eu sempre me perguntei isso também.

Um invólucro simples, como:

#!/bin/sh
eval "mkdir -p \"\$$#\"" 
/bin/mount "$@"  

salvo como um script executável nomeado mountem um diretório que substitui o /binseu PATH deve cuidar disso se isso o incomodar demais

(Antes de executar o mountbinário real , ele cria um diretório nomeado após o último argumento mount, se esse diretório ainda não existir.)


Como alternativa, se você não deseja que invocações com falha do mountwrapper criem diretórios, você pode:

#!/bin/sh
set -e
eval "lastArg=\"\$$#\""
test -d "$lastArg" || { mkdir "$lastArg"; madeDir=1; }
/bin/mount "$@"  ||  {  test -z "$madeDir" || rmdir "$lastArg"; }
PSkocik
fonte
O mountcomando não deve usar o diretório assim criado?
muru 23/12/2015
11
@uru É isso que a última linha faz.
PSKocik
Ah, então você quer dizer que deve ser usado assim mount /dev/foo /some/path:? Eu supus que funcionaria como udisksctlfunciona, então você correria mount /dev/foo.
Muru
4
Você pode obter o último argumento do cmdline sem evalexpandir $#, usando "${@:-1}". Eu testei isso com o DASH, pois acho que ele não suporta nada além do que o POSIX sh é necessário para suportar. /bin/dash -c 'echo ${@:-1}' foo barimpressões bar.
Peter Cordes
11
você pode usar man -o x-mount.mkdir...
mikeserv