La versión continua luego reemplaza /apps/EXE con un ejecutable completamente nuevo.
Esta es la parte importante.
La forma en que se publica un nuevo archivo es mediante la creación de un nuevo archivo (por ejemplo, /apps/EXE.tmp.20190907080000
), escribir los contenidos, establecer permisos y propiedad y finalmente cambiarle el nombre (2) al 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 que, en efecto, es un archivo diferente).
Y el archivo anterior tenía su propio número de inodo, que en realidad todavía existe aunque el nombre del archivo ya no apunte a él (o ya no haya nombres de archivo que apunten a ese inodo).
Entonces, la clave aquí es que cuando hablamos de "archivos" en Linux, a menudo nos referimos a "inodos", ya que una vez que se ha abierto un archivo, el inodo es la referencia que mantenemos para el archivo.
Suposición 1 :Asumo que el proceso P (y cualquier otra persona con un descriptor de archivo que haga referencia al ejecutable anterior) continuará usando el antiguo, en la memoria/aplicaciones/EXE sin problemas, y cualquier proceso nuevo que intente ejecutar esa ruta obtendrá el nuevo ejecutable.
Correcto.
Suposición 2 :Supongo que si no todas las páginas del archivo están asignadas a la memoria, las cosas estarán bien hasta que haya una falla de página que requiera páginas del archivo que han sido reemplazadas, y probablemente ocurrirá una falla de segmento.
Incorrecto. El inodo antiguo aún existe, por lo que las fallas de página del proceso que usa el binario antiguo aún podrán encontrar esas páginas en el disco.
Puedes ver algunos efectos de esto mirando el /proc/${pid}/exe
enlace simbólico (o, equivalentemente, lsof
salida) para el proceso que ejecuta el antiguo binario, que mostrará /app/EXE (deleted)
para indicar que el nombre ya no está pero el inodo todavía existe.
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 eliminar el proceso, verá que se reduce al tamaño de ese viejo binario que pensó 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 a 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.
Pregunta 1 :si bloquea todas las páginas del archivo con algo como vmtouch, eso cambia el escenario
Esta pregunta se basa en la suposición incorrecta 2 de que no bloquear las páginas provocará fallas de segmento. No lo hará.
Pregunta 2 :Si /apps/EXE está en un NFS remoto, ¿habría alguna diferencia? (Supongo que no)
Es significado funcione de la misma manera y la mayoría de las veces lo hace, pero hay algunos "errores" 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 las exportaciones NFS, para asegurarse de que no se "reorganizarán" cuando se reinicie el servidor NFS.
Pero la idea principal es la misma. El controlador del cliente NFS aún usa inodos e intentará mantener los archivos (en el servidor) mientras aún se hace referencia al inodo.
Suposición 2:Supongo que si no todas las páginas del archivo están asignadas a la memoria, todo estará bien hasta que haya una falla de página que requiera páginas del archivo que se han reemplazado, y probablemente ocurra una falla de segmento.
No, eso no sucederá, porque el kernel no le permitirá abrir para escribir o reemplazar nada dentro de un archivo que se está ejecutando actualmente. Tal acción fallará con ETXTBSY
[1] :
cp /bin/sleep sleep; ./sleep 3600 & echo none > ./sleep
[9] 5332
bash: ./sleep: Text file busy
Cuando dpkg, etc. actualiza un binario, no lo sobrescribe, pero usa rename(2)
que simplemente apunta la entrada del directorio a un archivo completamente diferente, y cualquier proceso que aún tenga asignaciones o identificadores abiertos en el archivo antiguo continuará usándolo sin problemas.
ETXBUSY
la 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 lo hará hacer que el proceso se bloquee. En Linux, el enlazador dinámico pasa obedientemente el MAP_DENYWRITE
marca a mmap(2)
, pero no se equivoquen, no tiene ningún efecto. Ejemplo:
$ cc -xc - <<<'void lib(){}' -shared -o lib.so
$ cc -Wl,-rpath=. lib.so -include unistd.h -xc - <<<'
extern void lib();
int main(){ truncate("lib.so", 0); lib(); }
'
./a.out
Bus error
La respuesta de filbranden es correcta, suponiendo que el proceso de publicación continua realice 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, tu 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 el que está modificado. 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é, seguida de la modificación como si ya estuviera en caché. Las escrituras que abarcan una página completa o más pueden (y casi seguramente lo hacen) optimizar el paso de lectura al paginarlas. En cualquier caso, solo existe una versión canónica modificable de un archivo (*), la que está en el caché de la página. .
(*) Mentí un poco. Para NFS y otros sistemas de archivos remotos, puede haber más de uno, y por lo general (según cuál y qué opciones de montaje y del lado del servidor se usen) no implementan correctamente la atomicidad y la semántica de orden para las escrituras. Es por eso que muchos de nosotros los consideramos fundamentalmente rotos y nos negamos a usarlos para situaciones en las que habrá escrituras simultáneas con el uso.