Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков Хостинг

5 Модуль CXD2545_SUBQ_OUT

Посмотрим на код модуля CXD2545_SUBQ_OUT отвечающий за субканал:

Код целиком
module CXD2545S_SUBQ ( input  wire        clk,       //     Clock.clk input  wire        reset,     //     Reset.reset  input  wire        in_eof,    // SUBQ_Sink.endofpacket input  wire        in_sof,    //          .startofpacket output wire        out_ready, //          .ready input  wire        in_valid,  //          .valid input  wire [31:0] in_data,   //          .data input  wire [1:0]  in_empty,  //          .empty  input  wire        in_sqck,   //  SUBQ_OUT.export output reg         out_sqso,  //          .export output reg         out_scor,  //          .export output wire        out_emph   //          .export );  assign out_ready = 1'b1;  reg [95:0] sub_q; reg [31:0] sub_q_2; reg [31:0] sub_q_1;  reg sqck_cur; reg sqck_prev; reg [3:0] scor_latch;  assign out_emph = 1'b0;  always @(negedge clk) begin  if(in_valid == 1'b1) begin sub_q_1 <= in_data; sub_q_2 <= sub_q_1;  if(in_eof == 1'b1) begin sub_q <= {sub_q_2, sub_q_1, in_data}; end end  if((in_valid == 1'b1) && (in_eof == 1'b1)) begin scor_latch <= 4'b1111; out_scor <= 1'b1; end else begin  if(scor_latch > 0) begin scor_latch <= scor_latch - 1'b1; end else begin out_scor <= 1'b0; end  end  if((sqck_cur == 1'b0) && (sqck_prev == 1'b1)) begin out_sqso <= sub_q[95]; sub_q <= {sub_q[94:0], 1'b0}; end  sqck_cur  <= in_sqck;  sqck_prev <= sqck_cur; end  endmodule

Ну и по порядку:

input  wire        in_sqck,   //  SUBQ_OUT.export output reg         out_sqso,  //          .export output reg         out_scor,  //          .export output wire        out_emph   //          .export

Сигналы шины субканала, in_sqck — входящий тактовый импульс, out_sqso — выход данных, out_scor — сигнал что субканальные данные получены(это не совсем так. но в целом можно считать что так), out_emph — информация о том, что используется предискажение трека, в реальной жизни я таких дисков не видел поэтому подзабил на реализацию, хотя она и очень примитивна.

assign out_ready = 1'b1; 

Говорим шине Avalon-ST, что мы готовы принимать данные, а мы постоянно готовы это делать.

reg [95:0] sub_q; reg [31:0] sub_q_2; reg [31:0] sub_q_1; 

Регистры: sub_q используется для хранения текущего значения субканала, sub_q_1 и sub_q_2 части где храним формируемые данные для субканала.

if(in_valid == 1'b1) begin sub_q_1 <= in_data; sub_q_2 <= sub_q_1;  if(in_eof == 1'b1) begin sub_q <= {sub_q_2, sub_q_1, in_data}; end end 

Если на шине Avalon-ST есть данные, то полученные данные мы записываем в sub_q_1, а то, что было в sub_q_1, переносим в sub_q_2. Напоминаю, что в Verilog всё работает параллельно. Поэтому, несмотря на такой порядок строк, выполнится всё именно так, как я описал.

Если же пришел флаг in_eof(конец пакета), то мы формируем регистр sub_q в которые записываем три последних полученных 32х битных слова. Напоминаю, до выхода из блока Always значения регистров не поменяются, поэтому у нас in_data текущее значение шины данных Avalon-ST, sub_q_1 — прошлое, sub_q_2 дважды прошлое.

if((in_valid == 1'b1) && (in_eof == 1'b1)) begin scor_latch <= 4'b1111; out_scor <= 1'b1; end else begin if(scor_latch > 0) begin scor_latch <= scor_latch - 1'b1; end else begin out_scor <= 1'b0; end end 

Блок формирования scor. Если пришёл данные шины Avalon-ST валидны, и пришел флаг окончания пакета, переводим сигнал scor в высокое состояние, и устанавливаем счетчик в значение 15. Если условия не верны, данные не валидны или не конец пакета, декрементим счетчик пока он не станет равным нулю, и тогда опускаем сигнал scor. Код, по-моему, понятней, чем описание. И, наконец:

if((sqck_cur == 1'b0) && (sqck_prev == 1'b1)) begin out_sqso <= sub_q[95]; sub_q <= {sub_q[94:0], 1'b0}; end  sqck_cur  <= in_sqck;  sqck_prev <= sqck_cur; 

Отвязывать данные субканала от основного клока системы особой нужды нет, поэтому тот просто сделана проверка, что, клок перешел из высокого состояния в низкое. И тогда на линию out_sqso выводится значение 96 бита из sub_q, а данные самого sub_q сдвигаются влево на 1 бит.

По сути обычный сдвиговый регистр.Как это работает в целом, данные в SGDMA у нас передаются блоками по 2352 12 байт. SGDMA в начале каждой передаче при передаче первого байта(слова там всётаки 32 бита) флаг SOF, а при передаче последнего слова флаг EOF.

Двенадцать байт это три 32х битных слова. Этот модуль постоянно помнит два последних переданных слова, и при получении флага EOF из них и текущего слова формирует значения сдвиговый регистра на 96 бит. Который приставка и вытаскивает своим клоком.

6 Модуль CXD2545S_OUT

Теперь разберем модуль CXD2545S_OUT который отвечает за вывод данных на дата шину эмулируемой CXD2545:

Код целиком
module CXD2545S_OUT ( input  wire        clk,      //   clock.clk input  wire        rst,      //        .reset_n output wire        in_ready, //      .ready input  wire        in_valid, //        .valid input  wire [31:0] in_data,  //        .data input  wire        in_sof,   //        .startofpacket input  wire        in_eof,   //        .endofpacket input  wire [1:0]  in_empty, //        .empty    output reg      cd_c2po, output wire    cd_clk, output reg    cd_lr, output reg   cd_data );  assign in_ready = wait_data;  reg [47:0] cddata; reg [47:0] cddata_new;  reg wait_data;   reg [9:0] word_cnt;  reg new_c2po;  always @(negedge clk) begin if(rst == 0) begin wait_data <= 1'b1; word_cnt <= 10'h000; new_c2po <= 1'b0; end else begin  if((wait_data == 1) && (in_valid == 1)) begin if(in_sof == 1'b1) begin word_cnt <= 10'h000; end else begin word_cnt <= word_cnt   1'b1; end  if((word_cnt < 587) || (in_sof == 1'b1)) begin cddata_new <= { in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31:16],  in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15:0]   }; wait_data  <= 1'b0; end   end  if((cd_cnt == 0) && (clk_out == 1)) begin if(wait_data == 0) begin wait_data <= 1'b1; cddata  <= cddata_new; new_c2po  <= 1'b0; end else begin cddata <= 48'h000000000000; new_c2po <= 1'b1; end end  end end  reg [5:0] cd_cnt; reg clk_out; reg [47:0] cdout_data; reg c2po_delay; always @(negedge clk) begin clk_out <= ~clk_out; if(clk_out == 1'b1) begin cd_c2po <= c2po_delay; if(cd_cnt > 0) begin cd_cnt <= cd_cnt - 1'b1; end else begin cd_cnt <= 47; cdout_data <= cddata; c2po_delay <= new_c2po; end cd_lr   <= (cd_cnt < 24) ? 1'b0 : 1'b1; cd_data <= cdout_data[cd_cnt]; end; end  assign cd_clk = clk_out;  endmodule

Выходные сигналы шины данных:

output regcd_c2po, output wirecd_clk, output regcd_lr, output regcd_data 

Тут уже знакомые нам сигналы cd_clk клок данных сидирома, cd_lr передаваемый канал левый правый, cd_data сами данные каналов. А вот сигнал cd_c2po, что-то новое. На любом физическом носители при чтении неизбежно время от времени возникают ошибки. Это особенность физического мира.

Много ошибок CXD2545 может исправить сама, и мы про это даже не узнаем, но если ошибок слишком много то исправить их уже не получится. Тогда CXD2545 сообщает сигналом C2PO, что прочитанное слово содержит ошибки. Что делать с этим решает уже принимающая сторона, аудиоданные можно например интерполировать, бинарные данные интерполировать нельзя, но можно попытаться восстановить их, благо в секторе сеть для этого специальные поля(не всегда).

assign in_ready = wait_data; 

Здесь как с субканальными данными всегда принимать данные не получится, получаем мы их сразу по 32 бита, а выводим по одному. Поэтому мы должны говорить шине Avalon-ST когда мы приняли от неё данные, и она может передавать следующее слово.

if(rst == 0) begin wait_data <= 1'b1; word_cnt <= 10'h000; new_c2po <= 1'b0; 

если к нам пришёл ресет, то сбрасываем счетчик переданных слов, сбрасываем новое значение с2po и говорим что мы ждем новых данных.

if((wait_data == 1) && (in_valid == 1)) begin 

Если мы ждем данных, и они появились на шине:

if(in_sof == 1'b1) begin word_cnt <= 10'h000; end else begin word_cnt <= word_cnt   1'b1; end 

Если это первое слово в пакете сбрасываем счетчик переданных слов, если нет то увеличиваем его на единицу.

if((word_cnt < 587) || (in_sof == 1'b1)) begin cddata_new <= { in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31], in_data[31:16], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15], in_data[15:0] }; wait_data  <= 1'b0; end 

Если счетчик слов меньше 587 или мы получили первое слово в пакете, то загружаем его в регистр cddata_new. А так как данные мы передаем по шестнадцать бит на канал, а CXD2545 передавал их по двадцать четыре бита, при этом первые девять бит всегда одинаковы.

Мы размножаем первые девять бит каждого канала и таким способом получаем 24х битный регистр, очень удобная возможность FPGA. И после этого говорим, что данные нам теперь не нужны. Почему 587 у нас вектор передается как 2352 12, сначала данные сектора потом субканал.

if((cd_cnt == 0) && (clk_out == 1)) begin if(wait_data == 0) begin wait_data <= 1'b1; cddata   <= cddata_new; new_c2po  <= 1'b0; end else begin cddata  <= 48'h000000000000; new_c2po <= 1'b1; end end 

Тут всё чуточку запутанней, cd_cnt это счетчик переданных бит идёт на уменьшение. Так вот когда он доходит до 0 и при этом клок в фазе фиксации сигналов. Мы проверяем если ли у нас данные для отправки. Если есть мы их закидываем в регистр cddata, выставляем флаг ошибок C2PO в ноль(нету ошибок) и ставим флаг что нам нужен очередной блок данных.

Если же данных нет, мы кидаем в регистр данных нули, и ставим флаг С2PO, что у нас валят ошибки. В целом это не совсем верная работа этого флага, но оно работает.Но в этом модуле у нас есть ещё и второй блок Always который правда привязан к тому-же событию, что и первый. Это потому, что этот модуль наследие “монстра”, а не написан с нуля как модуль субканальных данных.

always @(negedge clk) begin clk_out <= ~clk_out; if(clk_out == 1'b1) begin cd_c2po <= c2po_delay; if(cd_cnt > 0) begin cd_cnt <= cd_cnt - 1'b1; end else begin cd_cnt <= 47; cdout_data <= cddata; c2po_delay <= new_c2po; end cd_lr   <= (cd_cnt < 24) ? 1'b0 : 1'b1; cd_data <= cdout_data[cd_cnt]; end; end 

Всё комментировать уже сил нет, да и думаю, вас тоже это уже, изрядно утомило. Вкратце, здесь генерируется выходная частота clk_out которая будет в два раза ниже чем входящая clk. Идёт подсчет переданных бит. И в момент передачи последнего, мы обновляем данные в регистре передачи данных.

А также в зависимости от текущего передаваемого бита, генерируем сигнал CDLR. Ну и сигнал c2po_delay синхронизируется с передаваемыми данными точно до такта. Все эти заморочки нужны, для того чтобы у нас было прокэшировано одно слово. Это даст нам время на заполнение шины данных сидирома, пока будут лететь субканальные данные, и будет происходить старт новой передачи в SGDMA.

4 Эмуляция механики

Видно было, что проблемы начинаются при чтении секторов расположенных далеко друг от друга. Например если запустить на воспроизведение второй трек, то он достаточно быстро начнет воспроизводиться. А вот если сразу восьмой, то там будет куча команд позиционирования, и воспроизводиться может начать, например четвертый или пятый. Приставка сначала пытается сделать позиционирование при помощи работы каретки напрямую командой 0x2, потом при помощи команд 0x4 пытается компенсировать ошибку. Но либо есть ограничение на количество команд, либо на время выполнения команда. И в итоге она не успевает это сделать. Либо вообще отказываясь воспроизводить трек, либо воспроизводит не тот. С играми также пока сектора игры близко всё ок, но если стоят дальше и идёт позиционирование через 0x2 то начинаются глюки. В целом я уже читал, что
приставка рассчитывает время нужное, чтобы каретке примерно приехать в нужную область, и даёт команду движения 0x2 в нужную сторону, потом на некоторое время она дает команду движения в противоположную сторону для компенсации инерции. Отсюда вырисовался очень простой план. После 0x2 запускаем таймер, и если пришла команда двигаться в противоположную сторону, останавливаем таймер. И по полученному времени выясняем примерно, где мы должны были оказаться. Дальше была попытка подобрать нужно число секторов в пересчете на время. Но выходила странная ситуация я мог подобрать например время для трека семь. Прям вот идеально. Но когда переходил на допустим трек двенадцать, я получал, тоже самое время. Я посмотрел логи которые снимал до отпайки CXD2545. Там время на разных треках разнилось. Например, можно посмотреть
здесь файлы Forsaken_play_track_6.dsl и Forsaken_play_track_12.dsl У меня же оно было всегда примерно одинаково и сильно больше указанного. Остаётся вопрос почему? Я долго сидел и смотрел на команды в анализаторе. Это было не очень удобно. А по работе как раз шел проект, для которого, я писал вспомогательные тулины. Для отладки протокола. Которые генерили более удобочитаемый формат. Я адаптировал их под свою задачу. Посмотреть получаемые логи можно тут. Все, что было видно, что приставка даёт команду 0x2 потом 0xB потом через нужное время останавливает каретку.
Вот, например, для трека номер семь:
Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков
Или вот трек десять:
Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков
Ну всё как ожидалось, но почему у меня она стремится судя по времени аж за границу диска. Долго ли коротко ли(сразу скажу долго). Но перечитывая описание команды 0xB:

The traverse monitor count is set when the traverse status is monitored by the SENS output COMP and COUT.

Как-то оно мониторится через SENS выводя COMP и COUT. Опять этот SENS. Я уже даже нашёл к тому моменту прошивку SUB-CPU и поковырялся в ней. Да есть места, где вроде бы читается SENS. По прошивке SENS читался после посылки 8 бит по шине управления CXD2545, причем посылать XLAT было не обязательно.

По даташиту зачастую первых 4х бит достаточно. Да там был список сигналов, которые можно получить с этого пина SENS. Некоторые при этом были продублированы физическими пинами чипа. И почему, после того как выбрали нужное значение SENS, оно может произвольно, где ему вздумается.

Чтение описания как работают команды позиционирования, вообще вводили в диссонанс. Сами команды ориентировались на эти сигналы COUT и COMP. Как-то всё было странно(а может простуда делала свое дело). Создавалось ощущение что автосеквенсор прям отдельный модуль от системы позиционирования. И тут я натыкаюсь, что ещё бывала связка CXA1372 CXD2510Q и оказывается, причем за функции позиционирование отвечала как раз CXA1372, а за декодирование данных CXD2510Q. А наша CXD2545 возможно была получена упаковкой их в один корпус. Интересно конечно, но ответов не прибавилось. Однако чтение того, как же работает эта самая SENS в разных случаях, привело простой и банальной мысли. Это мультиплексор. Управляемый по шине команд. Поэтому свое состояние он может менять, не зависимо от клока. Ну-ка посмотрим, что у нас творится на дата шине, во время позиционирования:
Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков
К итак непонятно зачем летающим, 0xA0 и 0x50 добавилась еще, какая то 0xC9, судя по даташиту 0x5X это FOK(Focus OK), 0xAX это GFS, а 0xCX это тот самый COUT. Ладно, с этим вроде бы ясно. А теперь что такое этот COUT. Одноименный пин говорит, что это:

Track count signal input.

Пока ничего не ясно, идём дальше:

Counts the number of tracks set with Reg B.
High when Reg B is latched, toggles each time the Reg B number is input by CNIN. While $44
and $45 are being executed, toggles with each CNIN 8-count instead of the Reg B number

Вот бы была возможность посмотреть анализатором что происходит, но чипа CXD2545 отпаян, и возможности такой нет. Зная как он работает, я сейчас могу понять, что это значит, но на тот момент я понять не смог. Но как я уже писал выше, я к тому моменту ковырял прошивку SUB-CPU и решил, может быть IDA, что ни будь подскажет:

Если просто, то в seek_dist_msb хранится рассчитанная дистанция. Дальше код закидывает на шину 0xC5(потому что от другой версии приставки, но это аналогично 0xC9 нас интересуют только старшие 4 бита). И проверяет, если относительно прошлого раза SENS выдает новое значение, ну был 0 стал 1, или наоборот.

То значение seek_dist_msb декриментится. Когда дошло до 0, выходим из этой части кода. Получается COUT, генерирует переход из одного состояние в другое при прохождении определенного числа треков. Которое и задаётся командой 0xB(toggles each time the Reg B number is input by CNIN).

Приставка значит не бездумно, водит кареткой ориентируясь на время, а мониторит сколько треков уже пролетело, и на основе этого решат когда останавливать каретку. Вот так сюрприз. И это значило одно, придётся делать функциональный блок для правильно работы SENS.

Zfs на linux

ZFS-это комбинированная файловая система и менеджер логических томов,
разработанная компанией Sun Microsystems. Начиная с Proxmox VE 3.4, родной
порт ядра Linux файловой системы ZFS вводится как дополнительная файловая
система, а также как дополнительный выбор для корневой файловой системы.
Нет необходимости вручную компилировать модули ZFS — все пакеты
включены.

С помощью ZFS, можно достичь максимальной производительности как для
предприятия с низко бюджетными аппаратными средствами, так и на
высокопроизводительных системах, используя кэширование SSD или даже
установку только SSD. ZFS может заменить дорогостоящие аппаратные
raid-карты умеренной нагрузкой на процессор и память в сочетании с простым
управлением.

ОБЩИЕ ПРЕИМУЩЕСТВА ZFS

  1. Оборудование

    ZFS сильно зависит от памяти, поэтому вам нужно по крайней мере 8 ГБ,
    для начала. На практике используйте столько, сколько вы можете
    получить для вашего оборудования/бюджета. Для предотвращения
    повреждения данных мы рекомендуем использовать высококачественную ОЗУ
    ECC.

    Если вы используете выделенный кэш и / или диск журнала, вы должны
    использовать SSD корпоративного класса (например, Intel SSD DC S3700
    Series). Это может значительно повысить общую производительность.


    Важно
    Не используйте ZFS поверх аппаратного контроллера, который имеет
    свое собственное управление кэшем. ZFS должна напрямую
    взаимодействовать с дисками. Адаптер HBA — это то, что нужно, или
    что-то вроде контроллера LSI, переведенного в режим «IT»(initiator
    target).

    Если вы экспериментируете с установкой Proxmox VE внутри виртуальной
    машины (вложенная виртуализация), не используйте virtio для дисков
    этой виртуальной машины, поскольку они не поддерживаются ZFS. Вместо
    этого используйте IDE или SCSI (работает также с типом контроллера
    virtio SCSI).
  2. Установка в качестве корневой файловой системы

    При установке с помощью программы установки Proxmox VE можно выбрать
    ZFS для корневой файловой системы. Вам нужно выбрать тип RAID во время
    установки:

    RAID0
    также называется «чередование». Емкость такого Тома — это сумма
    емкостей всех дисков. Но RAID0 не добавляет избыточности, поэтому
    сбой одного диска делает том непригодным для использования.
    RAID1
    также называют «зеркалированием». Данные записываются одинаково на
    все диски. В этом режиме требуется как минимум 2 диска одинакового
    размера. Результирующая емкость-это емкость одного диска.
    RAID10
    комбинация RAID0 и RAID1. Требуется не менее 4 дисков.
    RAIDZ-1
    вариация на тему RAID-5, одинарная четность. Требуется не менее 3
    дисков.
    RAIDZ-2
    вариация на RAID-5, двойная четность. Требуется не менее 4 дисков.
    RAIDZ-3
    вариация на RAID-5, тройная четность. Требуется не менее 5 дисков.

    Программа установки автоматически разбивает диски на разделы, создает
    пул ZFS с именем rpool и устанавливает корневую файловую систему в ZFS
    subvolume rpool/ROOT/pve-1.

    Следующий подраздел называется rpool/data он создается для хранения
    образов виртуальных машин. Чтобы использовать это с инструментами
    Proxmox VE, установщик создает следующую запись конфигурации в
    /etc/pve/storage.cfg:

    После установки можно просмотреть состояние пула ZFS с помощью команды
    zpool:

    Команда zfs используется для настройки и управления файловыми
    системами ZFS. Следующая команда выводит список всех файловых систем
    после установки:

  3. Загрузчик

    В зависимости от того, загружается ли система в режиме EFI или legacy
    BIOS, программа установки Proxmox VE устанавливает grub или
    systemd-boot в качестве основного загрузчика. См.
    главу о загрузчиках хостов Proxmox VE
    раздел
    3.10
    для получения дополнительной информации.

  4. Администрирование zfs

    В этом разделе приведены некоторые примеры использования для общих
    задач. ZFS сама по себе очень мощная и предоставляет множество опций.
    Основными командами для управления ZFS являются zfs и zpool . Обе
    команды поставляются с подробными страницами руководства, которые
    можно прочитать с помощью:

    # man zpool
    # man zfs

    Создание нового zpool
    Для создания нового пула необходим хотя бы один диск. Ashift должен
    иметь тот же размер сектора (2 в степени ashift) или больше, что и
    базовый диск.

    zpool create -f -o ashift=12 <pool> <device>

    Чтобы активировать сжатие

    zfs set compression=lz4 <pool>

    Создать новый пул с RAID-0
    Минимум 1 Диск

    zpool create -f -o ashift=12 <pool> <device1> <device2>

    Создать новый пул с RAID-1
    Минимум 1 Диск

    zpool create -f -o ashift=12 <pool> mirror <device1> <device2>

    Создать новый пул с RAID-10
    Минимум 4 Диска

    zpool create -f -o ashift=12 <pool> mirror <device1> <device2> mirror <device3> <device4>

    Создать новый пул с RAIDZ-1
    Минимум 3 Диска

    zpool create -f -o ashift=12 <pool> raidz1 <device1> <device2> <device3>

    Создать новый пул с RAIDZ-2
    Минимум 4 Диска

    zpool create -f -o ashift=12 <pool> raidz2 <device1> <device2> <device3> <device4>

    Создать новый пул с кэшем (L2ARC)
    Для повышения производительности можно использовать выделенный раздел
    диска кэша (используйте SSD). В качестве <устройства> можно
    использовать больше устройств, как показано в разделе » Создание
    нового пула с RAID*».

    zpool create -f -o ashift=12 <pool> <device> cache <cache_device>

    Создать новый пул с журналом (ZIL)
    Для повышения производительности можно использовать выделенный раздел
    диска кэша(SSD). В качестве <устройства> можно использовать
    больше устройств, как показано в разделе » Создание нового пула с
    RAID*».

    zpool create -f -o ashift=12 <pool> <device> log <log_device>

    Добавление кэша и журнала в существующий пул
    Если у вас есть пул без кэша и журнала. Первый раздел SSD на 2 раздела
    с parted или gdisk


    Важно
    Всегда используйте таблицы разделов GPT.

    Максимальный размер лог-устройства должен быть примерно в два раза
    меньше размера физической памяти, поэтому обычно это довольно мало.
    Остальная часть SSD может использоваться в качестве кэша.
    zpool add -f <pool> log <device-part1> cache <device-part2>

    Замена неисправного устройства

    zpool replace -f <pool> <old device> <new device>

    Замена неисправного загрузочного устройства при использовании
    systemd-boot

    sgdisk <healthy bootable device> -R <new device>
    sgdisk -G <new device>
    zpool replace -f <pool> <old zfs partition> <new zfs partition>
    pve-efiboot-tool format <new disk's ESP>
    pve-efiboot-tool init <new disk's ESP>

    Примечание
    ESP означает системный раздел EFI, который устанавливается как
    раздел #2 на загрузочных дисках, устанавливаемых установщиком
    Proxmox VE с версии 5.4. Дополнительные сведения см. В разделе
    Настройка нового раздела для использования в качестве
    синхронизированного ESP.

  5. Активация уведомлений по электронной почте

    ZFS поставляется с демоном событий, который отслеживает события,
    генерируемые модулем ядра ZFS. Демон также может отправлять
    электронные письма на события ZFS, такие как ошибки пула. Более новые
    пакеты ZFS поставляют демон в отдельном пакете, и вы можете установить
    его с помощью apt-get :

    # apt-get install zfs-zed

    Для активации демона необходимо отредактировать файл
    /etc/zfs/zed.d/zed.rc выберите нужный редактор и
    раскомментируйте параметр ZED_EMAIL_ADDR:

    ZED_EMAIL_ADDR="root"

    Обратите внимание, что Proxmox VE пересылает почту root на адрес
    электронной почты, настроенный для пользователя root.


    Важно
    Единственным параметром, который требуется, является
    ZED_EMAIL_ADDR . Все остальные настройки являются необязательными.

  6. Ограничение использования памяти zfs

    Для предотвращения нехватки производительности хоста рекомендуется
    использовать не более 50% (по умолчанию) системной памяти для ZFS ARC.
    Используйте любимый редактор, чтобы изменить конфигурацию в файле
    /etc/modprobe.d/zfs
    и вставить:

    options zfs zfs_arc_max=8589934592

    Этот пример настройки ограничивает использование до 8 ГБ.


    Важно
    Если ваша корневая файловая система ZFS, вы должны обновлять
    initramfs каждый раз, когда это значение изменяется:
    update-initramfs -u

  7. Своп на zfs

    Swap-пространство, созданное на zvol, может создавать некоторые
    проблемы, такие как блокировка сервера или создание высокой нагрузки
    ввода-вывода, часто наблюдаемой при запуске резервного копирования на
    внешнее хранилище.

    Мы настоятельно рекомендуем использовать достаточно памяти, чтобы вы
    не сталкивались с ситуациями нехватки памяти. Если вам нужно или вы
    хотите добавить swap, предпочтительно создать раздел на физическом
    диске и использовать его в качестве swapdevice. Вы можете оставить
    немного свободного места для этой цели в расширенных настройках
    установщика. Кроме того, вы можете снизить значение “swappiness”.
    Хорошее значение для серверов составляет 10:

    sysctl -w vm.swappiness=10

    Чтобы сделать подкачку постоянной, откройте файл /etc/sysctl.conf в
    своем любимомредакторе по вашему выбору и добавьте следующую строку:

    vm.swappiness=10

    Таблица 3.1: Значения параметра Linux kernel swappiness

  8. Зашифрованные наборы данных zfs

    ZFS на Linux версии 0.8.0 представила поддержку собственного
    шифрования наборов данных. После обновления с предыдущих версий ZFS на
    Linux, функция шифрования может быть включена для каждого пула:


    Внимание!
    В настоящее время нет поддержки загрузки из пулов с зашифрованными
    наборами данных с помощью Grub, и только ограниченная поддержка
    автоматического разблокирования зашифрованных наборов данных при
    загрузке. Старые версии ZFS без поддержки шифрования не смогут
    расшифровать сохраненные данные.


    Примечание
    Рекомендуется либо разблокировать наборы данных хранилища вручную
    после загрузки, либо написать пользовательский модуль для передачи
    ключевого материала, необходимого для разблокировки при загрузке,
    в ZFS load-key.


    Внимание!
    Перед включением шифрования критических данных установите и
    протестируйте процедуру резервного копирования.Если связанный
    ключевой материал/парольная фраза/ключевой файл был потерян,
    доступ к зашифрованным данным больше невозможен.

    Шифрование должно быть настроено при создании
    datasets/zvols, и по умолчанию наследуется дочерним
    наборам данных. Например, чтобы создать зашифрованный набор данных
    tank/encrypted_data и настроить его как хранилище в
    Proxmox VE, выполните следующие команды:

    Все гостевые volumes/disks, созданные в этом хранилище,
    будут зашифрованы с использованием общего ключа родительского набора
    данных. Чтобы фактически использовать хранилище, связанный ключевой
    материал должен быть загружен с помощью ZFS load-key:

    Также можно использовать (случайный) ключевой файл вместо запроса
    парольной фразы, задав свойства keylocation и keyformat либо во время
    создания, либо с помощью zfs change-key для существующих наборов
    данных:


    Внимание!
    При использовании файла ключей необходимо соблюдать особую
    осторожность, чтобы защитить его от несанкционированного доступа
    или случайной потери. Без ключевого файла невозможно получить
    доступ к открытым текстовым данным!

    Гостевой том, созданный под зашифрованным набором данных, будет иметь
    соответствующее свойство encryptionroot. Ключевой материал должен быть
    загружен только один раз на encryptionroot, чтобы быть доступным для
    всех зашифрованных наборов данных под ним.

    Смотри свойства
    encryptionroot , encryption , keylocation , keyformat и
    keystatus, команды zfs unload-key и
    zfs change-key и раздел шифрование в
    man ZFS для более детальной информации и продвинутого
    использования.

Изучаем исходники

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

wa-system/contact/waContact.class.php

Функция save($data, $validate) — осторожно, много кода!
/**
 * Saves contact's data to database.
 *
 * @param array $data Associative array of contact property values.
 * @param bool $validate Flag requiring to validate property values. Defaults to false.
 * @return int|array Zero, if saved successfully, or array of error messages otherwise
 */
public function save($data = array(), $validate = false)
{
    $add = array();
    foreach ($data as $key => $value) {
        if (strpos($key, '.')) {
            $key_parts = explode('.', $key);
            $f = waContactFields::get($key_parts[0]);
            if ($f) {
                $key = $key_parts[0];
                if ($key_parts[1] && $f->isExt()) {
                    // add next field
                    $add[$key] = true;
                    if (is_array($value)) {
                        if (!isset($value['value'])) {
                            $value = array('ext' => $key_parts[1], 'value' => $value);
                        }
                    } else {
                        $value = array('ext' => $key_parts[1], 'value' => $value);
                    }
                }
            }
        } else {
            $f = waContactFields::get($key);
        }
        if ($f) {
            $this->data[$key] = $f->set($this, $value, array(), isset($add[$key]) ? true : false);
        } else {
            if ($key == 'password') {
                $value = self::getPasswordHash($value);
            }
            $this->data[$key] = $value;
        }
    }
    $this->data['name'] = $this->get('name');
    $this->data['firstname'] = $this->get('firstname');
    $this->data['is_company'] = $this->get('is_company');
    if ($this->id && isset($this->data['is_user'])) {
        $c = new waContact($this->id);
        $is_user = $c['is_user'];
        $log_model = new waLogModel();
        if ($this->data['is_user'] == '-1' && $is_user != '-1') {
            $log_model->add('access_disable', null, $this->id, wa()->getUser()->getId());
        } else if ($this->data['is_user'] != '-1' && $is_user == '-1') {
            $log_model->add('access_enable', null, $this->id, wa()->getUser()->getId());
        }
    }

    $save = array();
    $errors = array();
    $contact_model = new waContactModel();
    foreach ($this->data as $field => $value) {
        if ($field == 'login') {
            $f = new waContactStringField('login', _ws('Login'), array('unique' => true, 'storage' => 'info'));
        } else {
            $f = waContactFields::get($field, $this['is_company'] ? 'company' : 'person');
        }
        if ($f) {
            if ($f->isMulti() && !is_array($value)) {
                $value = array($value);
            }
            if ($f->isMulti()) {
                foreach ($value as &$val) {
                    if (is_string($val)) {
                        $val = trim($val);
                    } else if (isset($val['value']) && is_string($val['value'])) {
                        $val['value'] = trim($val['value']);
                    } else if ($f instanceof waContactCompositeField && isset($val['data']) && is_array($val['data'])) {
                        foreach ($val['data'] as &$v) {
                            if (is_string($v)) {
                                $v = trim($v);
                            }
                        }
                        unset($v);
                    }
                }
                unset($val);
            } else {
                if (is_string($value)) {
                    $value = trim($value);
                } else if (isset($value['value']) && is_string($value['value'])) {
                    $value['value'] = trim($value['value']);
                } else if ($f instanceof waContactCompositeField && isset($value['data']) && is_array($value['data'])) {
                    foreach ($value['data'] as &$v) {
                        if (is_string($v)) {
                            $v = trim($v);
                        }
                    }
                    unset($v);
                }
            }
            if ($validate !== 42) { // this deep dark magic is used when merging contacts
                if ($validate) {
                    if ($e = $f->validate($value, $this->id)) {
                        $errors[$f->getId()] = $e;
                    }
                } elseif ($f->isUnique()) { // validate unique
                    if ($e = $f->validateUnique($value, $this->id)) {
                        $errors[$f->getId()] = $e;
                    }
                }
            }
            if (!$errors && $f->getStorage()) {
                $save[$f->getStorage()->getType()][$field] = $f->prepareSave($value, $this);
            }
        } elseif ($contact_model->fieldExists($field)) {
            $save['waContactInfoStorage'][$field] = $value;
        } else {
            $save['waContactDataStorage'][$field] = $value;
        }
    }

    // Returns errors
    if ($errors) {
        return $errors;
    }

    $is_add = false;
    // Saving to all storages
    try {
        if (!$this->id) {
            $is_add = true;
            $storage = 'waContactInfoStorage';

            if (wa()->getEnv() == 'frontend') {
                if ($ref = waRequest::cookie('referer')) {
                    $save['waContactDataStorage']['referer'] = $ref;
                    $save['waContactDataStorage']['referer_host'] = parse_url($ref, PHP_URL_HOST);
                }
                if ($utm = waRequest::cookie('utm')) {
                    $utm = json_decode($utm, true);
                    if ($utm && is_array($utm)) {
                        foreach ($utm as $k => $v) {
                            $save['waContactDataStorage']['utm_'.$k] = $v;
                        }
                    }
                }
            }

            $this->id = waContactFields::getStorage($storage)->set($this, $save[$storage]);
            unset($save[$storage]);
        }
        foreach ($save as $storage => $storage_data) {
            waContactFields::getStorage($storage)->set($this, $storage_data);
        }
        $this->data = array();
        $this->removeCache();
        $this->clearDisabledFields();
        wa()->event(array('contacts', 'save'), $this);

    } catch (Exception $e) {
        // remove created contact
        if ($is_add && $this->id) {
            $this->delete();
            $this->id = null;
        }
        $errors['name'][] = $e->getMessage();
    }
    return $errors ? $errors : 0;
}


Параметр $data содержит данные в формате

‘название поля’ => ‘значение поля’

, в функции я не заметил защиты от

, но не исключал, что фильтрация аргумента происходит до вызова самой функции. Мне стало лениво просматривать все места в коде, где вызывается save() и я решил проверить теорию экспериментальным путем.

Установив на локалку движок, первым делом я решил посмотреть структуру таблицы `wa_contact`.

Подключение четырех дисков как zfs массив raid-5 (raidz1)

Не забудем и про дополнительные четыре диска, которые в моем случае будут использоваться для хранения медиа файлов (фильмы, сериалы и др.)

И да, я знаю про специфику работы с RAID-5 и что к нему есть много вопросов, я решил пойти именно таким путем, вы же можете использовать свои знания и выбрать то, что кажется вам наиболее правильным. Но у ZFS RAID-5 есть одно преимущество, он восстановит потерянные данные, хоть и не целиком. А т.к. у меня там медиа данные, их можно без особого труда скачать снова. Это выгодно отличает его от обычного RAID-5. В итоге я потеряю файл/часть файла, но не потеряю весь массив данных.

Для начала проверим, видны ли они в системе, в этом нам поможет команда

lsblk

:

root@pve1:~# lsblk

В ответ мы увидим, что-то такое…

NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0   236G  0 disk 
├─sda1   8:1    0  1007K  0 part 
├─sda2   8:2    0   512M  0 part 
└─sda3   8:3    0 235.5G  0 part 
sdb      8:16   0   236G  0 disk 
├─sdb1   8:17   0  1007K  0 part 
├─sdb2   8:18   0   512M  0 part 
└─sdb3   8:19   0 235.5G  0 part 
sdc      8:32   0   2.7T  0 disk 
sdd      8:48   0   2.7T  0 disk 
sde      8:64   0   2.7T  0 disk 
sdf      8:80   0   2.7T  0 disk

Активные диски уже используются и на них можно наблюдать уже логические разделы, это два SSD диска: sda и sdb
А вот sdc, sdd, sde и sdf пока не задействованы, давайте это исправим!

Проверим созданный нами ранее RAID-1 из двух SSD

zpool list

Ответ

NAME     SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
rpool    234G  8.07G   226G         -     0%     0%  1.00x  ONLINE  -

Создадим RAID-5 из нужных нам дисков. Массив назовем rpoolz и пропишем полные пути к дискам (через /dev):

zpool create -f -o ashift=12 rpoolz raidz1 /dev/sdc /dev/sdd /dev/sde /dev/sdf

Не путайте с raidz2, это немного другое.
Проверяем более детально:

root@pve1:~# zpool list -v
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
rpool   234G   8.07G   226G         -     0%     0%  1.00x  ONLINE  -
  mirror   234G   8.07G   226G         -     0%     0%
    sda3      -      -      -         -      -      -
    sdb3      -      -      -         -      -      -
rpoolz   10.9T   2.14T   8.73T         -     0%     0%  1.00x  ONLINE  -
  raidz1   10.9T   2.14T   8.73T         -     0%     0%
    sdc      -      -      -         -      -      -
    sdd      -      -      -         -      -      -
    sde      -      -      -         -      -      -
    sdf      -      -      -         -      -      -

Папка массива в файловой системе доступна по пути, который мы прописали при создании: /rpoolz

В целом этого будет достаточно, но есть еще один момент, это вопрос «Как подключить данный массив как папку для хранения данных?»
Для начала необходимо отправиться в раздел Datacenter -> Storage
Например я добавил папку, куда сохраняю Backup архивы.

gost-proxmox-configure-4
Добавляем папку для Backup архивов
gost-proxmox-configure-5
Заполняем параметры для папки

Тут нужно заполнить ID — это имя директории, Directory — это путь в файловой системе к нужной папке. Выбрать тип хранимых данных. При добавлении типа VZDump backup file появится дополнительная настройка, где нудно указать количество хранимых Backup архивов для каждой виртуальной машины. (Настройка архивации виртуальных машин выполняется отдельно!)

Подключение папки массива в контейнерах LXC будем рассматривать уже в отдельных статьях.

Управление vps в proxmox

Панель управления — содержит инструменты управления сервером, как это было бы с физическим компьютером: включение, отключение, перезапуск, видео вывод экрана; дополнительные инструменты мониторинга нагрузки процессора, дисковой подсистемы и использования оперативной памяти.

Если у вас пропал удалённый доступ по ssh/vnc, вы всегда можете  подключиться к вашему VPS напрямую, и провести анализ неисправностей подключения и работы VPS.

Панель управления Proxmox можно найти по следующему адресу:

  1. Выбрать «Активные услуги»
  2. Нажать «управление» под нужной VPS

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Затем, на следующей странице, справа нажать на ссылку для подключения:

Для входа в панель управления наберите в строке браузера адрес, указанный в высланном при заказе письме, вида https://cnXX.justhost.ru:8006/.

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

ПримечаниеОбратите внимание на строку «Область» (на английской раскладке «Realm») должно быть выбрано значение Proxmox VE authentication server

После успешной авторизации перед Вами откроется интерфейс управления виртуальным сервером.

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Запуск VPS выполняется нажатием на одноименную кнопку Запуск на панели управления в правом верхнем углу.

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

После того как, Вы нажали на значение запуск, у Вас в панели задач, отобразится поставленная задача Вашему VPS.

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Вкладка Сводка позволяет просмотреть используемые ресурсы

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Если Вам необходимо открыть консоль для управления виртуальным сервером можно так же кликнуть на соответствующую кнопку на панели управления Консоль

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

  • Выключить (передаёт виртуальному серверу эмуляцию нажатия кнопки Power off, соответствующую обычному серверу)
  • Остановка (останавливает виртуальный сервер)
  • Приостановить (ставит на паузу виртуальную машину)
ВниманиеОстановка VPS является штатной процедурой и не является отказом от услуги. Денежные средства при этом списываются в прежнем режиме

В панели инструментов консоли присутствует меню, для выполнения действий, связанных с управлением виртуальной машиной.

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Если Вам необходимо отправить сочетание клавиш в виртуальную машину

Следует кликнуть левой кнопкой мыши по соответствующей кнопке в панели управления, как показано на снимке экрана.

Главное зеркало сайта | SEO оптимизация и продвижение сайта для новичков

Оцените статью
Хостинги