Що відбувається, коли файл, який на 100% завантажений у кеш сторінки, змінюється іншим процесом


14

Я знаю, що коли сторінка кеша сторінки змінена, вона позначається брудною і вимагає повернення, але що відбувається, коли:

Сценарій: Файл / програми / EXE, який є виконуваним файлом, повністю заповнено в кеш сторінки (усі його сторінки знаходяться в кеші / пам'яті) і виконується процесом P

Постійний випуск потім замінює / apps / EXE на абсолютно новий виконуваний файл.

Припущення 1: Я припускаю, що процес P (і будь-хто інший з дескриптором файлу, що посилається на старий виконуваний файл), буде продовжувати використовувати старе, в пам'яті / додатках / EXE без проблем, і будь-який новий процес, який намагається виконати цей шлях, отримає новий виконуваний файл.

Припущення 2: Я припускаю, що якщо не всі сторінки файлу будуть зібрані в пам'ять, то все буде добре, поки не з’явиться помилка сторінки, що вимагає заміни сторінок із файлу, і, мабуть, відбудеться сегментація?

Запитання 1: Якщо ви замикаєте всі сторінки файлу чимось на кшталт vmtouch, це взагалі змінює сценарій?

Запитання 2: Якщо / apps / EXE знаходиться на віддаленій NFS, чи має це значення? (Я припускаю, що ні)

Будь ласка, виправте або підтвердіть мої 2 припущення та дайте відповіді на мої 2 запитання.

Припустимо, це вікно CentOS 7.6 з ядром 3.10.0-957.el7

Оновлення: Думаючи про це далі, мені цікаво, чи цей сценарій не відрізняється від будь-якого іншого сценарію брудної сторінки.

Я припускаю, що процес, який записує новий двійковий файл, буде читати і отримувати всі сторінки кешу, оскільки всі вони завантажені на сторінку, і тоді всі ці сторінки будуть позначені брудними. Якщо їх заблокують, вони будуть просто марними сторінками, що займають основну пам'ять після того, як кількість посилань перейде до нуля.

Я підозрюю, що коли закінчуються програми, що виконуються в даний час, все інше використовуватиме новий бінарний файл. Якщо припустити, що це все правильно, я думаю, що це цікаво лише тоді, коли лише деякі файли завантажуються на сторінку.


Просто, щоб зробити це експліцитним, заміна файлу не буде великою справою (залежно від того, чи він повторно відкритий програмою і як програма реагує на модифікований вміст), але зміна файлів, що змінюються, може призвести до серйозних збоїв програм (це поширена проблема у світі Java, коли змінено zip-файл, у якому є запис каталогу mmaped). Однак це залежить від платформи, не гарантується, що змінилися регіони бачать зміни чи ні.
eckes

Відповіді:


12

Постійний випуск потім замінює / apps / EXE на абсолютно новий виконуваний файл.

Це важлива частина.

Спосіб випуску нового файлу полягає у створенні нового файлу (наприклад /apps/EXE.tmp.20190907080000), написанні вмісту, встановленні дозволів та права власності та, нарешті, перейменуванні (2) з використанням остаточного /apps/EXEфайлу.

Результат полягає в тому, що новий файл має нове число inode (що означає, що це фактично інший файл.)

І старий файл мав власний номер inode, який насправді все ще існує, навіть якщо ім'я файлу вже не вказує на нього (або імена файлів більше не вказують на цей inode.)

Отже, ключовим тут є те, що коли ми говоримо про "файли" в Linux, ми найчастіше насправді говоримо про "inode", оскільки після відкриття файлу inode - це посилання, яке ми зберігаємо на файл.

Припущення 1 : Я припускаю, що процес P (і будь-хто інший з дескриптором файлу, що посилається на старий виконуваний файл), буде продовжувати використовувати старе, в пам'яті / додатках / EXE без проблем, і будь-який новий процес, який намагається виконати цей шлях, отримає новий виконуваний файл.

Правильно.

Припущення 2 : Я припускаю, що якщо не всі сторінки файлу будуть зібрані в пам'ять, то все буде добре, поки не з’явиться помилка сторінки, що вимагає заміни сторінок із файлу, і, ймовірно, відбудеться сегментація?

Неправильно. Стара індея все ще існує, тому помилки сторінки в процесі використання старого двійкового файлу все одно зможуть знайти ці сторінки на диску.

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

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

До речі, це не тільки з бінарними файлами, але і з будь-якими відкритими файлами. Якщо ви відкриєте файл у процесі та вилучите файл, він буде зберігатися на диску, поки цей процес не закриє файл (або відмирає.) Аналогічно тому, як жорсткі посилання зберігають лічильник того, скільки імен вказують на індезу на диску, драйвер файлової системи (в ядрі Linux) зберігає лічильник того, скільки посилань на цей інод існує в пам’яті , і випускає inode з диска лише після того, як будуть звільнені всі посилання з запущеної системи.

Запитання 1 : Якщо ви замикаєте всі сторінки файлу чимось на кшталт vmtouch, це змінює сценарій

Це питання грунтується на хибному припущенні 2, що не заблокування сторінок призведе до відхилень. Це не стане.

Запитання 2 : Якщо / apps / EXE знаходиться на віддаленій NFS, чи має це значення? (Я припускаю, що ні)

Це мається на увазі , щоб працювати так само , як і більшу частину часу він робить, але є деякі «помилки» з NFS.

Іноді можна побачити артефакти видалення файла, який все ще відкритий у NFS (відображається як прихований файл у цьому каталозі.)

У вас також є спосіб присвоїти номери пристроїв експорту NFS, щоб переконатися, що вони не будуть "перестановлені" під час перезавантаження сервера NFS.

Але головна ідея та ж. Клієнтський драйвер NFS все ще використовує inodes і намагатиметься зберігати файли навколо (на сервері), поки на вкладку ще посилаються.


1
Блокує перейменування (2), поки кількість посилань на файл старого імені не перейде до нуля?
Грегг Левенталь

2
Ні, перейменування (2) не блокується. Стара інеда зберігається навколо потенційно дуже довго.
filbranden

1
Дивіться відповідь @ mosvy на те, чому ви не можете записати файл, який виконується (ви отримуєте ETXTBSY). Від’єднання та створення нового має той самий ефект перейменування: ви закінчуєте новий inode. (Перейменувати краще, тому що тоді немає моменту, коли ім'я файлу не існує, це атомна операція, що замінює ім'я, щоб вказати на новий inode.)
filbranden

4
@GreggLeventhal: "Яке припущення ви робите щодо процесу безперервного випуску, який я використовую, завдяки чому ви впевнені, що він використовує тимчасові файли?" - Тому що, поки існує Unix, це є єдиним розумним способом зробити це. renameмайже однакова операція з файлами та файловою системою, яка гарантовано є атомною (якщо припустимо, що ми не перетинаємо межі файлової системи чи пристрою), тому "створити тимчасовий файл, а потім rename" - це стандартний зразок для оновлення файлів. Наприклад, це також використовує кожен текстовий редактор на Unix.
Йорг W Міттаг

1
@ grahamj42: renameє частиною POSIX. Згідно з умовами, він включений посиланням на ISO C (розділ 7.21.4.2 у поточному проекті), але він знаходиться там.
Йорг W Міттаг

7

Припущення 2: Я припускаю, що якщо не всі сторінки файлу будуть зібрані в пам'ять, то все буде добре, поки не з’явиться помилка сторінки, що вимагає заміни сторінок із файлу, і, ймовірно, відбудеться сегментація?

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

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

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

[1] такий захист не поширюється на інші файли, які також можна вважати "текстовими" (живий код / ​​виконуваний файл): спільні бібліотеки, java-класи тощо; зміна такого файла під час відображення іншого процесу призведе до його збою. У Linux Linux динамічний лінкер гідно передає MAP_DENYWRITEпрапор mmap(2), але не помиляйтесь - це не має жодного ефекту.


1
У сценарії dpkg, у який момент перейменування завершується таким чином, що зубний апарат для / apps / EXE буде посилатися на індекс нового бінарного файла? Коли більше немає посилань на старий? Як це працює?
Грегг Левенталь

2
rename(2)є атомним; як тільки він завершиться, запис dir посилається на новий файл. Процеси, які до цього часу використовували старий файл, отримали б доступ до нього лише за допомогою наявних відображень або через відкриті до нього ручки (які можуть посилатися на стоматологічну сироту, що вже не доступна, крім як через /proc/PID/fd).
mosvy

1
Мені найкраще подобається ваша відповідь, тому що ваша згадка ETXTBSY привела мене до цього utcc.utoronto.ca/~cks/space/blog/unix/WhyTextFileBusyError, який відповідає на всі мої запитання.
Грегг Левенталь

4

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

Немає можливості змінити речі на диску та бути невідповідними кешу сторінки, оскільки кеш сторінок є канонічною версією та модифікованою. Будь-яке записування у файл відбувається через кеш сторінки. Якщо він уже присутній там, то існуючі сторінки будуть змінені. Якщо його ще немає, спроби змінити часткову сторінку призведуть до кешування всієї сторінки з подальшими змінами так, ніби вона вже була кешована. Пише, що охоплює цілу сторінку або більше, може (і майже напевно це зробити) оптимізувати крок читання, підключаючи їх. У будь-якому випадку існує лише одна канонічна модифікована версія файлу (*), коли-небудь (*), що існує в кеш-сторінках сторінки. .

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.