LINUX.ORG.RU

[СИ] Заполнен диск. Пропали файлы.

 


0

2

[СИ] Заполнен диск. Пропали файлы.

Ясык СИ
ОС UNIX

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

Но из-за этого сбоя пропали файлы. Как я догадался, причина
в том, что в некоторых программах есть проверка открытия файла,
но нет проверки записи. А в других программах сначала опустошается
старый файл, а потом записывает новое содержимое. Это тоже
не работает. Казалось бы место только что освободилось. Но нет.
Это было видно по FTP. Удалить файлы - да. Записать другие - нет.
По этой причине не удалось запустить небольшую, наспех написанную
тестовую программу записи.

Заполнение диска - случай редкий. Но можно ли как-то от этого
застраховаться?

Вопрос-1.
Если диск заполнен так, что больше не пишет, то всегда ли вызов
k=write();
будет возвращать ошибку? Система пишет не сразу на диск, а в свой
буфер. Не случится ли так, что в буфер запишет без ошибки, а на
диск не запишет?

Вопрос-2.
Файлы ошибок тоже не будет писать. А хотелось бы чтоб писало.
Как быть?

Вопрос-3.
Сработает ли такое: некоторым особо важным файлам установить
стандартную длину (1 кБ), и никогда их не опустошать, писать
весь буфер на старое место?

Кто знает прошу ответить.


man 2 write

anonymous
()

> Не случится ли так, что в буфер запишет без ошибки, а на диск не запишет?

случится. емнип, ещё Торвальдс говорил: «проверяйте возвращаемое значение (f)close, с*ки!».

> Вопрос-2.

не распарсил.

> Вопрос-3.

да. можно даже отммапить файл в память, если размер фиксирован.

arsi ★★★★★
()
Ответ на: комментарий от nanoo_linux

anonymous
Имелось в виду: на диске места нет, а k=write() >= 0
ENOSPC
Есть ответ Вопроса-1.

arsi
Есть отает Вопроса-3.

Вопрос-2 подразумевает, что программы записывают свои ошибки
в свои файлы ошибок. И последней записи о невозможности записи
там не будет.

В целом ответами удовлетворен. Спасибо.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

Вопрос-2 подразумевает, что программы записывают свои ошибки

в свои файлы ошибок. И последней записи о невозможности записи там не будет.

Ну так зарезервируй немного места для файла с ошибками, пока это место ещё есть.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

«Ну так зарезервируй немного места для файла с ошибками, пока это место ещё есть.»

Т. к. Вопрос-3 отвечен положительно, то так и можно сделать.
Сейчас все файлы ошибок ограничены 50 кБ, но с частичным
при ротации опустошением. Согласен заготовить функции для
записи ошибок вовсе без опустошения. Спасибо.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

> записи о невозможности записи там не будет.

и это чертовски логично ;)

вариант раз: резервируй логгером больше места, чем необходимо (ftruncate+fdatasync), и до того, как исчерпается резерв лог-файла, выплюнь в него сообщение о невозможности продолжать работу в таких условиях и корректно умри. но при любом раскладе не забывай перед закрытием файла лога сделать ftruncate до реального размера.

вариант два: пиши подобные сообщения в спец. лог на другом разделе или в заранее отведённый файл необходимого размера.

arsi ★★★★★
()

Ъ Unix-вэйный подход тут следующий:

1. Приложение, пишущее в файлы, работает с правами обычного пользователя (не root). Таким образом оно не может* выжрать всё дисковое пространство, т.к. файловые системы в Unix имеют резерв блоков для root-а.

2. Если write() обломился по причине ENOSPC, то надо ругнуться в syslog. Поскольку syslogd имеет привилегии root-а, то у него будет возможность записать эту ругань в лог.

Вот и всё, собственно. Никаких дополнительных приседаний не надо.

____
* Вообще говоря, всё зависит от ФС. Системный вызов write() всего лишь перевызывает через VFS соответствующую функцию ФС. Например, если ФС использует технику отложенного выделения блоков, то write() вполне может сказать, что всё зашибись, а факт физической нехватки места выяснится позже (например при вызове close()) и «записанные» данные будут, соответственно, потеряны.

Relan ★★★★★
()
Ответ на: комментарий от Relan

«write() вполне может сказать, что всё зашибись»

Что такое.
Только что все молча согласились, что выдаст ENOSPC,
и вдруг такое.
В мане про это не сказано.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

> Только что все молча согласились, что выдаст ENOSPC,

4.2.

> В мане про это не сказано.

опять 4.2:

NOTES
       A successful return from write() does not make any guarantee that data  has  been  committed  to
       disk.   In  fact,  on some buggy implementations, it does not even guarantee that space has suc‐
       cessfully been reserved for the data.  The only way to be sure is to call fsync(2) after you are
       done writing all your data.
arsi ★★★★★
()
Ответ на: комментарий от pathfinder

> Не гарантирует? Неужели так все плохо?

да, ошибся я, с кем не бывает… результат работы close() сильно зависит от устройства и ос. например, в линуксе при закрытии файла на блочном устройстве close() обычно делает fsync(), на что я когда-то нарывался, пытаясь выводить прогресбар копирования файла и после close() писать «готово»: 100% появлялось через пару секунд, а «готово» — через пару десятков секунд после 100%. но нет никакой гарантии, что close() на пайпе, сокете или последовательном порту сделает fsync()/tcdrain().

arsi ★★★★★
()
Ответ на: комментарий от oleg_2

> А fsync() что-нибудь гарантирует?

да выучи уже английский… нет, не гарантирует: если винт имеет свой кэш, при паверфейле нет никаких гарантий, что данные будут записаны после успешного вызова fsync().

arsi ★★★★★
()

Чтобы убедиться, что место под файл точно выделено и со временем данные туда запишутся, надо успешно проделать всё до close включительно.

Чтобы гарантировать, что данные легли на диск - fdatasync. Чтобы гарантировать, что и метаданные обновились - fsync. Это нужно делать, если файл стал длиннее или короче, например.

Чтобы не потерять старый файл при обновлении в случае вероломного исчерпания места, надо записывать данные в новый файл, делать ему fsync, закрывать и делать rename.

const86 ★★★★★
()
Ответ на: комментарий от const86

Успешные write() и close() не гарантируют, что данные
будут когда-нибудь записаны в файл. А может быть и
гарантируют, в том смысле, что они будут лежать в
буфере системы неделю, пока кто-нибудь не почистит
диск. Но это слишком долго. За это время всякое может
случиться. Грубая перезагрузка с отключением.

Известно, что fsync() сбрасывает данные не на диск, а
в буфер дисковода. Т. е. пользы мало от него.
Но может быть, он хоть точно вернет ошибку, если нет
места на диске. Ведь тут задействованы и ФС, и дисковод.
Чтож они - не знают, что нет места?


oleg_2
() автор топика

Самый нормальный вариант это настроить мониторинг свободного места. Остальные способы менее надёжны. Щас уже не середина 2000-х когда некоторые fs типа ext3 просто убивались насмерть при переполнении, но всё же...

Предложенные способы могут не работать или работать не правильно при сетевом монтировании дисков.

true_admin ★★★★★
()
Ответ на: комментарий от oleg_2

> Успешные write() и close() не гарантируют, что данные будут когда-нибудь записаны в файл.

Но место под них выделится до close.

Известно, что fsync() сбрасывает данные не на диск, а

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

Места может не быть на ФС, а не на диске, так что этот вопрос решается раньше.

const86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.