Como saber se um arquivo está mapeado na memória?

8

Estou confuso com os arquivos mapeados na memória, então tenho algumas perguntas que ficaria muito feliz se você pudesse me ajudar.

  1. Digamos que eu procure um diretório no meu sistema de arquivos e haja um arquivo nesse diretório. É possível que esse arquivo aponte para uma região na memória principal, em vez de apontar para uma região no disco?
  2. Se isso for possível, é isso que chamamos de 'arquivo mapeado na memória'?
  3. Qual seria o significado de mover esse arquivo pelo sistema de arquivos (ou seja, mvinserir esse arquivo de um diretório para outro)? O que eu entendo é que, como o arquivo é mapeado na memória, o (s) processo (s) interagindo com o arquivo sempre grava em uma região predefinida da memória principal e, quando abrimos esse arquivo (por exemplo, usando vim), lemos a região principal memória (portanto, nenhum disco está envolvido). Portanto, não importa para onde movemos o arquivo, ele sempre funcionará corretamente, certo? Se sim, mover o arquivo pelo sistema de arquivos tem algum significado?
  4. Existe um comando que informa se um arquivo está mapeado na memória?
  5. Por fim, se eu abrir um arquivo mapeado na memória vim, faça algumas alterações e salve e feche vim, o que acontecerá? Minhas alterações serão gravadas na memória principal? Se for esse o caso, outros processos que usam esse arquivo verão as alterações que acabei de fazer? Na minha experiência, os outros processos não viram as alterações que fiz no arquivo quando fiz algumas alterações no arquivo vim. Qual é a razão para isto?
Utku
fonte
12
Isso me lembra alguém perguntando como saber se um arquivo era um link físico.
Dmitry Grigoryev
3
@DmitryGrigoryev Isso é muito engraçado, na verdade, mas aprende todos :)
gato

Respostas:

24

Os arquivos mapeados na memória funcionam ao contrário. O mapeamento de memória não é uma propriedade do arquivo, mas uma maneira de acessá-lo: um processo pode mapear o conteúdo de um arquivo (ou um subconjunto dele) em seu espaço de endereço. Isso facilita a leitura e a gravação no arquivo; fazer isso envolve simplesmente ler e escrever na memória. O arquivo em si, no disco, é igual a qualquer outro arquivo.

Para configurar isso, os processos usam a mmapfunção Isso também pode ser usado para outros fins, como compartilhar memória entre processos.

Stephen Kitt
fonte
14
@Utku Isso não tem nada a ver com arquivos mapeados na memória.
Satō Katsura
12
Se você não desligou o servidor MySQL, esse é um comportamento normal: o servidor possui um descritor de arquivo aberto no arquivo e isso permanece válido mesmo mv.
Stephen Kitt
11
O descritor de arquivo aponta (eventualmente) para inodes no sistema de arquivos; é onde o arquivo realmente mora. As entradas de diretório também apontam para esses inodes e mvsimplesmente alteram as entradas de diretório, não os inodes (quando estão movendo arquivos no mesmo sistema de arquivos).
Stephen Kitt
1
Sua descrição é uma simplificação útil, mas apenas para precisão: os mapeamentos de memória tecnicamente não são a mesma coisa que os descritores de arquivos, mas funcionam da mesma maneira (por referência ao inode, não ao nome do arquivo). open (), mmap (), close () não deixa FD, apenas um mapeamento, que será exibido lsof. Ele não vai embora até que o processo chama munmap () ou saídas (ou substitui o mapeamento com um diferente usando mmap (MAP_FIXED) ...)
Peter Cordes
3
@Utku Na verdade, você não moveu o arquivo. Você acabou de criar uma nova entrada de diretório que se refere ao mesmo arquivo e depois removeu o antigo. A alteração na nomeação não tem efeito em um processo que já tenha o arquivo aberto.
David Schwartz
11

Um arquivo mapeado na memória não é (necessariamente) suportado pela memória. Pode perfeitamente viver em um disco. Na verdade, o local onde um arquivo está não é uma propriedade do arquivo, mas do sistema de arquivos em que ele reside.

Mapear um arquivo na memória é uma operação que um processo pode fazer para ter uma parte do arquivo carregada na memória. O resultado parece uma região regular da memória, exceto que, quando o processo lê ou grava nessa região, ele realmente lê e grava no arquivo. Se você abrir um arquivo, mapeá-lo para a memória, gravá-lo e salvá-lo, a modificação será feita no arquivo, no disco (se estiver em um disco, é claro).

Isto pode ser usado por exemplo, quando você sabe que tem um monte de acessos para fazer em um arquivo, que não vão ser sequenciais, ser motivo pode ser mais fácil e mais eficiente para fazer leituras e gravações na memória do que a questão read, write, e llseekchamadas do sistema. O único problema com esse método é que você realmente não pode usá-lo se o arquivo precisar ser lido ou gravado por vários processos simultaneamente. Os resultados seriam imprevisíveis.

Não conheço nenhum comando que possa dizer se um arquivo está mapeado no momento. Você pode inspecionar os mapeamentos de um processo em /proc/<pid>/maps(se o seu sistema o possuir).

Para responder à sua segunda pergunta, quando você abre um arquivo, mesmo que você o mova no sistema de arquivos, os processos que o abriram ainda podem usá-lo. O que acontece é que um arquivo não depende de suas entradas nos sistemas de arquivos. Desde que você tenha um arquivo aberto, você tem um "identificador", um descritor de arquivo, que permite ler e gravar nele, mesmo que o caminho no sistema de arquivos seja alterado. Um arquivo desaparece apenas quando não tem entrada no sistema de arquivos e nenhum processo contém um descritor de arquivo.

lgeorget
fonte
Portanto, quando movemos um arquivo, o valor do descritor de arquivo não muda. Há um mapeamento de descritor de caminho para arquivo e apenas a parte do caminho desse mapeamento é alterada. Isso está correto?
Utku
1
De certa forma, sim, mas não tenho certeza de entendê-lo, então deixe-me reformulá-lo. Basicamente, "um arquivo" é três coisas. Uma entrada de diretório é um caminho no sistema de arquivos. Um inode é o conteúdo de um arquivo. E um descritor de arquivo representa um arquivo aberto. As entradas do diretório e os descritores de arquivo contêm um ponteiro para seu inode de backup. Quando você abre um arquivo, você passa a entrada do diretório e o kernel retorna um descritor de arquivo. Portanto, mesmo que a entrada do diretório original seja alterada, o descritor de arquivo ainda aponta para o mesmo inode e você pode acessar o arquivo.
Lgdk #
1
Você pode inspecionar os mapeamentos de um processo, no entanto /proc/<pid>/maps. - Desde que o referido processo viva em um sistema que tenha um /proccomeço. O OpenBSD não, e o FreeBSD está eliminando gradualmente. Além disso, o FreeBSD possui em /proc/<pid>/mapvez de /proc/<pid>/maps.
Satō Katsura
@SatoKatsura Obrigado pela precisão. Eu só tenho uma máquina Linux em mãos, então pensei em contar sobre o meu caso e deixar as pessoas falarem sobre o deles ... Sinta-se livre para editar a resposta se você tiver algumas coisas para corrigir / adicionar aqui.
lgeorget 13/09/16
Desde que você pergunta: você assumiu que o OP realmente entende o que ele está perguntando e explicou em detalhes o que são arquivos mapeados na memória. Eu não acho que você fez um serviço para ele. OMI, seu primeiro comentário acima foi muito mais relevante para o que o OP estava realmente pedindo, em seguida, sua resposta. FWIW.
Satō Katsura
9

Q4: existe um comando que informa se um arquivo está mapeado na memória?

O lsofcomando mostrará todos os arquivos atualmente em uso pelo sistema. A coluna "FD" conterá "mem" se o arquivo estiver mapeado na memória. Portanto, você pode receber a saída desse comando pelo nome do arquivo em que está interessado.

Wossname
fonte
3
Ou uselsof -ad mem /path/to/file
Stéphane Chazelas
5
Ou melhor, lsof -ad mem,txt /path/to/filecomo os arquivos que estão sendo executados também têm partes deles mapeadas no espaço de endereço do processo, mas aparecem como txtna lsofsaída.
Stéphane Chazelas
7

Você parece estar confundindo mapeamento de memória com arquivos em sistemas de arquivos que residem na memória, além de outros conceitos como como os processos mantêm o acesso aos arquivos, mesmo quando eles são movidos.

Vou perguntar pergunta por pergunta para ver se consigo esclarecer as coisas.

  1. Digamos que eu procure um diretório no meu sistema de arquivos e haja um arquivo nesse diretório. É possível que esse arquivo aponte para uma região na memória principal, em vez de apontar para uma região no disco?

Ele aponta para a memória principal se estiver em um sistema de arquivos que resida na memória, como procfs que normalmente é montado em / proc, ou sysfs que está em / sys ou tmpfs que às vezes está em / tmp.

  1. Se isso for possível, é isso que chamamos de 'arquivo mapeado na memória'?

Não. Como stephen-kitt disse, "mapeamento de memória" refere-se a uma maneira de acessar um arquivo "mapeando" na memória principal e trabalhando com ele lá, em vez de ler e escrever pedaços de cada vez por meio de funções como read () e Escreva().

  1. Qual seria o significado de mover esse arquivo pelo sistema de arquivos (ou seja, mover esse arquivo de um diretório para outro)? O que eu entendo é que, como o arquivo é mapeado na memória, o (s) processo (s) interagindo com o arquivo sempre grava em uma região predefinida da memória principal e, quando abrimos esse arquivo (por exemplo, usando o vim), lemos essa região de memória principal (portanto, nenhum disco está envolvido). Portanto, não importa para onde movemos o arquivo, ele sempre funcionará corretamente, certo? Se sim, mover o arquivo pelo sistema de arquivos tem algum significado?

Se você movê-lo dentro do mesmo sistema de arquivos, você está apenas movendo uma referência, um inode de um diretório para outro. Se houver programas que já tiveram esse arquivo aberto, eles ainda estarão acessando o mesmo arquivo porque já têm o inode em mãos por meio de um descritor de arquivo. Foi o que aconteceu com o arquivo table_name.idb que você mencionou em um comentário.

  1. Existe um comando que informa se um arquivo está mapeado na memória?

O Wossname já respondeu isso para arquivos mapeados na memória. lsofinformará quais processos têm o arquivo mapeado na memória.

Para saber se um arquivo está em um sistema de arquivos que reside na memória, você pode usar dfou mountpara listar os sistemas de arquivos e seus pontos de montagem. Você só precisa saber quais tipos de sistemas de arquivos residem na memória pesquisando-os (por exemplo, na wikipedia).

  1. Finalmente, se eu abrir um arquivo mapeado na memória com o vim, faça algumas alterações e salve e feche o vim, o que acontecerá? Minhas alterações serão gravadas na memória principal? Se for esse o caso, outros processos que usam esse arquivo verão as alterações que acabei de fazer? Na minha experiência, os outros processos não viram as alterações que fiz no arquivo quando fiz algumas alterações no arquivo com o vim. Qual é a razão para isto?

Pessoalmente, eu não usei a mmapfunção em um programa em C, mas como eu a entendo por skimming man mmapeinfo mmap , não há mágica envolvida em manter a representação na memória em sincronia. Em sua forma básica, chamar mmap copia o conteúdo do arquivo para a memória e msyncé usado para gravá-lo da memória para o disco. Se o arquivo em disco for alterado, não há nada para detectá-lo e modificar automaticamente a representação na memória em todos os processos que o mapearam.

EDIT: Acontece que mmap () realmente tenta manter a representação na memória sincronizada sob algumas condições. Se o mapa for apenas lido, ele será mantido sincronizado, mesmo quando outros processos forem gravados no arquivo. Se for gravado (atribuindo à região da memória), o que acontecerá depende de qual sinalizador MAP_SHARED ou MAP_PRIVATE aparentemente obrigatório é fornecido ao mmap (). Se MAP_PRIVATE for fornecido, o mapa bifurca-se da representação em disco e deixa de estar sincronizado até você usar msync (). Se MAP_SHARED for fornecido, as atualizações serão visíveis para outros processos que têm o arquivo mapeado, bem como (embora isso não seja necessariamente imediato) a representação em disco.

Acabei de abrir o vim em um arquivo existente ee executei o comando :wenquanto inotifywait -m .rodava em outro terminal. Entre alguns trechos estranhos, essa é a parte importante de que recebi inotifywait.

./ MOVED_FROM e
./ MOVED_TO e~
./ CREATE e
./ OPEN e
./ MODIFY e
./ CLOSE_WRITE,CLOSE e
./ ATTRIB e
./ ATTRIB e
./ DELETE e~

O Vim cria um novo arquivo e remove o antigo. Por que isso ocorre em vez de modificar o arquivo está além do escopo desta pergunta, mas o ponto é que este é um novo arquivo e, portanto, possui um novo inode.

Agora, o que você quer dizer com outros processos usando esse arquivo? Se você quer dizer processos que tiveram o arquivo aberto enquanto você fazia isso, eles não verão as alterações. Isso ocorre porque, embora eles tenham aberto um arquivo com o mesmo caminho, eles não são o mesmo arquivo. Se você quer dizer processos que podem abrir o arquivo depois de fazer isso, sim, eles verão as alterações. Eles abrirão o novo arquivo que você criou.

É importante observar que, embora os programas pareçam ter um arquivo aberto na interface do usuário, isso não significa necessariamente que eles mantêm o arquivo aberto no processo. O Vim é um exemplo disso, como mostrado acima.

JoL
fonte
3
" Se o arquivo em disco for alterado, não há nada para detectá-lo e modificar automaticamente a representação na memória em todos os processos que o mapearam. " O que alteraria o sistema de arquivos em disco atrás da parte de trás do mapeamento de página do sistema operacional sistema? Você está imaginando algum acesso bruto ao dispositivo de bloco ou a um dispositivo de bloco compartilhado pelo iSCSI ou algo assim?
David Schwartz
@ david-schwartz Não. Estou imaginando dois processos com um arquivo aberto () 'ed. O processo 1 usa mmap () para copiar o conteúdo do arquivo / mapeado para a memória. Em seguida, o processo 2 usa write () (e possivelmente fsync ()) para alterar o conteúdo do disco. No momento, o processo 1 do conteúdo do arquivo na memória não reflete as alterações efetuadas pelo processo 2, certo?
Jol
Não, claro que não. O objetivo da writefunção é alterar os dados do arquivo. Isso pode ou não significar a alteração do conteúdo do disco, mas seja o que for que envolva, é de responsabilidade do sistema de arquivos fazer o correto. Nesse caso, isso envolveria a modificação da página de memória mapeada e a marcação de suja.
David Schwartz
@ david-schwartz Eu experimentei o mmap () e você está certo. No cenário apresentado em meu comentário anterior, o processo de conteúdo que 1 tinha na memória (no mapa) realmente refletia as alterações, a menos que o processo 1 tivesse gravado na memória no mapeamento anteriormente. Isso era verdade mesmo quando o processo de mudança que fiz foi em um local diferente da mudança feita pelo processo 2. Atualizei a resposta riscando o que estava incorreto e adicionando o que encontrei.
JOL
1
@ david-schwartz Desculpe, não tive a intenção de sugerir que o mmap se comportasse de maneira diferente da especificada na documentação, mas sim, acho que tornei a resposta muito confusa. Acho que ainda está no escopo, mas a pergunta "outros processos que usam esse arquivo verão as alterações que acabei de fazer?", Parece ser muito ampla. Existem muitos "depende". Como a necessidade do OP parece ser puramente autodidática, tentei dar uma resposta precisa e cobrir o máximo de terreno possível, mas posso ter exagerado. No entanto, ainda estou feliz por ter aprendido um pouco, também.
Jol