Запись системного вызова Linux: гарантирует ли ядро последовательность записи данных?

#linux #system-calls

#linux #системные вызовы

Вопрос:

Я знаю, что ядро гарантирует, если не прерывается, определенный размер (предположительно, PIPE_BUF, 4096 Байт) данных, записанных атомарно, что означает, что другой процесс пытается прочитать блоки.

И все же мне было интересно, что, если я напишу еще один блок данных (скажем, «abc…[x байт] …xyz») на запоминающее устройство, во время выполнения ядром действия, будет ли ядро записывать abc первым, а xyz последним?

Если нет, то какой-либо другой процесс может прочитать «*…[x байт] …xyz» до завершения операции записи. Я думаю, это, безусловно, катастрофа для многих приложений.

Кто-нибудь знает реализацию или где я могу найти ответ в исходном коде ядра?

С нетерпением ждем ваших ответов! Спасибо!

[обновление 2011.11.12]

Я просмотрел исходный код, но не могу понять его полностью. Я обнаружил вызывающую цепочку «write -> vfs_write -> do_sync_write [циклы] -> generic_file_aio_write [inode_mutex] -> __generic_file_aio_write -> .. -> generic_perform_write -> .. -> __copy_from_user(to, from, n)

__copy_from_user — это макрос / функция, реализованная с помощью зависящих от архитектуры asm-кодов, и я не могу их сейчас понять. Но я думаю, что программист сделает это так, как большинство из нас думает, каким это должно быть…

Надеемся на дальнейшие разъяснения ~

Комментарии:

1. Взгляните на «Съесть мои данные» в качестве отправной точки: flamingspork.com/talks

2. Спасибо. Я прочитал презентацию. Это практично и описывает многие проблемы, но для меня недостаточно глубоко.

Ответ №1:

Данные могут быть физически сброшены на диск не в том порядке, в котором вы их записали, поэтому, если компьютер выйдет из строя в середине записи, вы можете увидеть «xyz» без «abc» после резервной загрузки системы. Но если предположить, что машина продолжает работать, ядро гарантирует, что все записи, по-видимому, происходят в правильном порядке.

Комментарии:

1. Да, я полностью понимаю реализацию кэширования ядром; но мне нужны некоторые доказательства для подтверждения последовательности записи… Должен ли я заглянуть в исходный код?

Ответ №2:

Всегда соблюдается правильный порядок.

Но при неатомной записи в приемник, который имеет несколько устройств записи, может случиться так, что полученные данные содержат, скажем, "abc...[n bytes]...[data from other writer]...[m bytes]...xyz" , где n m=x .

Таким образом, данные вставляются в совершенно другой блок данных.

При атомарной записи таких вещей не происходит.

РЕДАКТИРОВАТЬ: Для ясности, речь идет только о каналах и FIFOs. Что насчет файлов, я не знаю.

Комментарии:

1. итак… В каком состоянии ядро будет рассматривать запись как атомарную?

2. как вы сказали в своем вопросе — если размер записи ниже PIPE_BUF : Запросы на запись в байтах {PIPE_BUF} или меньше не должны чередоваться с данными от других процессов, выполняющих запись в том же канале. При записи, превышающей байты {PIPE_BUF}, данные могут чередоваться в произвольных границах с записями, выполняемыми другими процессами, независимо от того, установлен флаг O_NONBLOCK флагов состояния файла или нет.

3. Спасибо. Я прочитал справочную страницу, которая связывает PIPE_BUF только с каналами / FIFO («со следующими исключениями», говорится в нем). Интересно, есть ли какая-то аналогичная константа с обычными файлами…

4. Ой, ты прав. Я ничего не нашел о файлах таким образом. Но я полагаю, что даже здесь порядок записи также соблюдается. Как насчет атомарности, я не знаю.

5. Я заглянул в исходный код, write вызывает vfs_write , который вызывает do_sync_write, который, наконец, вызывает __copy_from_user(to, from, n), который зависит от архитектуры макроса / функции со сборками… В настоящее время я не в состоянии понять эти asm-коды, но я думаю, что разработчик сделает так, как думает большинство…

Ответ №3:

допустим, я пишу abc, который равен 4k, и def, который равен 4k.

Ядро не гарантирует, что если я напишу «abcdef» в блоке размером 8 кб, другой процесс не увидит «abc», а затем увидит «def» как две отдельные записи.

Но если я просто напишу 4k «abc», ядро гарантирует, что любой другой процесс никогда не увидит «a», затем «b», затем «c»

http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_14.html#SEC215

Вы на другом пути. Гарантия, которую вы хотите, заключается в том, что «xyz» никогда не будет прочитан перед «abc». Это совершенно другая гарантия. На самом деле, это больше, чем гарантия. Это просто само собой разумеется. И это не имеет ничего общего со сбросом блоков на диск. Это другой уровень системы.