Развертывание образа qcow2

Образы дисков в формате qcow2 популярны не только для использования с гипервизорами виртуальных машин, но и как средство распространения преднастроенных операционных систем. В последнем случае, зачастую, возникает необходимость развернуть образ в формате qcow2 на том тонкого пула LVM, либо на устройство iSCSI, поддерживающее команду unmap. В обоих случаях рационально требовать не записывать на устройство нулевые области, которые в самом образе диска сохранены с использованием разреженного адресного пространства. В противном случае, том тонкого пула окажется заполнен на 100%, а так же будет затрачено дополнительное время на физическую запись данных. К счастью, утилита распаковки формата qcow2 имеет параметры, позволяющие исключить запись нулевых областей: -n — отключает создание и инициализацию целевого тома, --target-is-zero — интерпретирует целевой том, как состоящий из нулей:
qemu-img convert -f qcow2 -O raw -n --target-is-zero image.qcow2 /dev/system/lvm_thin_volume
При работе с существующими томами тонкого пула LVM или устройствами iSCSI такая команда вероятнее всего будет предворяться вызовом blkdiscard, выполняющим операцию trim (она же unmap, она же discard) для данного устройства. В общем случае, формально, не гарантируется, что после выполнения этой команды чтение целевого устройства будет возвращать нули, однако, в частных случаях (особенно при использовании LVM), такое поведение очевидно детерминировано и может быть заранее проверенно.

Fixing console UART on Quartz64 Model B

Recently, I've obtained Quartz64 Model B single board computer (the board revision is 1.4 2022.06.06). It is equipped with so-called RasbperryPi-compatible 40-pin extension header, which provides access to UART console. The board is powered by Rockchip RK3566 Quad-Core ARM Processor and default UART baudrate is 1500000 as it was for RK3328 for instance.

Surprisingly, I had nothing on the console when I powered the board up. Even though HDMI output works fine, and the board was booting successfully. It took some time to realize that something is wrong with the board itself. Then it appeared that other people also suffer from the similar issue: https://forum.pine64.org/showthread.php?tid=17131&pid=115539#pid115539

At some point I attached an oscilloscope to the UART TX pin:

These saw teeth are supposed to be rectangular for not-disturbed signal. So, the hardware origin of the issue became more evident. Unfortunately, Pine64 support didn't help me with this issue, they only adviced to try different OS, different power supply, etc. All of that didn't helped.

The board schematic is not very complicated for UART TX (the same is valid for RX):

The resistors can be probed relatively easily, it appeared that all of them have correct nominals. So, the final decision appeared to replace Q1 (for RX line) and Q2 (for TX line) SOT-323 MOSFETs. There are only two components of SOT-323 size on the board and they can be easily located with the help of components placement:

The MOSFETs have KN on their case and three pins and each located at its own side of the board. The pars are relatively big to be manually resoldered. I used Pine64 Pencil with ILS soldering tip. It seems that high-temperature lead-free soldering was used on the factory, so the temperature close to 400C was required to unsolder the parts. After the parts were replaced with the spares supplied by local electronic distributor, UART console has been working as initially expected.

Использование chrony для синхронизации времени с GPS

Возможность использования систем спутниковой навигации в качестве источника точного времени востребована в настоящее время, во многом благодаря обилию доступных по цене приёмников. Сервер точного времени chrony, развиваемый как легковесная замена ntpd, выбран во многих дистрибутивах в качестве сервера времени по умолчанию, и, конечно, поддерживает такую возможность.

Де-факто стандартом приёмников является, пришедший с водного транспорта, протокол NMEA 0183, зачастую используемый поверх RS232. Для целей синхронизации времени как правило используется отдельная линия с TTL сигналом с частотой 1 Гц. При использовании линий RS232 для передачи TTL сигнала используется DCD (первый пин разъема DB9). На популярных в последнее время одноплатных компьютерах для приема сигнала 1 Гц используется интерфейс GPIO.

На стороне ядра Linux сигнал обрабатывается подсистемой PPS: модулем pps-ldisc в случае DCD, или модулем pps-gpio для GPIO. Пользовательские приложения получают доступ к таблице событий через символьные устройства /dev/ppsX.

Данные, передаваемые по протоколу NMEA, доступны для чтения через соответсвующее устройство: /dev/ttyY. В отличии от ntpd, chrony не содержит код для разбора протокола NMEA, поэтому полагается на gpsd, который, в свою очередь, передает chrony данные о точном времени через unix сокет.

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

  • -n начать приём данных сразу после запуска; по умолчанию, gpsd ждет клиентских подключений для начала работы;
  • -s 9600 указывается скорость обмена для приёмника;
  • /dev/ttyY устройсто с NMEA.

При использовании устройств с именами вида /dev/ttyY gpsd пытается активировать на них линейную дисциплину PPS для получения сигнала с линии DCD. Сигнала, да и самой линии, может не быть, особенно в случаях с одноплатными компьютерами, а сообщить gpsd об этом явно возможности не предусмотрено. Однако, если устройство имеет имя /dev/gpsd0, то gpsd пытается открыть уже готовое устройство /dev/pps0, которое очень удачно может обслуживаться модулем pps-gpio. В последнем случае, придётся пойти на поклон к udev и попросить его делать символическую ссылку для нужного нам tty устройства. Примерное содержимое /etc/udev/rules.d/98-gpsd.rules:

ACTION=="remove", GOTO="gpsd_end"

KERNEL=="ttyS2", SYMLINK+="gpsd0", MODE="0600", OWNER="root", GROUP="root"

LABEL="gpsd_end"

Для chrony следует указать источник точного времени в виде сокета следующим образом. Примерное содержимое /etc/chrony.d/gps.conf:

refclock SOCK /run/chrony.gpsd0.sock refid GPS

Имя сокета для подключения не может быть задано произвольно. Дело в том, что gpsd нельзя указать, куда он должен передавать информацию о времени, вместо этого он самостоятельно начинает запись в сокет с именем /run/chrony.gpsd0.sock если его обнаружит. Следует убедиться, что gpsd запускается после chronyd. Текст gpsd0 после первой точки в имени файла соответсвует имени устройства используемого gpsd для чтения NMEA.

С помощью утилиты chronyc можно проверить, что всё работает корректно.

chronyc> sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS                           0   4   377    21   -721ns[-2140ns] +/- 1333ns
^- 2a00:ab00:203:9::1000:1       2   6   337     2  +9783us[+9783us] +/-   65ms
^- ftpshare1.corbina.net         2   6   377     2  -4050us[-4050us] +/-   39ms
^- tms04.deltatelesystems.ru     2   6   377    63    +11ms[  +11ms] +/-  104ms
^- 2a00:ab00:203:9::1000:6       2   6   177     1    +12ms[  +12ms] +/-   63ms

Возможные значения колнки "S":

  • * — используется в качестве основного источника,
  • + — используется,
  • - — не используется,
  • ? — не используется, идёт сбор информации о стабильности источника.

Изменение размера шард для InfluxDB 1.7

Хранилище сервера баз данных временных рядов InfluxDB 1.x использует шарды фиксированного по времени размера независимо от количества хранящихся в них записей. Шарды не могут быть слиты или разделены. При устаревании данные удаляются отдельными шардами. Использование слишком маленького размера шарда приводит к проблемам с производительностью и избыточному потреблению памяти: на каждый шард требуется хранить в памяти отдельный дескриптор, даже если используется TSI1 индексирование.

Размер шарда является свойством политики хранения (retention policy), и, хотя настройка может быть изменена в онлайне, её изменение не приводит к перебалансировке уже существующих шард. Это приводит к проблемам для баз данных где требуется бесконечный или достаточно длительный срок хранения, т.е. шарды удаляются медленно, так как, несмотря на собственные рекомендации, настройки политики хранения по умолчанию состоят в том чтобы хранить данные бесконечно и разделять на шарды по 1 неделе.

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

В качестве альтернативного решения предлагается следующая оффлайн (при остановленном сервере) процедура: экспорт данных из существующей политики хранения в бинарном виде, удаление политики хранения, создание новой политики хранения (с прежним именем и новыми настройками) и импорт сохраненных данных. Для процедуры используется модифицированная (добавлена команда droprp) утилита influx_tools:

git clone -b influx_tools/droprp https://github.com/matwey/influxdb.git
cd influxdb/cmd/influx_tool
go build .

Экспорт данных производится следующим образом:

./influx_tools export -config /etc/influxdb/config.toml -no-conflict-path -database ${DB_NAME} -rp ${RP_NAME} -duration 8736h -format binary | xz -3 -c - > /tmp/ifx_dump

здесь 8736h — новый размер шарда, в данном случае 52 недели. Сжатие можно опустить, но оно весьма эффективно работает в данном месте.

Удалим политику хранения ${RP_NAME}:

./influx_tools droprp -config /etc/influxdb/config.toml -database ${DB_NAME} -rp ${RP_NAME}

В этот момент будут удалены файлы старых шард, удалены файлы журналов упреждающей записи, и модифицирован файл meta/meta.db, который представляет из себя сериализованный документ в формате ProtoBuf, хранящий список политик хранения и шард.

Загрузим данные на прежнее место с новыми настройками политики хранения:

xzcat /tmp/ifx_dump | ./influx_tools import -config /etc/influxdb/config.toml -database ${DB_NAME} -rp ${RP_NAME} -replace -shard-duration 8736h

Пересобирем индекс для новых шард:

influx_inspect buildtsi -datadir /var/lib/influxdb/data/ -waldir /var/lib/influxdb/wal -v

Восстановим права доступа:

chown -R influxdb:influxdb /var/lib/influxdb/*

Миграция InfluxDB 0.9 до InfluxDB 1.1

Между 0.9 и 1.1 нет прямой совместимости, поэтому прежде всего понадобится какая-нибудь промежуточная версия на короткий промежуток времени:
# wget https://dl.influxdata.com/influxdb/releases/influxdb-0.11.1-1_linux_amd64.tar.gz

Сначала рекомендуется сбросить WAL (write-ahead log), для этого рекомендуется изолировать сервер InfluxDB от записи и выполнить его restart.
Далее, останавливаем InfluxDB 0.9 и с помощью утилиты influx_tsm из пакета InfluxDB версии 1.1 конвертируем директорию data.
Предполагается, что резервную копию данных мы уже сделали внешним образом.
# influx_tsm -parallel -nobackup /var/lib/influxdb/data

Утилита выводит список всех найденных файлов устаревшего формата b1 или bz1 и спрашивает Proceed? y/N:
После подтверждения данные преобразуются в новый формат tsm.

Далее осталось преобразовать в новый формат /var/lib/influxdb/meta. Для этого на некоторое время придется запустить InfluxDB версии 0.11
# ./influxdb-0.11.1-1/usr/bin/influxd -config /etc/influxdb/config.toml

И попросить его сделать резервную копию:
# influxd backup /tmp/backup/
2016/11/27 17:41:37 backing up metastore to /tmp/backup/meta.00
2016/11/27 17:41:37 backup complete

После этого сервер 0.11 можно выключить и загрузить резервную копию назад, но уже используя InfluxDB версии 1.1:
# influxd restore -metadir=/var/lib/influxdb/meta/ /tmp/backup/
Using metastore snapshot: /tmp/backup/meta.00

После этого восстановим права доступа
# chown -R influxdb:influxdb /var/lib/influxdb/

И можно запускать сервер InfluxDB 1.1
# systemctl start influxd

Открываем консоль influx и проверяем что все наши данные доступны.

Настройка звука в конфигурации с несколькими одинаковыми звуковыми картами

Имеется следующая конфигурация. Два звуковых устройства, оба управляются одним и тем же модулем snd-hda-intel. Первое устройство отвечает за звуковой канал в HDMI, встроенной в процессор графической системы. Второй устройство — обычный интегрированный на материнскую плату аудио-контроллер.
00:03.0 Audio device [0403]: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller [8086:0c0c] (rev 06)
00:1b.0 Audio device [0403]: Intel Corporation 9 Series Chipset Family HD Audio Controller [8086:8ca0]
Пользователи жалуются, что звук не работает. Проблема состоит в том, что YaST создаёт следующую конфигурацию в 50-sound.conf:
options snd slots=snd-hda-intel,snd-hda-intel
alias snd-card-0 snd-hda-intel
alias snd-card-1 snd-hda-intel
Здесь snd-card-0 — звуковое устройство "по умолчанию". Очевидно, что в таком подходе ситуация, когда один и тот же модуль отвечает за два устройства, обрабатывается не корректно. Кто из устройств первый попал в функцию azx_probe модуля, тот и станет snd-card-0. В нашем случае, это не то устройство, которое нам хотелось бы. Это можно проверить, сделав
ls -l /sys/class/sound/card0/device
lrwxrwxrwx 1 root root 0 окт  9 21:36 /sys/class/sound/card0/device -> ../../../0000:00:03.0

Для восстановления правильного порядка предлагается делать следующее.
Во-первых, внимательно изучив исходники модуля, добавляем в 50-sound.conf:
options snd-hda-intel index=1,0
Во-вторых, надеемся, что при следующих загрузках порядок инициализации не будет меняться случайным образом, потому-что кто первый попадет в функцию azx_probe, тот теперь и будет card1. И это всё происходит в 2015 году, когда повсюду systemd и прочий udev, а звуковую карту за её DeviceId привязать нельзя.

Настройка вложенной виртуализации в ESXi 6.0

Иногда в гостевой системе требуется в свою очередь запускать виртуальные машины. В нашем случае, гипервизор VMWare ESXi 6.0 (он же известен под названием vSphere Hypervisor) используется для запуска различных операционных систем, сервисы в одной из которых, в свою очередь, динамически запускают qemu-kvm. Для того, чтобы kvm в гостевой системе работал, необходимо включить вложенную (nested) виртуализацию. Делается это следующим замысловатым образом.

Во-первых, в vmx-файл настроенной гостевой системы дописывается директива vhv.enable = "TRUE". Включить эту настройку из клиентского приложения, видимо, нельзя. Для редактирования файла можно сначала загрузить его на локальную машину, а затем отредактированную версию загрузить назад, используя браузер датастора гипервизора.
Во-вторых, нужно попросить гипервизор перечитать vmx-файл, как описано в тикете 1026043 базы знаний VMWare. А именно, используя ssh для доступа к командной строке гипервизора выполнить команды:
# vim-cmd vmsvc/getallvms
# vim-cmd vmsvc/reload Vmid
Первая команда просто отображает список всех виртуальных машин гипервизора, она нужна чтобы определить Vmid интересующей нас машины, это число используется во второй команде.

После этого стартуем виртуальную машину и проверяем, что аппаратная виртуализация стала доступна нам в гостевой системе:
# cat /proc/cpuinfo | grep vmx
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq vmx ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm ida arat epb dtherm tpr_shadow vnmi ept vpid
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq vmx ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm ida arat epb dtherm tpr_shadow vnmi ept vpid
# lsmod | grep kvm
kvm_intel             151704  3 
kvm                   493230  1 kvm_intel

Удаленная сетевая консоль ядра Linux

Иногда, когда ядро Linux испытывает проблемы, одними из способов сбора отладочной информации являются консоль последовательного порта или сетевая консоль. Сразу обратим внимание, что второй вариант имеет как недостатки, например, предполагает, что сетевая подсистема ядра остается функциональной во время возникновения проблем, так и преимущества, например, можно сконфигурировать удаленно.

Полное описание сетевой консоли находится в документации ядра. Для настройки достаточно добавить в modprobe.d/99-local.conf:
options netconsole netconsole=@/,514@192.168.10.7/00:0C:29:F3:92:97
Здесь, 514 - номер UDP порта, 192.168.10.7 - IP удаленного хоста куда будет отсылаться информация, 00:0C:29:F3:92:97 - его MAC адрес, если его не указать явно то будет использоваться широковещательный адрес FF:FF:FF:FF:FF:FF, что может затруднить передачу информации в зависимости от настроек сетевого оборудования.
И загрузить модуль netconsole или, по желанию, поставить его на автозагрузку при старте системы.

После загрузки модуля netconsole, сетевая консоль начинает немедленно функционировать, а в системном журнале можно увидеть примерно следующее:
May  1 18:57:51 192.168.10.4 kernel: [162255.522603] netconsole: local port 6665
May  1 18:57:51 192.168.10.4 kernel: [162255.522673] netconsole: local IP 0.0.0.0
May  1 18:57:51 192.168.10.4 kernel: [162255.522710] netconsole: interface eth0
May  1 18:57:51 192.168.10.4 kernel: [162255.522746] netconsole: remote port 514
May  1 18:57:51 192.168.10.4 kernel: [162255.522784] netconsole: remote IP 192.168.10.7
May  1 18:57:51 192.168.10.4 kernel: [162255.522826] netconsole: remote ethernet address 00:0c:29:f3:92:97
May  1 18:57:51 192.168.10.4 kernel: [162255.522881] netconsole: local IP 192.168.10.4
May  1 18:57:51 192.168.10.4 kernel: [162255.523032] console [netcon0] enabled
May  1 18:57:51 192.168.10.4 kernel: [162255.523349] netconsole: network logging started

Данные приходят в самом простом текстовом виде и их можно читать самым простым способом:
netcat -u -l 514
Если у нас в наличии есть syslog-ng — можно использовать его следующим образом:
source s_remote_udp {
        network(transport("udp") ip(0.0.0.0) port(514));
};
filter f_remote_remhost {
        netmask(192.168.10.4);
};
destination d_remote_remhost {
        file("/var/log/remote/remhost.log");
};
log {
        source(s_remote_udp);
        filter(f_remote_remhost);
        destination(d_remote_remhost);
};

Проверить, что всё работает можно следующим образом:
echo '<7>Hello world!' > /dev/kmsg
dmesg -n 8
Сообщение должно появиться в журнале и быть передано по сети на удаленный хост.

Удаленная отладка ядра Linux

Ядро Linux периодически ломается, иногда это происходит на стадии загрузки. Одним из методов исследования проблемы является удаленная отладка с использованием последовательного порта.

Опции конфигурации ядра должны быть такими:
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
Кроме того, драйвер последовательного порта должен быть включен в состояние Y.

Далее нам понадобятся отладочные символы и исходные коды ядра, которые находятся в пакетах -debuginfo и -debugsource. Скорее всего, архитектуры удаленной и локальной системы не будут совпадать, так как особенно часто ядро Linux не работает на архитектуре armv7l, поэтому просто распакуем данные следующим образом:
> rpm2cpio kernel-default-base-debuginfo-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
> rpm2cpio kernel-default-debuginfo-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
> rpm2cpio kernel-default-debugsource-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
В текущей директории будет создана поддиректория /usr содержащая отладочные символы и исходные коды в стандартной иерархии. Кроме того, нам понадобятся сами бинарные файлы ядра:
> rpm2cpio kernel-default-base-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
> rpm2cpio kernel-default-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id

Далее, следует подключить последовательный порт, и открыть удаленную консоль следующим, например, образом:
> screen /dev/ttyUSB0 115200
и начать загрузку целевого устройства. Для активации механизма kgdb потребуется добавить параметры командной строки ядра в загрузчике:
U-Boot# setenv append "kgdboc=ttyO0,115200 kgdbwait"
U-Boot# boot

Если все пойдет правильно, то загрузка ядра остановится после примерно следующих строк:
[    3.753423] 44e09000.serial: ttyO0 at MMIO 0x44e09000 (irq = 154, base_baud = 3000000) is a OMAP UART0
[    4.497783] console [ttyO0] enabled
[    4.502387] STMicroelectronics ASC driver initialized
[    4.507960] KGDB: Registered I/O driver kgdboc
[    4.512673] KGDB: Waiting for connection from remote gdb...

Entering kdb (current=0xdb0b3480, pid 1) on processor 0 due to Keyboard Entry
[0]kdb> 
kdb ождает ввода команд, среди прочего доступна команда help, выводящая список базовых команд. На этом консоль можно закрыть: Ctrl-A :quit и открыть отладчик gdb.

Для начала установим пути к отладочным символам и исходным кодам и загрузим объектный файл ядра целевой системы (внимание, сначала этот файл нужно будет распаковать командой gz).
(gdb) set debug-file-directory /tmp/dbg/usr/lib/debug
(gdb) directory /tmp/dbg/usr/src/debug/kernel-default-4.2.rc4/linux-4.2-rc4/linux-obj
(gdb) file /tmp/dbg/boot/vmlinux-4.2.0-rc4-1.gaf243bc-default
Reading symbols from /tmp/dbg/boot/vmlinux-4.2.0-rc4-1.gaf243bc-default...Reading symbols from /tmp/dbg/usr/lib/debug/boot/vmlinux-4.2.0-rc4-1.gaf243bc-default.debug...done.
done.
После этого нужно подключиться к целевой системе:
(gdb) target remote /dev/ttyUSB0
Remote debugging using /dev/ttyUSB0
0xc031dc08 in arch_kgdb_breakpoint () at ../arch/arm/include/asm/outercache.h:142

Далее можно использовать отладчик как обычно. Через команду monitor доступны все команды из консоли kdb, среди них есть достаточно полезные, например dmesg или lsmod:
(gdb) monitor lsmod
Module                  Size  modstruct     Used by
musb_am335x             1431  0xbf000278    1  (Loading) 0xbf000000 [ ]
Обратите внимание, что команда lsmod любезно нам показывает адрес 0xbf000000, куда в памяти загружен модуль musb_am335x. Этот адрес нужен чтобы отлаживать код из модуля:
(gdb) add-symbol-file /tmp/dbg/lib/modules/4.2.0-rc4-1.gaf243bc-default/kernel/drivers/usb/musb/musb_am335x.ko 0xbf000000

Устойчивые имена сетевых интерфейсов

Разработчики systemd продолжают вести нас в светлое будущее. В udev уже давно реализован механизм Predictable Network Interface Names, который представляет из себя кусочек кода на C, заполняющий переменные ID_NET_NAME_* исходя из свойств расположения физического сетевого устройства.

Считается, что подобный подход дает больше информации, чем прибитие гвоздями имен интерфейсов eth? к MAC-адресам в 70-persistent-net.rules. Однако, не обходится без недостатков. Например, при запуске системы под гипервизором VMWare ESXi, единственный сетевой интерфейс у меня называется eno16777728. Устройства, определяемые в DTB для одноплатных компьютеров на базе ARM, не поддерживаются схемой именования и имеют обычные имена eth?. А при подключении USB устройств, типа мобильных телефонов или модемов, схема именования генерирует скорее неустойчивые имена, потому-что в имя входит расположение устройства на шине USB, которое изменится при следующем подключении, таким образом придется настраивать интерфейс заново, потому-что предыдущие сохраненные настройки будут относиться к интерфейсу с другим именем.

К счастью, udev заполняет переменную ID_NET_NAME_MAC, представляющую имя интерфейса, основанное исключительно на его MAC-адресе. По-умолчанию, эта переменная не используется, но можно поменять стандартное поведение для USB-устройств. Один способ - через настройку udev, второй - используя systemd.link, файл, используемый systemd, для конфигурации сетевых интерфейсов.

Создадим файл /etc/systemd/network/90-usb.link следуя инструкции:
[Match]
Path=*-usb-*
[Link]
NamePolicy=mac
Юнит-файл состоит из двух секций: [Match] для описания устройств к которым он относится и [Link] для описания того, что с ними делать. В примере выше мы просим systemd использовать политику именования основанную на MAC-адресах для всех устройств подключенных через USB. После выполнения systemctl daemon-reload можно подключить устройство и увидеть его интерфейс с именем enx112233445566. Достаточно длинное, но уникальное (в известных пределах) и не изменится при следующем подключении устройства.

Кроме изменения имени через systemd.link можно настроить WOL, MTU, ограничить скорость на интерфейсе, назначить устройству другой MAC-адрес.

Изменение размера раздела

Имеется диск с тремя разделами sda1 (/boot), sda2 (swap), sda3 (/). Необходимо увеличить размер раздела /boot за счет swap.

Сначала отмонтируем все разделы и проверим файловую систему.
# swapoff  /dev/sda2 
# umount /dev/sda1 
# e2fsck /dev/sda1 
e2fsck 1.42.6 (21-Sep-2012)
/dev/sda1: clean, 49/14056 files, 47157/56196 blocks

Используем parted для того, чтобы сначала уменьшить и передвинуть второй раздел, а затем расширить первый на освободившееся место. Так как второй раздел - swap, то его мы просто передвинем, не заботясь о содержимом. Иначе говоря, сначала мы совсем сломаем, а потом заново её разметим.

# parted /dev/sda
GNU Parted 2.4
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit s                                                           
(parted) print                                                            
Model: ATA QEMU HARDDISK (scsi)
Disk /dev/sda: 120103200s
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start     End         Size        Type     File system     Flags
 1      63s       112454s     112392s     primary  ext2            boot, type=83
 2      112455s   1686824s    1574370s    primary  linux-swap(v1)  type=82
 3      1686825s  120101939s  118415115s  primary  reiserfs        type=83

Для изменения раздела используется команда resize номер_раздела начало конец

(parted) resize 2 224973 1686824
WARNING: you are attempting to use parted to operate on (resize) a file system.
parted's file system manipulation code is not as robust as what you'll find in
dedicated, file-system-specific packages like e2fsprogs.  We recommend
you use parted only to manipulate partition tables, whenever possible.
Support for performing most operations on most types of file systems
will be removed in an upcoming release.
(parted) print
Model: ATA QEMU HARDDISK (scsi)
Disk /dev/sda: 120103200s
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start     End         Size        Type     File system     Flags
 1      63s       112454s     112392s     primary  ext2            boot, type=83
 2      224973s   1686824s    1461852s    primary  linux-swap(v1)  type=82
 3      1686825s  120101939s  118415115s  primary  reiserfs        type=83

К сожалению в этот момент оно само подмонтировало всё назад, поэтому нужно снова отмонтировать первый раздел. Раздел swap в данный момент уже должен быть работоспособен, потому-что mkswap на нем выполнился сам автоматически. К сожалению, я не нашел способа отключить всю эту самодеятельность.

# umount /dev/sda1
# e2fsck -p /dev/sda1

Снова идем в parted:

# parted
GNU Parted 2.4
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit s                                                           
(parted) print                                                            
Model: ATA QEMU HARDDISK (scsi)
Disk /dev/sda: 120103200s
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start     End         Size        Type     File system     Flags
 1      63s       112454s     112392s     primary  ext2            boot, type=83
 2      224973s   1686824s    1461852s    primary  linux-swap(v1)  type=82
 3      1686825s  120101939s  118415115s  primary  reiserfs        type=83

(parted) resize 1 63 224972
WARNING: you are attempting to use parted to operate on (resize) a file system.
parted's file system manipulation code is not as robust as what you'll find in
dedicated, file-system-specific packages like e2fsprogs.  We recommend
you use parted only to manipulate partition tables, whenever possible.
Support for performing most operations on most types of file systems
will be removed in an upcoming release.
(parted) quit                                                             
Warning: You should reinstall your boot loader before rebooting.  Read section 4 of the Parted User documentation for more
information.
Information: You may need to update /etc/fstab.   

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

snapper: настройка снимков подтомов

Показать список подтомов можно командой btrfs subvolume list /. Выберем какой-нибудь, например /var/lib/pgsql.
Создадим новую конфигурацию (профиль) для этого подтома: snapper -c pgsql create-config /var/lib/pgsql, здесь pgsql произвольное имя:
# snapper list-configs
Config | Subvolume     
-------+---------------
root   | /             
pgsql  | /var/lib/pgsql

Далее, все команды нужно выполнять с ключом -c pgsql, чтобы оперировать нужным профилем.

# snapper -c pgsql get-config
...      
NUMBER_CLEANUP         | yes           
NUMBER_LIMIT           | 50            
NUMBER_LIMIT_IMPORTANT | 10            
NUMBER_MIN_AGE         | 1800          

Здесь NUMBER_CLEANUP разрешает удалять старые снимки если их число превышает NUMBER_LIMIT и одновременно возраст (в секундах) больше NUMBER_MIN_AGE.

TIMELINE_CLEANUP       | yes           
TIMELINE_CREATE        | yes           
TIMELINE_LIMIT_DAILY   | 10            
TIMELINE_LIMIT_HOURLY  | 10            
TIMELINE_LIMIT_MONTHLY | 10            
TIMELINE_LIMIT_YEARLY  | 10            
TIMELINE_MIN_AGE       | 1800

Здесь соответствующая настройка разрешает автоматическое создание снимков раз в час. Команда TIMELINE_CLEANUP удаляет старые снимки, используя следующие правила: удаляется снимок только если он старше TIMELINE_MIN_AGE секунд и одновременно после удаления останутся TIMELINE_LIMIT_* снимков с соответствующими интервалами.
Таким образом, в вышеописанном стандартном случае всегда будут доступны снимки: 10 с интервалом в час с текущего момента, 10 с интервалом в один день с текущего момента, 10 с интервалом в один месяц и так далее.

Конвертация CVS в Mercurial

В системе контроля версий CVS есть так называемые модули с амперсандом, представляющие собой поддиректорию общую для нескольких модулей. Концепция похожая на сабмодули в git или сабрепозитории в mercurial.

Поскольку CVS немного устарел, нужно куда-то переехать. К сожалению, правильную работу с моделями с амперсандом не поддерживает ни одна из найденных утилит миграции. Об инкрементальной миграции (когда существуют два параллельных репозитория (разных систем контроля), которые каким-то чудом остаются друг с другом синхронизированы) тоже придется забыть.

Краткая схема действий. Сначала все модули из CVS конвертируются в формат fastimport, далее полученные дампы преобразуются и конвертируются в mercurial. Mercurial имеет в данной ситуации преимущество над git в том, что сабрепозитории управляются просто служебными файлами в дереве репозитория.

Все CVS модули можно разделить на две категории: те, которые содержат в себе модули с амперсандом, и те, которые нет (сами являются ими). Второй набор конвертируется просто. Для преобразования первого набора нужно пойти в cvsroot и вставить символические ссылки в те места, где должны были быть директории, соответствующие модулям с амперсандом. После преобразования каждый модуль из первого набора потеряет связь со своими вложенными модулями, и файлы с путями, соответствующими им, окажутся преобразованы несколько раз — один раз в репозитории относящимся к вложенному модулю и по разу в каждом репозитории модуля первого типа. Перед импортом в mercurial данная связь будет восстановлена.

Использование cvs2git из пакета cvs2svn не требует особой внимательности, кроме параметра COMMIT_THRESHOLD который склеивает коммиты. Дело в том, что в CVS каждый файл имеет свою историю, а в формате fast-import (как в git и mercurial) историю имеет весь репозиторий, поэтому отдельные изменения файлов надо слепить в прообразы будущих коммитов. По-умолчанию COMMIT_THRESHOLD равен 5 минутам, это значит, что изменения всех файлов попадающих в пятиминутное окно будут слеплены в один коммит.
Кроме того, можно задать отображение тегов, отображение авторов и другие параметры.

Для преобразования из формата fastimport в репозиторий mercurial используется расширение hg-fastimport. Отметим, что изначальный автор забросил этот проект и считает его неудачным, а более правильным подходом к преобразованию называет другой свой проект. Видимо поэтому расширение очень странным образом обрабатывает TAG.FIXUP ветви (в CVS можно было накладывать теги на те ревизии файлов, которые во времени друг с другом вообще никогда не встречались, поэтому для отображения таких тегов создается отдельная специальная ветка), что обычно требует подправления кода.

Формат fastimport представляет из себя файл (или несколько), задающий дерево репозитория в топологическом порядке. Каждый узел дерева, который затем станет коммитом, помечается уникальным текстовым идентификатором, например ":1000000003". После преобразования модулей второго типа в соответствующих новых репозиториях будет лежать файл .hg/shamap, с отображением коммитов mercurial в идентификаторы fastimport. Кроме того, каждый узел дерева в текстовом виде содержит список измененных файлов, например
M 100644 :30 sub/Makefile
здесь :30 — маркер блоба, т.е. фактически содержания файла. Используя путь файла можно идентифицировать все файлы занесенные к нам из вложенных модулей. Нам бы хотелось преобразовать fastimport дамп таким образом чтобы в этих местах возникли ссылки на внешние репозитории, например так
M 160000 2d1eb0523f244f7bb1d58f016583a25ba3d40426 sub

Для этого предлагается следующих алгоритм. У нас есть два дерева в виде дампов fastimport: дерево вложенного репозитория и дерево основного. Кроме того, есть отображение маркеров узлов вложенного репозитория на хэш коммита. Обойдя каждое из деревьев для каждого узла, мы можем полностью восстановить состояние, т.е. набор всех существовавших файлов и их содержимое. Кроме того, для основного репозитория возможно определить состояние вложенной директории (будущего сабрепозитория). На рисунке схематично изображены узлы основного дерева (пронумерованы арабскими цифрами) и узлы дерева сабрепозитория (пронумерованы латинскими буквами). Черными стрелками показана очередность коммитов, стрелка идет от более нового коммита к его предку.
Далее, сравнивая состояния вложенного репозитория и соответствующие под-состояния основного репозитория, можно построить отображение узлов основного дерева на вложенное (красные стрелки на рисунке).

Возможны ситуации когда связь многозначная. Вообразим, что в предложенном примере G откатывает F, поэтому имеет такое же содержимое что и E, кроме того, в другой ветке есть C с таким же содержимым. Сообщения коммитов могут отсутствовать, время коммитов может отличаеться. В данной ситуации предлагаются следующие критерии разрешения конфликта.

Так как основное дерево обходится в топологическом порядке, то к моменту когда мы оказывается в узле 5 узел 4 уже обработан и мы знаем что ему соответствует узел D. Для всех возможных кандидатов C, E, G рассчитаем расстояние между ними и узлом D. Узел D не достижим из C, поэтому C отбрасывается. Оставшийся выбор производится на основании сообщения коммита и близости времени. Либо можно представить простой алгоритм, который за не полиномиальное время назначит соответствие, однако без информации о времени и сообщениях коммитов все-равно не обойтись.

Таким образом, у нас есть отображение меток дерева основного репозитория на метки (или хэши) вложенного репозитория. Этой информации достаточно, чтобы заменить все нужные вхождения об изменениях файлов в дампе. После этого, дамп можно скормить в hg-fastimport.

Наиболее удобным способом расположения иерархии репозиториев на сервере оказался следующий. Каждый вложенный репозиторий кладется в корень иерархии, кроме того, в каждый проект. Причем этим вторичным клонам мы запретим запись. А на первичный репозиторий навесим хуки, которые будут дергать pull во всех клонах.
[extensions]
hgext.acl=

[hooks]
pretxnchangegroup.acl = python:hgext.acl.hook

[acl]
sources = serve push bundle

[acl.deny]
** = *

[paths]
default = /repos/subrepo

OBS: локальная сборка под ARM

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

osc build --clean --alternative-project openSUSE:Factory:ARM qemu armv7l name.spec

Здесь указывается, что используется альтернативный проект для сборки — openSUSE:Factory:ARM (версию подставить по желанию), используется репозиторий qemu, который есть в этом проекте. Поэтому и указывается этот альтернативный проект.

Несмотря на то, что в данном примере указана архитектура armv7l, технически, это x86_64. В среду сборки будет установлен бинарный транслятор qemu, работающий через подсистему ядра binfmt. При инициализации ядро настраивается таким образом, что при виде сигнатуры ELF для архитектуры ARM вызывает бинарик как qemu-arm /usr/bin/..., подобно тому, как при виде символов "#!" в начале исполняемого файла вызывается указанный интерпретатор. Работает поэтому достаточно медленно.

К сожалению, с пакетами kiwi такое не проходит.

Сетевой стек на ATSAMD20

В предыдущих выпусках рассматривалась демонстрационная плата на базе 32-битного микроконтроллера ATSAMD20. Далее рассмотрим как прикрутить к нему сетевое приложение. Так как сам микроконтроллер не снабжен интерфейсом Ethernet, возьмем какое-нибудь готовое решение на базе ENC28J60 и прикрутим его через SPI.

Нам понадобится:
  • Atmel Software Framework — распространяемая под странным образом модифицированной BSD лицензией библиотека, реализующая удобный уровень индирекции при работе с переферией микроконтроллеров Atmel. Мы ей воспользуемся для работы через SPI. Внутри библиотеки весьма красивый код, понятный API и гора документации, исполненной в doxygen. Поэтому, основываясь на чувстве прекрасного, будем её использовать.
  • ec28j60driver — драйвер для ENC28J60, реализует высокоуровневые функции работы с Ethernet путем обмена через SPI. Возьмем этот, потому-что написан он не левой пяткой и был достаточно легко портирован для работы с Atmel Software Framework. (см. ветку asf)
  • lwIP — легковесный стек TCP/IP. Он отсылает или принимает Ethernet-пакеты через драйвер устройства и дальше разбирается что-же там внутри пришло. На сайте присутствует куча примеров.

Настройки для lwIP следующие:

lwoptions.h:
#define MEM_LIBC_MALLOC 1
#define MEMP_MEM_MALLOC 1
#define MEM_ALIGNMENT 4

cc.h:
#define BYTE_ORDER  LITTLE_ENDIAN

Стиль программирования приложений, определяемый использованием RAW API библиотеки lwIP, через 5 минут создает полное ощущение, что ты пишешь gen_server на erlang, но последний почему-то кривой, неудобный и недоделанный.

Далее в таблице приводится размер кода прошивки, получаемый при различных вариантах конфигурации:
config -O3 -Os
TCP/IP + DHCP + DEBUG(printf) 96k 82k
TCP/IP + DHCP 54k 40k
TCP/IP 45k 36k
UDP/IP + SNMP 54k 43k
UDP/IP 28k 24k

Как-то так оно и работает.

openSUSE 13.1 на BeagleBone Black

BeagleBone Black — одноплатный компьютер на основе процессора TI AM3358 (Cortex-A8), выпущенный весной прошлого года:

На нем вполне успешно может загрузиться и даже работать openSUSE 13.1. Готовые образы для нанесения на microSD карточку находятся здесь. Эти же самые образы должны в теории работать и на BeagleBone. Конечно, пока все на этапе интеграции и поиска ошибок, поэтому имеется подробная инструкция по запуску:
  1. Скачать, распаковать и сделать dd на карточку образ системы *.raw.xz
  2. Подключить отладочный TTL-RS232 порт (можно использовать, например, такой, но важно помнить, что разработчики BeagleBone Black не поставили на свою плату преобразователь уровней и сигнал с отладочного RS232 идет в виде 3.3V. Подключение через обычный COM-порт на большом компьютере обречено на провал.), руководствуясь распиновкой. Используя screen /dev/ttyUSB0 115200, во-первых, можно будет легко видеть все этапы начиная от работы u-boot. Во-вторых, запустится Yast2 firstboot и попросит вас задать root пароль, завести пользователя, установить временную зону и системное время (аналогично тому, как это происходит на соответствующем этапе установки с DVD), а для этого потребуется интерактивное взаимодействие.
  3. Помните, что для загрузки с внешней карты памяти при подаче питания на устройство нужно удерживать кнопку S2 (она же boot select switch). Подсказка — загрузившись с SD карты можно подмонтировать раздел встроенной MMC памяти и переименовать или удалить файл загрузчика MLO, после этого загрузка будет всегда начинаться с SD, но загрузиться с MMC больше не получится.

Технические подробности (тем, кто хочет продолжить ковыряния) изложены в списке рассылки: http://lists.opensuse.org/opensuse-arm/2014-01/msg00001.html.

Atmel ATSAMD20-XPRO: собираем компилятор

Поскольку сборка компилятора привела к боли и страданиям, она будет тут сохранена для истории (такими историями гугл полнится).

Возьмем последний binutils-2.24:
./configure  --target=arm-none-eabi -enable-interwork   --enable-multilib --disable-nls  --disable-libssp --prefix=/opt/arm-none-eabi
make
make install-strip
export PATH=$PATH:/opt/arm-none-eabi/bin

Возьмем newlib-2.0.0 и распакуем его, пусть проветривается.

Возьмем gcc-4.8.2 который слышал о cortex-m0plus. Возьмем дебиановские патчи отсюда. Наложим их и скомпилируем:
mkdir build
../configure  --target=arm-none-eabi --prefix=/opt/arm-none-eabi --enable-languages="c,c++" --enable-interwork --enable-multilib  --with-
newlib --with-headers=/path/to/src/newlib-2.0.0/newlib/libc/include/  --disable-nls --disable-libssp  --with-system-zlib --with-multilib-lis
t=armv6-m
# в этом месте ./configure может ругаться, надо проследить чтобы он заголовки смог переписать на место
make
make all-gcc
make install-gcc

newlib собирается со следующими ключами (без --disable-newlib-supplied-syscalls не собираются некоторые куски для armv6-m, и atmel-овский asf ругается на дублирующиеся определения функций из syscalls):
./configure --target=arm-none-eabi -enable-interwork --enable-multilib --disable-libssp --disable-nls --prefix=/opt/arm-none-eabi --disable-newlib-supplied-syscalls  --enable-newlib-register-fini --enable-newlib-io-long-long
make
make install

После доделываем gcc:
cd build
make all
make install

Atmel ATSAMD20-XPRO


ATSAMD20-XPRO оценочный набор для новой серии микроконтроллеров Atmel ATSAMD20 на ядре Cortex-M0+. Выглядит следующим образом:
Купить в России можно например тут: Дельта Электроника.

Этот пост о том как подключать эту плату в GNU/Linux. Плата снабжена интерфейсом micro-USB для отладки, реализуемым через отдельную микросхему. Atmel называет это «Embedded Debugger», анонсируется наличие виртуального последовательного интерфейса (прикрученного к основному чипу) и собственно средств отладки и программирования.

При подключении появляется устройство:
Bus 001 Device 010: ID 03eb:2111 Atmel Corp.

[13761.329235] usb 1-1.5: New USB device found, idVendor=03eb, idProduct=2111
[13761.329240] usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[13761.329242] usb 1-1.5: Product: EDBG CMSIS-DAP
[13761.329245] usb 1-1.5: Manufacturer: Atmel Corp.
[13761.329247] usb 1-1.5: SerialNumber: ATML1873040200000110
[13761.330868] hid-generic 0003:03EB:2111.000A: hiddev0,hidraw3: USB HID v1.11 Device [Atmel Corp. EDBG CMSIS-DAP] on usb-0000:00:1a.0-1.5/input0
[13761.330964] cdc_acm 1-1.5:1.1: ttyACM0: USB ACM device

Устройство, как видно, отдает нам виртуальный последовательный интерфейс на /dev/ttyACM? и интерфейс CMSIS-DAP на /dev/hid*.

В openocd недавно добавили поддержку этого интерфейса. Пока пакеты openocd с поддержкой CMSIS-DAP доступны здесь:

В пакетах есть небольшой баг, связанный с тем, что udev стремится поставить на /dev/hidraw* группу владельца plugdev, которая по-умолчанию в системе не существует и в пакете не создается. openocd будет искать свой devel-project и потом попадет в Factory.

Запускаем и убеждается, что таки оно работает:
> openocd -f /usr/share/openocd/scripts/board/atmel_samd20_xplained_pro.cfg 
Open On-Chip Debugger 0.8.0-dev-snapshot (2013-12-13-18:45)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'cmsis-dap'
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: Interface Initialised (SWD)
adapter speed: 500 kHz
adapter_nsrst_delay: 100
cortex_m reset_config sysresetreq
Info : CMSIS-DAP: FW Version = 01.0F.00DB
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : DAP_SWJ Sequence (reset: 50+ '1' followed by 0)
Info : CMSIS-DAP: Interface ready
Info : clock speed 500 kHz
Info : IDCODE 0x0bc11477
Info : at91samd20j18.cpu: hardware has 4 breakpoints, 2 watchpoints

Быстродействие UNIX сокетов

Сравнение скорости работы unix-сокетов. Выполнялась передача большого объема данных от одного процесса другому через unix-сокет. Изменялся размер данных, передаваемых за один вызов write/read (chunk). С каждым размером производилось пять измерений, результат усреднялся.


На графике черная кривая — производительность unix-сокетов, красная и зеленая — для сравнения копирование памяти memcpy в рамках одного процесса и, соответственно, копирование из разделяемой (shared) памяти. Если рост производительности при увеличении "размера пакета" для сокетов не является чем-то не очевидным, то падение производительности операции memcpy при росте значения третьего аргумента функции не тривиально.

Характеристики тестового стенда. Процессор: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz, память: DDR3 Kingston HyperX KHX1600C9D3P1K2/8G. Ядро: 3.7.10.

Xen: проброс USB устройств

Xen умеет пробрасывать USB-устройства (по отдельности) в гостевые непривилегированные домены. Для этого используется механизм, называемый PVUSB (подозреваю, что сокращение от Para-Virtualized USB), концептуально состояний из модулей usbbk (Xen USB backend driver) и xen_hcd (Xen USB Virtual Host Controller driver). Соответственно, первый модуль съедает устройство в dom0, делая его недоступным для других драйверов, а все URB отправляет через гипервизор в нужный выбранный домен, где их получает перавиртуальный контроллер. Утверждается, что потеря производительности минимальна.

Вся конструкция управляется несколькими командами. Посмотреть, какие устройства доступны:
# xm usb-list-assignable-devices
4-2          : ID 067b:2303 Prolific Technology Inc. USB-Serial Controller
Создать в домене паравиртуальный USB хост контроллер: xm usb-hc-create Domain UsbVer PortNum, где параметры — название домена, версия USB (поддерживаются 1 и 2) и количество USB-портов. После этого, в гостевом домене с помощью lsusb видно появившийся контроллер. Для удаления есть обратная команда xm usb-hc-destroy

Для присваивания устройства есть команда xm usb-attach Domain HostNum PortNum Device, где параметры — название домена, номер хост контроллера (их можно хоть пачку создать), номер порта на виртуальном контроллере, первая колонка выдачи usb-list-assignable-devices. Обратная команда — xm usb-destroy. При этом, в dom0 устройство пропадет на глазах у изумленного драйвера:
[12129.803899] pl2303 ttyUSB0: pl2303 converter now disconnected from ttyUSB0
[12129.803938] pl2303 4-2:1.0: device disconnected
но появится в гостевом домене:
# lsusb
Bus 001 Device 002: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Важное замечание. Если в гостевом домене ничего не появилось, кроме записей в dmesg:
[12332.892117] usb 1-1: new full-speed USB device number 70 using vusb
[12332.892126] usb 1-1: parent hub has no TT
то скорее всего, устройство не поддерживает USB 2.0, к которому его прицепили, нужно сделать другой контроллер с правильным параметром UsbVer.

Кроме того, устройство можно прибить гвоздями в конфигурационном файле домена:
vusb=['usbver=1, numports=4, port_1=4-2']
Список литературы: