k001
k001
:...

April 2032
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

k001 [userpic]
where has my /dev/null gone?

Вы, друзья мои, не поверите, за чем я сегодня на работе полдня охотился! За /dev/null!!!

Значит, в новом ядре OpenVZ, базирующемся на 2.6.32 (конкретно, с сегодняшнего дня на 2.6.32.10), сижу, работаю, никого не трогаю. И вдруг бац! Вместо /dev/null девайса -- обычный файл! Иногда в нём что-то написано (что неудивительно, много кто делает > /dev/null). Принадлежит руту, права 0600. Соответственно, нерутовые скрипты, которые отправляют что-то в /dev/null, ругаются, что не могут туда ничего записать -- собственно, только по такой ругани я и заметил, что там вовсе не файл символьного устройства с правами доступа 666, а обычный файл.

Какое наше первое предположение? Кто-то файл символьного устройства удалил, а потом при первом же > /dev/null он создался. Экспериментальным путём было выяснено, что виноват первый вызов /etc/init.d/vz restart, точнее stop, ещё точнее первый vzctl stop $CTID. Тут мне стало очень стыдно, что я там где-то накосячил аж до того, что /dev/null удаляю.

Внимательно прогрепал исходники vzctl на предмет /dev/null -- не нашёл ничего предосудительного, кроме ошибки в одном из редко используемых скриптов (для добавления IP адреса в контейнер на базе Slackware) -- там был пропущен слеш в начале, то есть путь не абсолютный, а относительный получался. Но скрипт тот используется в контексте контейнера, причём текущий каталог рутовый, поэтому никакой ошибки происходит, и вообще всё это не имеет отношения к данной проблеме.

Что ещё интересно. Если потом /dev/null создать обратно, то он уже не удалялся. До следующей перезагрузки. Поэтому в ходе экспериментов приходилось машину постоянно перезагружать, что сильно замедлило процесс отладки.

Ну хорошо, мы видим, что вроде бы это делает vzctl. Как точно убедиться и воочию пронаблюдать, что это именно vzctl (или кто-то из кучи скриптов, которые он загружает) удаляет файл? Очевидно, с помощью strace -fF -oout vzctl stop 101. Однако, он не показал, что кто-то покушается на /dev/null (нет там ни unlink, ни rename). Всё страньше и страньше, сказал я в этот момент.

Так как я с какого-то момента разбирался не один, а вместе с коллегой кернель дивелопером Павлом Е., то мы очень много смеялись ржали, как ненормальные ходили по офису и спрашивали, кто украл /dev/null пошли прямым путём и куда-то там в ядро вписали отладочный printk, срабатывающий в случае, когда кто-то хочет удалить /dev/null. И он сработал, напечатал, когда при загрузке switch_root переключался с initrd-шного на обычный рут. А в нашем случае молчал. Тогда мы таким же макаром подпёрли rename. Тоже ничего. Всё чудесатее и чудесатее!!

Тут я отобрал клавиатуру и сделал то, что надо было сделать с самого начала -- ls -l /dev до и после проблемы, ну и diff -u промеж ними. Оказалось, что /dev/null не одинок -- в числе почивших в бозе файлов оказались также /dev/random, /dev/urandom, /dev/zero, /dev/full и что-то там ещё. Стало понятно, что vzctl тут точно не причём.

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

Проверить это предположение я не успел, уехал домой. Завтра буду читать, что это за гадский devtmpfs такой и какого чёрта он зохавал мой /dev/null.

Tags: , ,
Comments

devtmpfs -- это вам привет от greg kh. дятел :(

devtmpfs имеет право на существование. в embedded, например, где держать udev не резонно.

А нефиг было включать всё подряд, не разобравшись, что это такое :)

я брал конфиг от федоры специально, потому что потом мы будем работать на конфиге, максимально приближенном к rhel6.

А аудит в данном случае помочь не мог?

Оно там удалялось где-то на уровне vfs, поэтому, возможно, проходило мимо аудита. Точно я не знаю...