Sé que cuando se modifica una página de caché de página, se marca como sucia y requiere una reescritura, pero qué sucede cuando:
Escenario: el archivo / aplicaciones / EXE, que es un archivo ejecutable, se pagina en la caché de la página por completo (todas sus páginas están en la caché / memoria) y se ejecuta mediante el proceso P
La versión continua luego reemplaza / apps / EXE con un nuevo ejecutable.
Supuesto 1: supongo que el proceso P (y cualquier otra persona con un descriptor de archivo que haga referencia al ejecutable anterior) continuará utilizando el antiguo, en memoria / aplicaciones / EXE sin ningún problema, y cualquier proceso nuevo que intente ejecutar esa ruta obtendrá El nuevo ejecutable.
Supuesto 2: supongo que si no todas las páginas del archivo se asignan a la memoria, todo estará bien hasta que haya un error de página que requiera páginas del archivo que se han reemplazado, y probablemente se producirá una falla predeterminada.
Pregunta 1: Si bloquea todas las páginas del archivo con algo como vmtouch, ¿eso cambia el escenario?
Pregunta 2: Si / apps / EXE está en un NFS remoto, ¿haría alguna diferencia? (Supongo que no)
Corrija o valide mis 2 supuestos y responda mis 2 preguntas.
Supongamos que este es un cuadro CentOS 7.6 con algún tipo de kernel 3.10.0-957.el7
Actualización: Pensando más en ello, me pregunto si este escenario no es diferente a cualquier otro escenario de página sucia
Supongo que el proceso que escribe el nuevo binario hará una lectura y obtendrá todas las páginas de caché, ya que está todo paginado, y luego todas esas páginas se marcarán como sucias. Si están bloqueados, solo serán páginas inútiles que ocuparán la memoria central después de que el conteo de referencias llegue a cero.
Sospecho que cuando finalizan los programas que se están ejecutando actualmente, cualquier otra cosa usará el nuevo binario. Suponiendo que todo sea correcto, supongo que solo es interesante cuando solo se paginó parte del archivo.
fuente
Respuestas:
Esta es la parte importante.
La forma en que se publica un nuevo archivo es creando un nuevo archivo (por ejemplo
/apps/EXE.tmp.20190907080000
), escribiendo el contenido, estableciendo permisos y propiedad y finalmente renombrándolo (2) con el nombre final/apps/EXE
, reemplazando el archivo antiguo.El resultado es que el nuevo archivo tiene un nuevo número de inodo (lo que significa, en efecto, que es un archivo diferente).
Y el archivo antiguo tenía su propio número de inodo, que en realidad todavía está presente a pesar de que el nombre del archivo ya no apunta a él (o ya no hay nombres de archivo que apunten a ese inodo).
Entonces, la clave aquí es que cuando hablamos de "archivos" en Linux, a menudo hablamos realmente de "inodes" ya que una vez que se ha abierto un archivo, el inodo es la referencia que mantenemos en el archivo.
Correcto.
Incorrecto. El viejo inodo todavía está presente, por lo que las fallas de página del proceso que usa el viejo binario aún podrán encontrar esas páginas en el disco.
Puede ver algunos efectos de esto mirando el
/proc/${pid}/exe
enlace simbólico (o, de manera equivalente, lalsof
salida) para el proceso que ejecuta el binario antiguo, que se mostrará/app/EXE (deleted)
para indicar que el nombre ya no está allí, pero el inodo todavía está presente.También puede ver que el espacio en disco utilizado por el binario solo se liberará después de que el proceso muera (suponiendo que sea el único proceso con ese inodo abierto). Verifique la salida de
df
antes y después de matar el proceso, verá que cae por el tamaño de ese viejo binario que creías que ya no existía.Por cierto, esto no es solo con binarios, sino con cualquier archivo abierto. Si abre un archivo en un proceso y elimina el archivo, el archivo se mantendrá en el disco hasta que ese proceso cierre el archivo (o muera). De manera similar a cómo los enlaces duros mantienen un contador de cuántos nombres apuntan a un inodo en el disco, el El controlador del sistema de archivos (en el kernel de Linux) mantiene un contador de cuántas referencias existen para ese inodo en la memoria , y solo liberará el inodo del disco una vez que se hayan liberado también todas las referencias del sistema en ejecución.
Esta pregunta se basa en la suposición incorrecta 2 de que no bloquear las páginas provocará segfaults. No lo hará.
Está destinado a funcionar de la misma manera y la mayoría de las veces, pero hay algunas "trampas" con NFS.
A veces puede ver los artefactos de eliminar un archivo que todavía está abierto en NFS (aparece como un archivo oculto en ese directorio).
También tiene alguna forma de asignar números de dispositivo a exportaciones NFS, para asegurarse de que no se "reorganicen" cuando el servidor NFS se reinicie.
Pero la idea principal es la misma. El controlador de cliente NFS todavía usa inodes e intentará mantener los archivos (en el servidor) mientras el inode todavía está referenciado.
fuente
rename
es prácticamente la única operación de archivos y sistemas de archivos que se garantiza que es atómica (suponiendo que no crucemos los límites del sistema de archivos o del dispositivo), por lo que "crear archivo temporal y luegorename
" es el patrón estándar para actualizar archivos. También es lo que usa cada editor de texto en Unix, por ejemplo.rename
es parte de POSIX. Por supuesto, se incluye por referencia a ISO C (sección 7.21.4.2 en el borrador actual), pero está ahí.No, eso no sucederá, porque el núcleo no le permitirá abrir para escribir y reemplazar nada dentro de un archivo que se está ejecutando actualmente. Tal acción fallará con
ETXTBSY
[1]:Cuando dpkg, etc. actualiza un binario, no lo sobrescribe, sino
rename(2)
que usa el que simplemente señala la entrada del directorio a un archivo completamente diferente, y cualquier proceso que todavía tenga asignaciones o identificadores abiertos al archivo antiguo continuará usándolo sin problemas .[1] dicha protección no se extiende a otros archivos que también pueden considerarse "texto" (código en vivo / ejecutable): bibliotecas compartidas, clases de Java, etc. modificar dicho archivo mientras está mapeado por otro proceso hará que se bloquee. En linux, el enlazador dinámico pasa obedientemente la
MAP_DENYWRITE
bandera ammap(2)
, pero no se equivoque, no tiene ningún efecto.fuente
rename(2)
es atómico Tan pronto como se haya completado, la entrada dir se refiere al nuevo archivo. Los procesos que todavía usaban el archivo antiguo en ese momento solo podrían acceder a él a través de asignaciones existentes, o a través de identificadores abiertos (que pueden hacer referencia a una negación huérfana, a la que ya no se puede acceder a través de/proc/PID/fd
).La respuesta de filbranden es correcta, suponiendo que el proceso de liberación continua realiza un reemplazo atómico adecuado de los archivos a través de
rename
. Si no lo hace, pero modifica el archivo en el lugar, las cosas son diferentes. Sin embargo, su modelo mental todavía está equivocado.No hay posibilidad de que las cosas se modifiquen en el disco y sean inconsistentes con el caché de la página, porque el caché de la página es la versión canónica y la que está modificada. Cualquier escritura en un archivo se realiza a través de la memoria caché de la página. Si ya está presente allí, las páginas existentes se modifican. Si aún no está presente, los intentos de modificar una página parcial harán que toda la página se almacene en caché, seguido de la modificación como si ya estuviera almacenada en caché. Las escrituras que abarcan una página entera o más pueden (y casi seguramente lo hacen) optimizar el paso de lectura pagándolos. En cualquier caso, solo existe una versión canónica modificable de un archivo (*), la que está en la memoria caché de la página .
(*) Mentí un poco. Para NFS y otros sistemas de archivos remotos, puede haber más de uno, y generalmente (dependiendo de cuál y qué opciones de montaje y del lado del servidor se usen) no implementan correctamente la atomicidad y la semántica de pedidos para las escrituras. Es por eso que muchos de nosotros los consideramos fundamentalmente rotos y nos negamos a usarlos en situaciones donde habrá escrituras concurrentes con el uso.
fuente