Здесьтам говорится, что вы можете перезаписать исполняемый файл, и процесс будет работать нормально — он будет перечитан при перезапуске процесса.
Однако, когда я пытаюсь заменить двоичный файл во время выполнения процесса (с scp, с dev на тестовый сервер), он сообщает 'файл занят'. А если я заменяю файл общей библиотеки (*.so), все процессы, которые его связывают, падают.
Почему так? Я что-то упускаю? Как заменить бинарные файлы, не останавливая/не вызывая сбой процесса?
решение1
Как упоминалось вПочему программный пакет работает нормально даже во время обновления?, блокировка устанавливается на inode, а не на filename. Когда вы загружаете и выполняете двоичный файл, файл помечается как занятый — вот почему вы получаете ошибку ETXTBSY (файл занят) при попытке записи в него.
Теперь, для разделяемых библиотек это немного отличается: библиотеки получают отображение памяти в адресное пространство процесса с помощью mmap()
. Хотя MAP_DENYWRITE
может быть указано, по крайней мере Glibc в Linux молча игнорирует это (согласно странице руководства, не стесняйтесь проверять исходники) - проверьте этонить. Таким образом, вам фактически разрешено записывать файл, и поскольку он отображен в памяти, любые изменения видны практически сразу - это означает, что если вы постараетесь, вы сможете кирпичвашей машине, перезаписав библиотеку.
Поэтому правильный способ обновления:
удаление файла, которое удаляет ссылку на данные из файловой системы, так что они становятся недоступными для любых вновь созданных приложений, которые могут захотеть их использовать, при этом данные остаются доступными для тех, у кого они уже открыты (или отображены);
создание нового файла с обновленным содержимым.
Вновь созданные процессы будут использовать обновленное содержимое, запущенные приложения будут получать доступ к старой версии. Это то, что делает любая разумная утилита управления пакетами. Обратите внимание, что это не совсем безопасно - например, приложения, динамически загружающие код (использующие dlsym()
и друзей), будут испытывать проблемы, если API библиотеки изменится молча.
Если вы хотите быть на самом деле,ДействительноДля большей безопасности выключите систему, смонтируйте файловую систему из другого экземпляра операционной системы, обновите ее и снова запустите обновленную систему.
решение2
Обновление RPM делает то же самое — исполняет двоичные файлы и библиотеки, и при этом ничего не вылетает.
Так в чем же разница:
- отсоединить файл
- записать новый файл с тем же именем
Это НЕ заменит файл на месте: inode, ссылающийся на in-use-binary, все еще "занят", пока последний объект, держащий его открытым, не завершит работу. Новый файл будет создан с новым номером inode.
Сейчас scp
или cp
попытаюсь заменить файл на месте - что изменит содержимое, на которое ссылается inode. Это не работает - как вы описали.