Eu sei que quando uma página de cache de página é modificada, ela é marcada como suja e requer uma write-back, mas o que acontece quando:
Cenário: O arquivo / apps / EXE, que é um arquivo executável, é paginado no cache da página completamente (todas as suas páginas estão no cache / memória) e sendo executado pelo processo P
A liberação contínua substitui / apps / EXE por um novo executável.
Suposição 1: Presumo que o processo P (e qualquer outra pessoa com um descritor de arquivo que faça referência ao antigo executável) continuará usando o antigo, na memória / apps / EXE sem problemas, e qualquer novo processo que tente executar esse caminho será iniciado. o novo executável.
Suposição 2: Presumo que, se nem todas as páginas do arquivo forem mapeadas na memória, tudo ficará bem até que haja uma falha de página exigindo páginas do arquivo que foram substituídas e provavelmente ocorrerá um segfault?
Pergunta 1: Se você bloquear todas as páginas do arquivo com algo como vmtouch, isso muda o cenário?
Pergunta 2: Se / apps / EXE estiver em um NFS remoto, isso faria alguma diferença? (Presumo que não)
Corrija ou valide minhas 2 suposições e responda minhas 2 perguntas.
Vamos assumir que esta é uma caixa do CentOS 7.6 com algum tipo de kernel 3.10.0-957.el7
Atualização: Pensando nisso mais, me pergunto se esse cenário não é diferente de qualquer outro cenário de página suja.
Suponho que o processo que escreve o novo binário faça uma leitura e obtenha todas as páginas de cache, pois todas estão paginadas e, em seguida, todas essas páginas serão marcadas como sujas. Se estiverem bloqueados, serão apenas páginas inúteis que ocupam a memória principal depois que a contagem de referências for zero.
Eu suspeito que, quando os programas em execução no momento terminarem, qualquer outra coisa usará o novo binário. Supondo que tudo esteja correto, acho que só é interessante quando apenas parte do arquivo é paginada.
fonte
Respostas:
Essa é a parte importante.
A maneira como um novo arquivo é lançado é criando um novo arquivo (por exemplo
/apps/EXE.tmp.20190907080000
), escrevendo o conteúdo, definindo permissões e propriedade e, finalmente, renomeie (2) o nome final/apps/EXE
, substituindo o arquivo antigo.O resultado é que o novo arquivo possui um novo número de inode (o que significa que, na verdade, é um arquivo diferente.)
E o arquivo antigo tinha seu próprio número de inode, que ainda está presente , embora o nome do arquivo não esteja mais apontando para ele (ou não há mais nomes de arquivos apontando para esse inode).
Portanto, a chave aqui é que, quando falamos de "arquivos" no Linux, na maioria das vezes estamos realmente falando de "inodes", pois uma vez que um arquivo foi aberto, o inode é a referência que mantemos no arquivo.
Corrigir.
Incorreta. O inode antigo ainda está disponível, portanto, as falhas de página no processo usando o binário antigo ainda poderão encontrar essas páginas no disco.
Você pode ver alguns efeitos disso observando o
/proc/${pid}/exe
link simbólico (ou, equivalente, alsof
saída) do processo que está executando o binário antigo, que mostrará/app/EXE (deleted)
para indicar que o nome não está mais lá, mas o inode ainda está por aí.Você também pode ver que o espaço em disco usado pelo binário só será liberado após a morte do processo (supondo que seja o único processo com esse inode aberto.) Verifique a saída
df
antes e depois de encerrar o processo, você verá que ela cairá pelo tamanho daquele velho binário que você pensou que não estava mais por perto.BTW, isso não é apenas com binários, mas com qualquer arquivo aberto. Se você abrir um arquivo em um processo e removê-lo, ele será mantido em disco até que o processo feche o arquivo (ou morra). De maneira semelhante à maneira como os hardlinks mantêm um contador de quantos nomes apontam para um inode no disco, o O driver do sistema de arquivos (no kernel do Linux) mantém um contador de quantas referências existem para esse inode na memória e libera o inode do disco apenas quando todas as referências do sistema em execução também forem liberadas.
Esta pergunta é baseada na suposição incorreta 2 de que não bloquear as páginas causará segfaults. Não vai.
Ele deve funcionar da mesma maneira e na maioria das vezes, mas existem algumas "dicas" com o NFS.
Às vezes, você pode ver os artefatos de excluir um arquivo que ainda está aberto no NFS (aparece como um arquivo oculto nesse diretório).
Você também tem uma maneira de atribuir números de dispositivo às exportações do NFS, para garantir que eles não sejam "reorganizados" quando o servidor NFS for reiniciado.
Mas a ideia principal é a mesma. O driver do cliente NFS ainda usa inodes e tentará manter os arquivos ao redor (no servidor) enquanto o inode ainda estiver relacionado.
fonte
rename
é praticamente a única operação de arquivo e sistema de arquivos que é garantida como atômica (supondo que não ultrapassemos os limites do sistema de arquivos ou do dispositivo), portanto, "crie arquivo temporário e depoisrename
" é o padrão padrão para atualizar arquivos. É também o que todo editor de texto no Unix usa, por exemplo.rename
faz parte do POSIX. Concedido, ele é incluído por referência à ISO C (seção 7.21.4.2 no rascunho atual), mas está lá.Não, isso não acontecerá, porque o kernel não permitirá que você abra para escrever e substituir qualquer coisa dentro de um arquivo que está sendo executado no momento. Tal ação falhará com
ETXTBSY
[1]:Quando o dpkg, etc atualiza um binário, ele não o substitui, mas usa o
rename(2)
que simplesmente aponta a entrada do diretório para um arquivo completamente diferente, e qualquer processo que ainda tenha mapeamentos ou identificadores abertos no arquivo antigo continuará a usá-lo sem problemas .[1] essa proteção não é estendida a outros arquivos que também podem ser considerados "texto" (código ativo / executável): bibliotecas compartilhadas, classes java, etc; modificar esse arquivo um tempo mapeados por outro processo vai fazer com que ele deixe de funcionar. No linux, o vinculador dinâmico passa a
MAP_DENYWRITE
bandeira obedientementemmap(2)
, mas não se engane - não tem nenhum efeito.fonte
rename(2)
é atômico; assim que for concluída, a entrada dir se refere ao novo arquivo. Os processos que ainda estavam usando o arquivo antigo naquele momento só poderiam acessá-lo por meio de mapeamentos existentes ou por identificadores abertos (que podem fazer referência a um dentry órfão, não mais acessível a não ser via/proc/PID/fd
).A resposta de filbranden está correta, assumindo que o processo de liberação contínua faça a substituição atômica adequada dos arquivos via
rename
. Se não, mas modifica o arquivo no local, as coisas são diferentes. No entanto, seu modelo mental ainda está errado.Não há possibilidade de as coisas serem modificadas no disco e serem inconsistentes com o cache da página, porque o cache da página é a versão canônica e a que foi modificada. Qualquer gravação em um arquivo ocorre através do cache da página. Se já estiver presente lá, as páginas existentes serão modificadas. Se ainda não estiver presente, as tentativas de modificar uma página parcial farão com que a página inteira seja armazenada em cache, seguida pela modificação como se já estivesse em cache. Gravações que abrangem uma página inteira ou mais podem (e quase certamente o fazem) otimizar a etapa de leitura que está sendo paginada. .
(*) Menti levemente. Para NFS e outros sistemas de arquivos remotos, pode haver mais de um, e eles normalmente (dependendo de qual e quais opções de montagem e de servidor são usadas) não implementam corretamente a atomicidade e a semântica de pedidos para gravações. É por isso que muitos de nós os consideramos fundamentalmente quebrados e nos recusamos a usá-los para situações em que haverá gravações simultâneas ao uso.
fonte