read() из файлов - блокирующее и неблокирующее поведение

Давайте предположим, что мы открыли файл, используя fopen() и из полученного указателя файла извлеките дескриптор файла, используя fileno(), Затем мы делаем много (>10^8) случайных read()s относительно небольших кусков, размером от 4 до 10 КБ из этого файла:

Ожидается ли поведение такого read() может вернуть меньше байтов, чем запрошено, без настройки errno, если файловая система является

  1. ext3

  2. NFS

  3. OCFS2

  4. комбинация 2 и 3 (OCFS2 с помощью NFS)

?

Мои чтения дали мне заключение, что это не должно быть возможно для 1. (если файл не имеет O_NONBLOCK установить, если это возможно для ext3 чтобы он был установлен), но для остальных трех (2., 3., 4.) я не уверен.

(Кстати: я мог предположить, что имея O_NONBLOCK не установлен по умолчанию в любом случае?)

Этот вопрос возник, потому что я заметил read()s возвращает меньше байтов, чем запрашивается без errno установить в случае 4.

Проблема для детализации этого путем тестирования состоит в том, что такое поведение происходит в <1/1000000000 случаях... - что все еще слишком часто:-}

Обновление: средний размер файла составляет от нескольких ТБ до 1 ГБ.

2 ответа

Вы не должны предполагать, что read() не вернет меньше байтов, чем требуется для любой файловой системы. Это особенно верно в случае больших чтений, поскольку POSIX.1 указывает, что поведение read() для размеров, превышающих SSIZE_MAX, зависит от реализации. В этом основном Unix-боксе, который я сейчас использую, SSIZE_MAX составляет 32767 байт. Тот факт, что read() всегда возвращает полную сумму сегодня, не означает, что это произойдет в будущем.

Одной из возможных причин может быть то, что в будущем приоритеты ввода / вывода будут более четко прописаны в ядре. Например, вы пытаетесь читать с того же устройства, что и другой процесс с более высоким приоритетом, и другой процесс получит лучшую пропускную способность, если ваш процесс не будет вызывать перемещение головы от секторов, которые хочет другой процесс. Ядро может предпочесть дать вашему read() короткий счет, чтобы вывести вас из строя на некоторое время, вместо того, чтобы продолжать выполнять неэффективные чередующиеся чтения блоков. Более странные вещи были сделаны ради эффективности ввода / вывода. То, что не запрещено, часто становится обязательным.

Мы решили проблему, описанную как имеющую read() вернуть меньше байтов, чем запросить при чтении из файла, расположенного на NFS монтировать, указывая на OCFS2 файловая система (случай 4 в моем вопросе).

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

Чтобы прочитать все данные так же просто, как просто read()снова и снова, пока не будет прочитан объем запрашиваемых данных.

Более того, такая настройка иногда делает read() потерпеть неудачу с EIOи даже тогда простойread() приводит к успеху и данные приходят.

Мой вывод: чтение через OCFS2 с помощью NFS марки read()из файлов ведут себя как read()из розеток, что не соответствует спецификациям read() http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html:

При попытке прочитать файл (кроме канала или FIFO), который поддерживает неблокирующее чтение и не имеет данных, доступных в настоящее время:

Если O_NONBLOCK установлен, read() должен вернуть -1 и установить errno на [EAGAIN].

Если O_NONBLOCK очищен, read() должен блокировать вызывающий поток, пока некоторые данные не станут доступными.

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

Другие вопросы по тегам