Что происходит, когда файл, который на 100% загружен в кэш страниц, изменяется другим процессом

Ошибка связана с тем, что для команды sedдобавления aтребуется обратная косая черта после фактическогоa:

С GNUsed:

$ sed "/pattern/a\\$VAR" file.in >file.out

BSD sed, насколько мне известно, может вставить в файл только одну строку с помощью команды a, если символы новой строки не экранированы должным образом.

Тесно связанный ответ о том, как решить эту проблему с помощью BSDsed:http://unix.stackexchange.com/a/60322

14
07.09.2019, 20:21
3 ответа

Continuous release then replaces /apps/EXE with a brand new executable.

Это важная часть.

Новый файл выпускается путем создания нового файла (, например. /apps/EXE.tmp.20190907080000), запись содержимого, установка разрешений и владельца и окончательное переименование (2 )в окончательное имя /apps/EXE, замена старого файла.

В результате новый файл имеет новый номер инода (, что фактически означает, что это другой файл.)

И у старого файла был свой собственный индексный дескриптор, который на самом деле по-прежнему примерно равен , даже несмотря на то, что имя файла больше не указывает на него (или больше нет имен файлов, указывающих на этот индексный дескриптор.)

Итак, ключевой момент здесь в том, что когда мы говорим о «файлах» в Linux, мы чаще всего на самом деле говорим об «инодах», поскольку после открытия файла индексный дескриптор является ссылкой, которую мы сохраняем на файл.

Assumption 1: I assume that process P (and anyone else with a file descriptor referencing the old executable) will continue to use the old, in memory /apps/EXE without an issue, and any new process which tries to exec that path will get the new executable.

Верно.

Assumption 2: I assume that if not all pages of the file are mapped into memory, that things will be fine until there is a page fault requiring pages from the file that have been replaced, and probably a segfault will occur?

Неверно. Старый индексный дескриптор все еще существует, поэтому сбои страниц из процесса, использующего старый двоичный файл, по-прежнему смогут найти эти страницы на диске.

Вы можете увидеть некоторые последствия этого, взглянув на символическую ссылку /proc/${pid}/exe(или, что то же самое, lsofвывод )для процесса, выполняющего старый двоичный файл, который будет отображать /app/EXE (deleted), чтобы указать имя больше нет, но индекс все еще существует.

Вы также можете видеть, что дисковое пространство, используемое двоичным файлом, будет освобождено только после того, как процесс умрет (, предполагая, что это единственный процесс с открытым индексным узлом. )Проверьте вывод dfдо и после уничтожения процесса, вы увидите, что он уменьшается на размер того старого двоичного файла, который, как вы думали, больше не существует.

Кстати, это касается не только бинарников, но и любых открытых файлов. Если вы открываете файл в процессе и удаляете файл, файл будет храниться на диске до тех пор, пока этот процесс не закроет файл (или не умрет. )Подобно тому, как жесткие ссылки ведут счетчик количества имен, указывающих на индексный дескриптор на диске, драйвер файловой системы (в ядре Linux )ведет счетчик количества ссылок на этот индексный дескриптор в памяти. и освободит индексный дескриптор с диска только после того, как будут освобождены все ссылки из работающей системы.

Question 1: If you mlock all of the pages of the file with something like vmtouch does that change the scenario

Этот вопрос основан на неверном предположении 2 о том, что отсутствие блокировки страниц приведет к ошибкам сегментации. Это не будет.

Question 2: If /apps/EXE is on a remote NFS, would that make any difference? (I assume not)

Это означает, что работает так же, и в большинстве случаев так оно и есть, но есть некоторые «подводные камни» с NFS.

Иногда вы можете увидеть артефакты удаления файла, который все еще открыт в NFS (, который отображается как скрытый файл в этом каталоге.)

У вас также есть способ назначать номера устройств для экспорта NFS, чтобы гарантировать, что они не будут «перетасованы» при перезагрузке сервера NFS.

Но основная идея та же. Драйвер клиента NFS по-прежнему использует индексные дескрипторы и будет пытаться хранить файлы вокруг (на сервере ), пока на индексный дескриптор все еще ссылаются.

13
27.01.2020, 19:50

Assumption 2: I assume that if not all pages of the file are mapped into memory, that things will be fine until there is a page fault requiring pages from the file that have been replaced, and probably a segfault will occur?

Нет, этого не произойдет, потому что ядро ​​не позволит вам открывать для записи или замены что-либо внутри исполняемого в данный момент файла. Такое действие потерпит неудачу сETXTBSY[1] :

cp /bin/sleep sleep;./sleep 3600 & echo none >./sleep
[9] 5332
bash:./sleep: Text file busy

Когда dpkg и т. д. обновляют двоичный файл, он не перезаписывает его, а использует rename(2), который просто указывает запись каталога на совершенно другой файл, и любые процессы, которые все еще имеют сопоставления или открытые дескрипторы старого файла, будут продолжайте использовать его без проблем.

[1] защита ETXBUSYне распространяется на другие файлы, которые также можно считать «текстовыми» (= живой код/исполняемый файл ):общие библиотеки, классы Java и т. д.; изменение такого файла во время отображения другим процессом приведет к сбою процесса. В linux динамический компоновщик покорно передает флаг MAP_DENYWRITEв mmap(2), но не заблуждайтесь --, это не имеет никакого эффекта. Пример:

$ 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
8
27.01.2020, 19:50

Ответ filbranden верен, если предположить, что процесс непрерывного выпуска выполняет правильную атомарную замену файлов через rename. Если это не так, но изменяет файл в месте -, все по-другому. Однако ваша ментальная модель все еще ошибочна.

Невозможно, чтобы что-то изменилось на диске и не соответствовало кешу страниц, потому что кеш страниц является канонической версией и той, которая изменена. Любая запись в файл происходит через кеш страницы. Если он там уже присутствует, существующие страницы изменяются. Если ее еще нет, попытки изменить часть страницы приведут к кэшированию всей страницы с последующим изменением, как если бы она уже была кэширована. Записи, которые занимают целую страницу или более, могут (и почти наверняка )оптимизируют шаг чтения, подкачивающий их. В любом случае существует только одна каноническая модифицируемая версия файла (*), в кэше страниц.

(*)Я немного солгал. Для NFS и других удаленных файловых систем их может быть более одной, и они обычно (зависят от того, какая из них и какие параметры монтирования и сервера -используются )неправильно реализуют атомарность и семантику упорядочения для записи. Вот почему многие из нас считают их принципиально неработоспособными и отказываются использовать их в ситуациях, когда записи будут выполняться одновременно с использованием.

4
27.01.2020, 19:50

Теги

Похожие вопросы