Ускорение копирования с помощью copy_file_range - PullRequest
0 голосов
/ 22 января 2019

Я узнал о передаче данных в ядре между двумя файловыми дескрипторами в Linux и наткнулся на то, что я не могу понять.Вот цитата из copy_file_range manpage

copy_file_range() дает файловым системам возможность реализовать методы «ускорения копирования», такие как использование ссылок (т. Е. Два или более я-узлы, которые совместно используют указатели на одни и те же блоки диска копирования-при-записи) или копию на стороне сервера

Я привык думать об индексных узлах как о чем-то, что возвращается stat / statx системный вызов.Тип st_ino typedef ed здесь как

typedef unsigned long   __kernel_ulong_t;

Так что же это означает «два или более i-узлов, которые совместно используют указатели на одну и ту же копиюзаписать дисковые блоки "?

1 Ответ

0 голосов
/ 24 января 2019

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

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

Существует три уровня хранения файлов в типичной Linux FS:

  1. Запись файла в некотором каталоге (который сам является файлом, содержащим список таких записей). Такая запись по существу отображает имя файла в некоторый индекс. Это делается путем сохранения номера инода, известного как st_ino, который фактически является указателем на индекс в некоторой таблице.

  2. Индекс , который содержит некоторые общие (см. Далее) метаданные (как возвращенные stat) и некоторые указатели на блок (ы) данных, которые хранят фактический файл содержание.

  3. Фактические блоки данных

Так, например, жесткая ссылка - это запись в некотором каталоге, которая указывает на тот же индекс, что и «исходный» файл (и увеличивает «счетчик ссылок» внутри индекса). Это означает, что отличаются только имена файлов (и, возможно, каталогов), все остальные данные и метаданные распределяются между жесткими ссылками. Обратите внимание, что создание жесткой ссылки - это очень быстрый способ копирования файла. Единственным недостатком является то, что оба файла теперь должны обмениваться своим содержимым навсегда, так что это не настоящая копия. Но если бы мы использовали какой-нибудь метод copy-on-write для исправления части «write», это было бы очень хорошо. Это то, что некоторые FS (например, Btrfs ) поддерживают через ссылки.

Идея этого трюка с копированием при записи заключается в том, что вы можете создать новый индекс с новыми соответствующими метаданными, но при этом использовать одни и те же блоки данных. Вы также добавляете перекрестные ссылки между двумя inode в «невидимой» части метаданных inode, чтобы они знали, что они совместно используют блоки данных. Очевидно, эта операция очень быстрая по сравнению с реальным копированием. И снова, пока файлы только для чтения, все работает отлично. Но в отличие от жестких ссылок, мы можем иметь дело с записями, считая их независимыми. Когда выполняется некоторая запись, FS проверяет, является ли файл (или, скорее, индекс) действительно единственным владельцем блоков данных, и копирует данные перед записью в него. В зависимости от реализации FS он может копировать весь файл при первой записи или может хранить более подробные метаданные и копировать только блоки, которые должны быть изменены, и все же делить остальное между файлами. В последнем случае блоки могут вообще не копироваться, если размер записи больше, чем блок.

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

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

...