Skip to content

Повреждение дисков виртуальной машины при миграции в Proxmox, часть 2

Первоначально я решил проблему простым патчем:

--- /usr/share/perl5/PVE/Storage/LVMPlugin.pm.bak       2018-12-14 14:21:48.000000000 +0300
+++ /usr/share/perl5/PVE/Storage/LVMPlugin.pm   2019-01-10 12:35:44.665242759 +0300
@@ -601,7 +601,7 @@
        }
        my $file = $class->path($scfg, $volname, $storeid)
            or die "internal error: failed to get path to newly allocated volume $volname\n";
-       run_command(['dd', "of=$file", 'conv=sparse', 'bs=64k'],
+       run_command(['dd', "of=$file", 'bs=64k'],
                    input => '<&'.fileno($fh));
     };
     if (my $err = $@) {

Но оказалось, что патч не совсем корректный - исправляет LVM, но ломает LVM Thin. Так как LvmThinPlugin наследуется от LVMPlugin, он использует ту же командную строку для запуска dd. В результате удаления аргумента conv=sparse диск после миграции начинает занимать свой полный объем, становится не разреженным. Один из разработчиков предложил корректное исправление вот здесь: https://pve.proxmox.com/pipermail/pve-devel/2019-January/035313.html

 PVE/Storage/LVMPlugin.pm     | 10 ++++++++--
 PVE/Storage/LvmThinPlugin.pm |  7 +++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/PVE/Storage/LVMPlugin.pm b/PVE/Storage/LVMPlugin.pm
index 72d7464..9ad7979 100644
--- a/PVE/Storage/LVMPlugin.pm
+++ b/PVE/Storage/LVMPlugin.pm
@@ -620,8 +620,8 @@ sub volume_import {
     }
     my $file = $class->path($scfg, $volname, $storeid)
         or die "internal error: failed to get path to newly allocated volume $volname\n";
-    run_command(['dd', "of=$file", 'conv=sparse', 'bs=64k'],
-                input => '<&'.fileno($fh));
+
+    $class->volume_import_write($fh, $file);
     };
     if (my $err = $@) {
     eval { $class->free_image($storeid, $scfg, $volname, 0) };
@@ -630,4 +630,10 @@ sub volume_import {
     }
 }
 
+sub volume_import_write {
+    my ($class, $input_fh, $output_file) = @_;
+    run_command(['dd', "of=$output_file", 'bs=64k'],
+    input => '<&'.fileno($input_fh));
+}
+
 1;
diff --git a/PVE/Storage/LvmThinPlugin.pm b/PVE/Storage/LvmThinPlugin.pm
index 122fb37..aafc202 100644
--- a/PVE/Storage/LvmThinPlugin.pm
+++ b/PVE/Storage/LvmThinPlugin.pm
@@ -374,4 +374,11 @@ sub volume_has_feature {
     return undef;
 }
 
+# used in LVMPlugin->volume_import
+sub volume_import_write {
+    my ($class, $input_fh, $output_file) = @_;
+    run_command(['dd', "of=$output_file", 'conv=sparse', 'bs=64k'],
+    input => '<&'.fileno($input_fh));
+}
+
 1;
-- 
2.11.0

Повреждение дисков виртуальной машины при миграции в Proxmox

Внезапно столкнулся с такой проблемой. Есть кластер Proxmox VE, и виртуальная машина в нем, которая работает на ноде A. Понадобилось перенести ее на ноду B. После переноса она не запускается. Операционная система ругается на повреждение системных файлов. Восстановление из бекапа и повторный перенос проходят с точно таким же результатом, т.е. это не случайный сбой. Проверка контрольных сумм файлов показывает, что на ноде B они действительно повреждены.

Много времени было убито в попытках понять вероятную причину, но оказалось вот что.

Если у вас кластер Proxmox VE и в качестве хранилища используется LVM (обычный, не thin), то при миграции между нодами содержимое дисков может быть повреждено. Схема миграции дисков на LVM простая - содержимое читается посредством dd, передается по сети и записывается в месте назначения с помощью того же dd. Запись осуществляется командной строкой вида:

dd of=/dev/pve/vm-100-disk-0 conv=sparse bs=64k

Уже догадались, да? Или нет?

Each CONV symbol may be:
...
sparse try to seek rather than write the output for NUL input blocks
...

Proxmox помешан на тонких хранилищах, где образы дисков занимают столько же места, сколько данные внутри них - LVM Thin, ZFS, разрежённые файлы. Похоже кто-то из разработчиков забыл, что с простым LVM такое не работает. Если на виртуальном диске есть нулевые блоки, то после переноса диска на другую ноду вместо них окажутся неопределенные данные, а именно - то, что было ранее записано на этом месте на диске хост-машины.

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

Все сказанное актуально для последней на текущий момент версии:

proxmox-ve: 5.3-1 (running kernel: 4.15.18-9-pve)
pve-manager: 5.3-6 (running version: 5.3-6/37b3c8df)

Судя по коммитам в git, могу предположить, что этой проблеме возможно не менее полутора лет. Неужели до сих пор никто не заметил такой критический баг с повреждением данных? Что, никто не использует кластер с локальным LVM хранилищем? Все сидят на ZFS, LVM Thin или NAS/SAN хранилищах?

Отправлено в багтрекер разработчиков: https://bugzilla.proxmox.com/show_bug.cgi?id=2050

 

 

Thermaltake DPS G App - сворачивание в трей при автозапуске

Посчастливилось стать обладателем "умного" блока питания THERMALTAKE SMART DPS SPG-0750DPCG. В блок питания встроен чип мониторинга, который позволяет получать следующие данные: напряжение и ток по каждой из линий (3.3V, 5V, 12V), выходную мощность, коэффициент эффективности, температуру и скорость вентилятора. Идея хорошая, но как всегда подкачало прилагающееся к хорошему железу убогое поделие китайских программистов.

Опустим общую кривость программы, данная заметка не об этом. Есть один очень раздражающий момент. Thermaltake DPS G App в 3 мажорной версии до сих пор не умеет такую простую вещь, как сворачиваться в трей при автозапуске. В итоге при каждом запуске Windows окно программы красуется по центру экрана и его приходится вручную закрывать.

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

#include <AutoItConstants.au3>
Opt("TrayIconHide", 1)
Opt("WinTitleMatchMode", 3)
Local $hWnd = WinWait("[TITLE:ThermaltakeDPSPOWER;CLASS:Qt5QWindowIcon]", "", 20)
If Not $hWnd Then Exit
WinActivate($hWnd)
If Not WinActive($hWnd) Then Exit
Local $aPos = MouseGetPos()
Opt("MouseCoordMode", 0)
MouseClick($MOUSE_CLICK_PRIMARY, 981, 21, 1, 0)
Opt("MouseCoordMode", 1)
MouseMove($aPos[0], $aPos[1], 0)

Достаточно добавить его в автозапуск и проблема решена.

Скрипт в виде файла: ttdpsgapptotray.au3

Скомпилированный бинарник: ttdpsgapptotray.exe

PinTo10v2 v1.2

В рамках автоматической установки Windows или в групповых политиках иногда возникает необходимость прикрепить или открепить ярлык программы на панели задач или в меню "Пуск". Скрипты на базе VBS, предназначенные для Windows 7, перестали работать в Windows 10. Для решения этой проблемы Stuart Pearson создал утилиту PinTo10 на базе NSIS. А позднее, так как NSIS не совсем хорошо подходит для данной цели, обновленную версию на C# - PinTo10v2. Ее официальная страница в интернете: https://pinto10blog.wordpress.com/.

Программа универсальная и работает как на Windows 7, так и на Windows 10. Windows 8 и серверные ОС не поддерживаются.

К сожалению, в процессе использования данной утилиты обнаружился баг. Программа вылетает с ошибкой при попытке работы с ярлыками на панели задач, если в пути запуска программы использовались короткие имена в формате "8.3".

Немного технических деталей. Например, программа запускается из временной папки, и переменная %TEMP% у пользователя LongUserName будет равна C:\Users\LONGUS~1\AppData\Local\Temp. Функция ChangeImagePathName(), с помощью которой PinTo10v2 симулирует Windows Explorer, из-за использования GetDirectoryName() развернет это в C:\Users\LongUserName\AppData\Local\Temp и выбросит исключение, т.к. новый путь якобы длиннее старого. Более того, исключение не обрабатывается, и программа в результате падает с ошибкой.

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

Моя модифицированная версия PinTo10v2 v1.2. Содержит исходный код и бинарник, скомпилированный Visual Studio 2015: PinTo10v2_1.2.7z

Оригинальная утилита PinTo10v2 v1.1 от Stuart Pearson:
https://www.dropbox.com/s/q4joxy231hz0klj/PinTo10v2_1.1.zip?dl=1.
Зеркало: PinTo10v2_1.1.zip

Модификация прошивки "от энтузиастов" для маршрутизаторов Asus, D-Link, Netgear

Прошивка от Vampik - не является самостоятельной прошивкой, это модификация прошивки 1.9.2.7-d/-rtn от энтузиастов (авторы - lly и theMIROn). Она в свою очередь является продолжением небезызвестных прошивок "от Олега".

Разработка модификации прекращена в 2013 г. в связи с устареванием оборудования и отсутствием поддержки новых моделей в ядре.

Последние версии прошивки:

Устаревшая прошивка ветки -d

Новая прошивка ветки -rtn

Примечания к поддерживаемым моделям:

D-Link DIR-320 rev. A1, A2. Прошивка -rtn урезанной версии из-за 4 МБ флеш-памяти. Удалена поддержка веб-камер, FTP-сервер, Samba, NFS, SNMP, tcpdump. Поддержка принтеров ограничена (отсутствует поддержка LPR). Поддержка USB-накопителей ограничена (отсутствует поддержка NTFS и утилиты для форматирования и проверки файловой системы). Доступна полная версия устаревшей прошивки ветки -d, но в ней нет поддержки новых модемов. Переход с оригинальной прошивки D-Link осуществляется через промежуточную прошивку DIR320-wimax-1.2.6.bin. Переход со старой прошивки от энтузиастов для WL500GPv2 осуществляется загрузкой прошивки по tftp в момент включения роутера. IP-адрес загрузчика: 192.168.0.1, на устройстве с которого производится прошивка необходимо установить адрес из подсети 192.168.0.0/24. После перехода на прошивку от энтузиастов обязателен сброс настроек.

Asus WL-700gE. Поддерживается только в случае перепайки флеш-памяти с 2 МБ на 8 МБ.

D-Link DIR-620 rev. C1. Нет поддержки второй версии этой ревизии, возможна неполная поддержка начиная со сборки 3.0.6.5218.

NetGear WNR3500L v1. Маркировка на корпусе: WNR3500U/WNR3500L. Требуется внимательно выбирать версию прошивки. Прошивки для v1 и v2 несовместимы между собой. Восстановление после загрузки неправильной версии прошивки возможно только при наличии USB-TTL конвертера.

NetGear WNR3500L v2. Маркировка на корпусе: WNR3500L v2. Требуется внимательно выбирать версию прошивки. Прошивки для v1 и v2 несовместимы между собой. Восстановление после загрузки неправильной версии прошивки возможно только при наличии USB-TTL конвертера. Промежуточная версия для перехода с родной прошивки: entware-wnr3500lv2.chk