¿Cómo saber si un archivo está mapeado en memoria?

8

Estoy confundido acerca de los archivos mapeados en memoria, así que tengo un par de preguntas que me alegraría mucho si me pudieran ayudar.

  1. Digamos que busco un directorio en mi sistema de archivos y hay un archivo en este directorio. ¿Es posible que este archivo apunte a una región en la memoria principal, en lugar de apuntar a una región en el disco?
  2. Si esto es posible, ¿es esto lo que llamamos 'archivo mapeado en memoria'?
  3. ¿Cuál sería el significado de mover dicho archivo alrededor del sistema de archivos (es decir, mvllevar dicho archivo de un directorio a otro)? Lo que entiendo es que, dado que el archivo está mapeado en memoria, los procesos que interactúan con el archivo siempre escriben en una región predefinida de la memoria principal, y cuando abrimos ese archivo (por ejemplo, usando vim), leemos esa región de main memoria (por lo tanto, no hay disco involucrado). Por lo tanto, no importa dónde muevamos el archivo, siempre funcionará correctamente, ¿verdad? En caso afirmativo, ¿tiene algún sentido mover el archivo por el sistema de archivos?
  4. ¿Hay un comando que diga si un archivo está mapeado en memoria?
  5. Finalmente, si abro un archivo mapeado con memoria vim, hago algunos cambios y lo guardo y cierro vim, ¿qué sucederá? ¿Mis cambios simplemente se escribirán en la memoria principal? Si ese es el caso, ¿otros procesos que usan este archivo verán los cambios que acabo de hacer? En mi experiencia, los otros procesos no vieron los cambios que hice al archivo cuando hice algunos cambios en el archivo vim. ¿Cuál es la razón para esto?
Utku
fuente
12
Esto me recuerda a alguien preguntando cómo saber si un archivo era un enlace duro.
Dmitry Grigoryev
3
@DmitryGrigoryev Eso es bastante divertido, de hecho, pero todos aprenden :)
gato

Respuestas:

24

Los archivos mapeados en memoria funcionan al revés. La asignación de memoria no es una propiedad del archivo, sino una forma de acceder al archivo: un proceso puede asignar el contenido de un archivo (o un subconjunto del mismo) a su espacio de direcciones. Esto hace que sea más fácil leer y escribir en el archivo; hacerlo simplemente implica leer y escribir en la memoria. El archivo en sí, en el disco, es igual que cualquier otro archivo.

Para configurar esto, los procesos usan la mmapfunción. Esto también se puede utilizar para otros fines, como compartir memoria entre procesos.

Stephen Kitt
fuente
14
@Utku Esto no tiene nada que ver con archivos mapeados en memoria.
Satō Katsura
12
Si no cerró el servidor MySQL, ese es el comportamiento normal: el servidor tiene un descriptor de archivo abierto en el archivo, y eso sigue siendo válido incluso con mv.
Stephen Kitt
11
El descriptor de archivo apunta (eventualmente) a inodos en el sistema de archivos; ahí es donde realmente vive el archivo. Las entradas de directorio también apuntan a estos inodos, y mvsimplemente cambian las entradas de directorio, no los inodos (cuando está moviendo archivos en el mismo sistema de archivos).
Stephen Kitt
1
Su descripción es una simplificación útil, pero solo para la precisión: las asignaciones de memoria técnicamente no son lo mismo que los descriptores de archivos, pero funcionan de la misma manera (por referencia al inodo, no al nombre del archivo). open (), mmap (), close () no deja FD, solo un mapeo, que aparecerá con lsof. No desaparece hasta que el proceso llama a munmap (), o sale (o reemplaza el mapeo por uno diferente usando mmap (MAP_FIXED) ...)
Peter Cordes
3
@Utku En realidad no moviste el archivo. Acaba de crear una nueva entrada de directorio que hace referencia al mismo archivo y luego eliminó la anterior. El cambio en la denominación no tiene efecto en un proceso que ya tiene el archivo abierto.
David Schwartz
11

Un archivo mapeado en memoria no está (necesariamente) respaldado por la memoria. Puede vivir perfectamente en un disco. En realidad, el lugar donde vive un archivo no es una propiedad del archivo en sí, sino del sistema de archivos en el que reside.

La asignación de un archivo en la memoria es una operación que un proceso puede hacer para cargar una parte del archivo en la memoria. El resultado parece una región regular de memoria, excepto que cuando el proceso lee o escribe en esta región, en realidad lee y escribe en el archivo. Si abre un archivo, lo asigna a la memoria, lo escribe y lo guarda, la modificación se realizará en el archivo, en el disco (si vive en un disco, por supuesto).

Esto se puede utilizar, por ejemplo, cuando se sabe que tiene una gran cantidad de accesos a hacer en un archivo, que no van a ser secuencial, sea la causa puede ser más fácil y más eficiente de hacer las lecturas y escrituras en la memoria que al tema read, write, y llseekllamadas al sistema. El único problema con este método es que realmente no puede usarlo si varios procesos deben leer o escribir en el archivo simultáneamente. Los resultados serían impredecibles.

No conozco ningún comando que pueda decirte si un archivo está asignado actualmente. Sin embargo, puede inspeccionar las asignaciones de un proceso en /proc/<pid>/maps(si su sistema lo tiene).

Para responder a su segunda pregunta, cuando abre un archivo, incluso si lo mueve en el sistema de archivos, los procesos que lo han abierto aún pueden usarlo. Lo que sucede es que un archivo no depende de sus entradas en los sistemas de archivos. Mientras tenga un archivo abierto, tiene un "identificador", un descriptor de archivo, que le permite leer y escribir en él, incluso si cambia su ruta en el sistema de archivos. Un archivo desaparece solo cuando no tiene entrada en el sistema de archivos y ningún proceso contiene un descriptor de archivo.

lgeorget
fuente
Entonces, cuando movemos un archivo, el valor del descriptor de archivo no cambia. Existe una asignación de descriptor de ruta a archivo y solo cambia la parte de ruta de esa asignación. ¿Es esto correcto?
Utku
1
En cierto sentido sí, pero no estoy seguro de entenderte, así que déjame reformularlo. Básicamente, "un archivo" es tres cosas. Una entrada de directorio es una ruta en el sistema de archivos. Un inodo es el contenido de un archivo. Y un descriptor de archivo representa un archivo abierto. Tanto las entradas de directorio como los descriptores de archivo contienen un puntero a su inodo de respaldo. Cuando abre un archivo, pasa la entrada del directorio y el núcleo le devuelve un descriptor de archivo. Por lo tanto, incluso si la entrada del directorio original cambia, el descriptor de archivo todavía apunta al mismo inodo y puede acceder al archivo.
lgeorget
1
Sin embargo, puede inspeccionar las asignaciones de un proceso en /proc/<pid>/maps. - Siempre que dicho proceso se desarrolle en un sistema que tiene /procque comenzar. OpenBSD no lo hace, y FreeBSD lo está eliminando gradualmente. Además, FreeBSD tiene en /proc/<pid>/maplugar de /proc/<pid>/maps.
Satō Katsura el
@SatoKatsura Gracias por la precisión. Solo tengo una máquina Linux a mano, así que pensé en contar mi caso y dejar que la gente hablara del suyo ... Siéntase libre de editar la respuesta si tiene algo que corregir / agregar aquí.
lgeorget
Como preguntas: asumiste que el OP realmente entiende lo que está preguntando y explicaste en detalle qué son los archivos mapeados en memoria. No creo que le hayas hecho un servicio. OMI su primer comentario anterior era mucho más relevante para lo que el PO fue en realidad pidiendo entonces su respuesta. FWIW
Satō Katsura
9

P4: ¿Hay algún comando que indique si un archivo está mapeado en memoria?

El lsofcomando le mostrará todos los archivos actualmente en uso por el sistema. La columna "FD" contendrá "mem" si el archivo está mapeado en memoria. Por lo tanto, puede seleccionar la salida de este comando para el nombre de archivo que le interesa.

Wossname
fuente
3
O uselsof -ad mem /path/to/file
Stéphane Chazelas
55
O más bien, lsof -ad mem,txt /path/to/filecomo los archivos que se están ejecutando también tienen partes de ellos mapeadas en el espacio de direcciones del proceso pero aparecen como txten la lsofsalida.
Stéphane Chazelas
7

Parece confundir la asignación de memoria con archivos en sistemas de archivos que residen en memoria, junto con otros conceptos como cómo los procesos mantienen el acceso a los archivos incluso cuando se mueven.

Iré pregunta por pregunta para ver si puedo aclarar las cosas.

  1. Digamos que busco un directorio en mi sistema de archivos y hay un archivo en este directorio. ¿Es posible que este archivo apunte a una región en la memoria principal, en lugar de apuntar a una región en el disco?

Apunta a la memoria principal si está en un sistema de archivos que reside en la memoria, como procfs que normalmente está montado en / proc, o sysfs que está en / sys, o tmpfs que a veces está en / tmp.

  1. Si esto es posible, ¿es esto lo que llamamos 'archivo mapeado en memoria'?

No. Como dijo stephen-kitt, "mapeo de memoria" se refiere a una forma de acceder a un archivo "mapeándolo" en la memoria principal y trabajando con él allí en lugar de leer y escribir fragmentos a la vez a través de funciones como read () y escribir().

  1. ¿Cuál sería el significado de mover dicho archivo alrededor del sistema de archivos (es decir, mover dicho archivo de un directorio a otro)? Lo que entiendo es que, dado que el archivo está mapeado en memoria, los procesos que interactúan con el archivo siempre escriben en una región predefinida de la memoria principal, y cuando abrimos ese archivo (por ejemplo, usando vim), leemos esa región de memoria principal (por lo tanto, no hay disco involucrado). Por lo tanto, no importa dónde muevamos el archivo, siempre funcionará correctamente, ¿verdad? En caso afirmativo, ¿tiene algún sentido mover el archivo por el sistema de archivos?

Si lo mueve dentro del mismo sistema de archivos, realmente solo se está moviendo alrededor de una referencia, un inodo de un directorio a otro. Si hay programas que ya tenían este archivo abierto, seguirán accediendo al mismo archivo porque ya tienen el inodo a la mano a través de un descriptor de archivo. Esto es lo que sucedió con el archivo table_name.idb que mencionaste en un comentario.

  1. ¿Hay un comando que diga si un archivo está mapeado en memoria?

Wossname ya respondió esto para los archivos mapeados en memoria. lsofle dirá qué procesos tienen el archivo mapeado en memoria.

Para saber si un archivo está en un sistema de archivos que reside en la memoria, puede usar dfo mountpara enumerar los sistemas de archivos y sus puntos de montaje. Solo necesita saber qué tipos de sistemas de archivos residen en la memoria buscándolos (por ejemplo, en wikipedia).

  1. Finalmente, si abro un archivo mapeado en memoria con vim, hago algunos cambios y guardo y cierro vim, ¿qué sucederá? ¿Mis cambios simplemente se escribirán en la memoria principal? Si ese es el caso, ¿otros procesos que usan este archivo verán los cambios que acabo de hacer? En mi experiencia, los otros procesos no vieron los cambios que hice en el archivo cuando hice algunos cambios en el archivo con vim. ¿Cuál es la razón para esto?

Personalmente, no he usado la mmapfunción en un programa en C, pero como la entiendo por descremado man mmapy info mmap, no hay magia involucrada en mantener la representación en memoria sincronizada. En su forma básica, llamar a mmap copia el contenido del archivo a la memoria y msyncse utiliza para volver a escribirlo desde la memoria al disco. Si el archivo en el disco cambia, no hay nada en el lugar para detectarlo y modificar automáticamente la representación en memoria en todos los procesos que lo mapearon.

EDITAR: Resulta que mmap () en realidad intenta mantener sincronizada la representación en memoria en algunas condiciones. Si el mapa solo se lee, se mantendrá sincronizado incluso cuando otros procesos escriban en el archivo. Si se escribe en (asignando a la región de memoria), lo que sucede depende de cuál de los indicadores MAP_SHARED o MAP_PRIVATE aparentemente obligatorios se proporciona a mmap (). Si se proporciona MAP_PRIVATE, el mapa se bifurca desde la representación en disco y deja de estar sincronizado hasta que use msync (). Si se proporciona MAP_SHARED, las actualizaciones se hacen visibles para otros procesos que tienen el archivo asignado, así como (aunque esto no es necesariamente inmediato) la representación en el disco.

Acabo de abrir vim en un archivo existente ey ejecuté el comando :w, mientras lo inotifywait -m .ejecutaba en otra terminal. Entre algunas partes extrañas, esta es la parte importante que obtuve inotifywait.

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

Vim crea un nuevo archivo y elimina el anterior. Por qué hace esto en lugar de modificar el archivo está más allá del alcance de esta pregunta, pero el punto es que este es un archivo nuevo y, por lo tanto, tiene un nuevo inodo.

Ahora, ¿qué quieres decir con otros procesos que usan este archivo? Si te refieres a procesos que tenían el archivo abierto mientras estabas haciendo esto, no, no verán los cambios. Esto se debe a que, aunque abrieron un archivo con la misma ruta, no son el mismo archivo. Si te refieres a procesos que pueden abrir el archivo después de hacer esto, entonces sí, verán los cambios. Abrirán el nuevo archivo que creaste.

Es importante tener en cuenta que aunque los programas pueden tener un archivo abierto en la interfaz de usuario, eso no significa necesariamente que mantengan el archivo abierto en el proceso. Vim es un ejemplo de esto, como se muestra arriba.

JoL
fuente
3
" Si el archivo en el disco cambia, no hay nada en el lugar para detectarlo y modificar automáticamente la representación en memoria en todos los procesos que lo mapearon " . ¿Qué cambiaría el sistema de archivos en el disco detrás de la asignación de página del sistema operativo? ¿sistema? ¿Se imagina algún acceso sin procesar al dispositivo de bloque o un dispositivo de bloque compartido a través de iSCSI o algo así?
David Schwartz
@ david-schwartz No. Me imagino dos procesos con un archivo abierto () 'ed. El proceso 1 usa mmap () para copiar / asignar el contenido del archivo a la memoria. Luego, el proceso 2 usa write () (y posiblemente fsync ()) para cambiar el contenido del disco. En este momento, el contenido del archivo que el proceso 1 tiene en la memoria no refleja los cambios que el proceso 2 hizo, ¿verdad?
JoL
No claro que no. El propósito de la writefunción es cambiar los datos del archivo. Eso puede o no significar cambiar el contenido del disco, pero sea lo que sea lo que implique, es responsabilidad del sistema de archivos hacerlo bien. En este caso, implicaría modificar la página de memoria asignada y marcarla como sucia.
David Schwartz
@ david-schwartz Experimenté con mmap (), y tienes razón. En el escenario que expuse en mi comentario anterior, el contenido del proceso 1 que tenía en la memoria (en el mapa) en realidad reflejaba los cambios a menos que el proceso 1 hubiera escrito en la memoria de antemano. Esto fue cierto incluso cuando el proceso de cambio 1 lo hizo en una ubicación diferente del cambio realizado por el proceso 2. Actualicé la respuesta tachando lo que es incorrecto y agregando lo que encontré.
JoL
1
@ david-schwartz Lo siento, no quise decir que mmap se comportó de manera diferente a lo que especificaba la documentación, pero sí, creo que he hecho la respuesta demasiado confusa. Creo que todavía está dentro del alcance, pero la pregunta, "¿otros procesos que usan este archivo verán los cambios que acabo de hacer?", Parece ser demasiado amplia. Hay demasiados "depende". Debido a que la necesidad del OP parece ser puramente autodidacta, traté de dar una respuesta precisa y cubrir todo el terreno que pude, pero podría haberlo exagerado. Sin embargo, todavía me alegro de haberlo hecho, ya que también aprendí un poco.
JoL