Как предотвратить изменения в базовом файле после того, как mmap () сделает файл видимым для моей программы? - PullRequest
1 голос
/ 07 июня 2019

Согласно mmap () manpage:

MAP_PRIVATE

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

Вопрос : Как предотвратить изменения вбазовый файл после mmap () - сделать файл видимым моей программе?


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

Так как файл может быть очень большим, существует несколько ограничений для дизайна:

  1. Не следует загружать весь файл в ОЗУ, так как файл может быть больше, чемдоступная физическая память

  2. Не должен копировать файлы при открытии, так как это сделает открытие новых файлов очень медленным

  3. Должен работать на файловых системах, таких как ext4, что делаетне поддерживает копирование при записи (cp --reflink / ioctl_ficlone)

  4. Не должно полагаться на обязательную блокировку файлов, поскольку это устарело и требует особой опции монтирования -o mand вфайловая система

  5. Пока изменения не видны в моем mmap (), можно изменить базовый файл в файловой системе

  6. Требуется только поддержка последних версий Linux и использование системных API, специфичных для Linux, в порядке

Структура данных, которую я разрабатываю, будет отслеживать список неотредактированных и отредактированных диапазонов в файлесохраняя начальный и конечный индекс диапазонов в Mmap() -ed буфер.Пока пользователь просматривает файл, диапазоны текста, которые никогда не были изменены пользователем, будут считываться непосредственно из mmap() исходного файла, в то время как файл подкачки будет хранить диапазоны текстов, которые были отредактированыпользователь, но не был сохранен.

Когда пользователь сохраняет файл, структура данных будет использовать copy_file_range , чтобы объединить файл подкачки и исходный файл для сборки нового файла.Чтобы это соединение работало, исходный файл, видимый моей программой, должен оставаться неизменным на протяжении всего сеанса редактирования.

Проблема : у пользователя могут одновременно быть другие программы, модифицирующие тот же файл, возможнодругие текстовые редакторы или некоторые другие программы, которые изменили текстовый файл на месте, после внесения несохраненных изменений в моем текстовом редакторе.

В такой ситуации редактор может обнаружить такие внешние изменения с помощью inotify, и затем я хочупредоставьте пользователю два варианта продолжения:

  1. отменить все несохраненные изменения и перечитать файл с диска, реализация этого параметра довольно проста

  2. позволяют пользователю продолжить редактирование файла, и в дальнейшем пользователь должен иметь возможность сохранить несохраненные изменения в новом месте или перезаписать изменения, которые были внесены другой программой, но реализация этого кажется сложной

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

Не думаю, что консультативные блокировки спасли бы ситуацию здесь во всех случаях, так как другие программы могут не поддерживать консультативную блокировку.

Моим идеальным решением было бы сделать так, чтобы, когда другие программы перезаписывали файл, система прозрачно копировала файл, чтобы моя программа продолжала видеть старую версию, в то время как другая программа заканчивает свою запись на диск и делает свою версию видимый в файловой системе. Я думаю, что ioctl_ficlone мог бы сделать это возможным, но, насколько я понимаю, это работает только с файловой системой копирования при записи, такой как btrfs.

Возможна ли такая вещь?


Любые другие предложения по решению этой проблемы также приветствуются.

1 Ответ

2 голосов
/ 08 июня 2019

То, что вы хотите сделать, невозможно с mmap, и я не уверен, возможно ли это вообще с вашими ограничениями.

Когда вы отображаете регион, ядро ​​может или не можетна самом деле загрузить все это в память.Область памяти, в которой отсутствуют данные, фактически будет содержать недопустимую страницу, поэтому при доступе к ней ядро ​​принимает ошибку страницы и отображает эту область в память.Этот регион, скорее всего, будет содержать все, что находится в этой части файла, в момент возникновения ошибки страницы.Существует опция MAP_LOCKED, которая пытается предварительно выполнить обход всех страниц, но не гарантирует ее, поэтому вы не можете полагаться на ее работу.

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

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

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

...