Я знаю, что при изменении страницы кэша страниц она помечается как грязная и требует обратной записи, но что происходит, когда:
Сценарий: файл / apps / EXE, который является исполняемым файлом, полностью помещается в кеш страниц (все его страницы находятся в кеше / памяти) и выполняется процессом P
Непрерывный выпуск заменяет / apps / EXE новым исполняемым файлом.
Предположение 1: Я предполагаю, что процесс P (и любой другой пользователь с файловым дескриптором, ссылающимся на старый исполняемый файл) продолжит использовать старый, в памяти / apps / EXE без проблем, и любой новый процесс, который попытается выполнить этот путь, получит новый исполняемый файл.
Предположение 2: Я предполагаю, что если не все страницы файла будут отображены в памяти, все будет хорошо, пока не произойдет сбой страницы, требующий страниц из файла, который был заменен, и, возможно, произойдет сегфоут?
Вопрос 1: Если вы скомбинируете все страницы файла с чем-то вроде vmtouch, это вообще изменит сценарий?
Вопрос 2: Если / apps / EXE находится на удаленной NFS, будет ли это иметь какое-то значение? (Я предполагаю, что нет)
Пожалуйста, исправьте или подтвердите мои 2 предположения и ответьте на мои 2 вопроса.
Давайте предположим, что это коробка CentOS 7.6 с ядром 3.10.0-957.el7
Обновление: Думая об этом дальше, мне интересно, если этот сценарий ничем не отличается от любого другого сценария грязной страницы ..
Я полагаю, что процесс, который записывает новый двоичный файл, выполнит чтение и получит все страницы кэша, так как он весь разбит на страницы, и тогда все эти страницы будут помечены как грязные. Если они заблокированы, они будут просто бесполезными страницами, занимающими основную память после того, как число ссылок станет равным нулю.
Я подозреваю, что когда текущие программы заканчиваются, все остальное будет использовать новый двоичный файл. Предполагая, что это все правильно, я думаю, что это интересно только тогда, когда в файл вставлена только часть файла.
источник
Ответы:
Это важная часть.
Способ выпуска нового файла - это создание нового файла (например
/apps/EXE.tmp.20190907080000
), запись содержимого, установка разрешений и владельца и, наконец, переименование (2) его окончательного имени/apps/EXE
, замена старого файла.В результате у нового файла новый номер инода (это означает, что это другой файл).
И у старого файла был свой собственный номер инода, который на самом деле все еще существует, хотя имя файла больше не указывает на него (или нет имен файлов, указывающих на этот инод больше).
Итак, ключевой момент в том, что когда мы говорим о «файлах» в Linux, мы чаще всего действительно говорим о «инодах», так как после открытия файла инод является ссылкой, которую мы храним на файл.
Верный.
Неправильно. Старый инод все еще существует, поэтому сбои страниц в процессе, использующем старый двоичный файл, все равно смогут найти эти страницы на диске.
Вы можете увидеть некоторые эффекты этого, посмотрев
/proc/${pid}/exe
символическую ссылку (или, что эквивалентно,lsof
выходные данные) для процесса, выполняющего старый двоичный файл, который покажет,/app/EXE (deleted)
что имя больше не существует, но индекс все еще существует.Вы также можете видеть, что дисковое пространство, используемое двоичным файлом, будет освобождено только после того, как процесс завершится (при условии, что это единственный процесс с открытым индексом). Проверьте выходные данные
df
до и после завершения процесса, вы увидите, что он уменьшается на размер о том старом бинарнике, который, как ты думал, больше не былКстати, это касается не только двоичных файлов, но и любых открытых файлов. Если вы откроете файл в процессе и удалите его, файл будет храниться на диске до тех пор, пока этот процесс не закроет файл (или не прекратит работу). Аналогично тому, как жесткие ссылки хранят счетчик количества имен, указывающих на индекс на диске, Драйвер файловой системы (в ядре Linux) хранит счетчик количества ссылок на этот индекс в памяти и освобождает индекс от диска только после того, как все ссылки из работающей системы также будут освобождены.
Этот вопрос основан на неверном предположении 2, что отсутствие блокировки страниц приведет к ошибкам в работе сегмента. Не будет
Он должен работать так же и большую часть времени, но с NFS есть некоторые "ошибки".
Иногда вы можете увидеть артефакты удаления файла, который все еще открыт в NFS (отображается как скрытый файл в этом каталоге).
У вас также есть способ назначить номера устройств для экспорта NFS, чтобы они не переставлялись при перезагрузке сервера NFS.
Но основная идея та же. Драйвер клиента NFS по-прежнему использует inode и будет пытаться хранить файлы (на сервере), пока на inode все еще есть ссылки.
источник
rename
это в значительной степени единственная операция с файлом и файловой системой, которая гарантированно является атомарной (при условии, что мы не пересекаем границы файловой системы или устройства), поэтому «создайте временный файл и затемrename
» - это стандартный шаблон для обновления файлов. Это также то, что каждый текстовый редактор в Unix использует, например.rename
является частью POSIX. Конечно, он включен в качестве ссылки на ISO C (раздел 7.21.4.2 в текущем проекте), но он там.Нет, этого не произойдет, потому что ядро не позволит вам открыть для замены что-либо внутри файла, который в данный момент выполняется. Такое действие потерпит неудачу с
ETXTBSY
[1]:Когда dpkg и т. Д. Обновляет двоичный файл, он не перезаписывает его, а использует,
rename(2)
который просто указывает запись в каталоге на совершенно другой файл, и любые процессы, у которых все еще есть сопоставления или открытые дескрипторы для старого файла, продолжат использовать его без проблем. ,[1] такая защита не распространяется на другие файлы, которые также можно считать «текстовыми» (живой код / исполняемый файл): общие библиотеки, классы Java и т. Д .; изменение такого файла во время отображения другим процессом приведет к его аварийному завершению. В Linux динамический компоновщик покорно передает
MAP_DENYWRITE
флагmmap(2)
, но не ошибается - он никак не влияет.источник
rename(2)
является атомным; как только он завершится, запись dir ссылается на новый файл. Процессы, которые все еще использовали старый файл в этой точке, могли бы получить к нему доступ только через существующие сопоставления или через открытые дескрипторы к нему (которые могут ссылаться на потерянный зубной протез, более недоступный, кроме как через/proc/PID/fd
).Ответ filbranden верен, если предположить, что процесс непрерывного выпуска правильно заменяет файлы с помощью
rename
. Если это не так, но изменяет файл на месте, все иначе. Однако ваша ментальная модель все еще ошибается.Невозможно что-либо изменить на диске и не совместить с кешем страниц, потому что кеш страниц является канонической версией и той, которая изменена. Любая запись в файл происходит через кеш страницы. Если он уже присутствует, существующие страницы будут изменены. Если это еще не сделано, попытки изменить частичную страницу приведут к кешированию всей страницы с последующей модификацией, как если бы она уже была кеширована. Записи, занимающие целую страницу или более, могут (и почти наверняка) оптимизируют шаг чтения, разбивая их на страницы. В любом случае, существует только одна каноническая модифицируемая версия файла, когда-либо существовавшая (*), та, которая находится в кеше страницы. ,
(*) Я слегка соврал. Для NFS и других удаленных файловых систем их может быть больше одной, и они обычно (в зависимости от того, какая из них и какие параметры монтирования и на стороне сервера) не правильно реализуют атомарность и упорядочение семантики для записей. Вот почему многие из нас считают их в корне сломанными и отказываются использовать их в ситуациях, когда записи будут выполняться одновременно с использованием.
источник