Перейти к содержимому

Что означает dev sdg1

  • автор:

fstab. Параметры монтирования блочных устройств

Файл /etc/fstab используется для настройки параметров монтирования различных блочных устройств, разделов на диске и удаленных файловых систем.

Пример файла

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

Формат строки

Каждая строка в файле /etc/fstab содержит следующие поля, разделенные пробелами или символами табуляции:

filesystem

Физическое место размещения файловой системы, по которому определяется конкретный раздел или устройство хранения для монтирования.

Точка монтирования, куда монтируется корень файловой системы.

Тип файловой системы. Поддерживается множество типов: ext2, ext3, ext4, btrfs, reiserfs, xfs, jfs, smbfs, iso9660, vfat, ntfs, swap и auto. При выборе auto команда mount попытается определить реальный тип файловой системы самостоятельно. Это полезно для компакт-дисков (CD/DVD).

options

Параметры монтирования файловой системы. Подробнее смотрите на man странице mount. Обратите внимание, что некоторые параметры относятся к конкретным типам файловых систем.

Опция Значение
auto Файловая система монтируется при загрузке автоматически или после выполнения команды 'mount -a'.
noauto Файловая система может быть смонтирована только вручную.
exec Позволяет исполнять бинарные файлы на разделе диска. Установлено по умолчанию.
noexec Бинарные файлы не выполняются. Использование опции на корневой системе приведёт к её неработоспособности.
ro Монтирует файловую систему только для чтения.
rw Монтирует файловую систему для чтения/записи.
sync Все операции ввода-вывода должны выполняться синхронно.
async Все операции ввода-вывода должны выполняться асинхронно.
user Разрешает любому пользователю монтировать файловую систему. Применяет опции noexec, nosuid, nodev, если они не переопределены.
nouser Только суперпользователь может монтировать файловую систему. Используется по умолчанию.
defaults Использовать значения по умолчанию. Соответствует набору rw, suid, dev, exec, auto, nouser, async.
suid Разрешить операции с suid и sgid битами. В основном используются, чтобы позволить пользователям выполнять бинарные файлы со временно приобретёнными привилегиями для выполнения определённой задачи.
nosuid Запрещает операции с suid и sgid битами.
nodev Данная опция предполагает, что на монтируемой файловой системе не будут созданы файлы устройств (/dev). Корневой каталог и целевая директория команды chroot всегда должны монтироваться с опцией dev или defaults.
atime Включает запись информации о последнем времени доступа (atime) при каждом чтении файла. Включено по умолчанию на Linux до v.2.6.29 включительно.
noatime Отключает запись информации о последнем времени доступа (atime) при каждом чтении файла.
relatime Включает запись информации о последнем времени доступа при чтении файла, если предыдущее время доступа (atime) меньше времени изменения файла (ctime). Включено по умолчанию на Linux начиная с v.2.6.30.
acl Включить обработку ACL для раздела

Используется утилитой dump для определения того, нужно ли создать резервную копию данных в файловой системе. Возможные значения: 0 или 1. Если указано число 1, dump создаст резервную копию. У большинства пользователей утилита dump не установлена, поэтому им следует указывать 0 в этом поле.

Используется программой fsck для определения того, нужно ли проверять целостность файловой системы. Возможные значения: 0, 1 или 2. Значение 1 следует указывать только для корневой файловой системы (с точкой монтирования /); для остальных ФС, которые вы хотите проверять, используйте значение 2, которое имеет менее высокий приоритет.Обратите внимание, что в случае btrfs следует всегда указывать 0, даже если эта файловая система используется в качестве корневой. Файловые системы, для которых в поле указано значение 0, не будут проверяться fsck.

Определение файловой системы

Конкретное место расположения файловой системы может быть определено различными способами. В файле /etc/fstab можно указать имя файла устройства, его метку или UUID (в том числе GPT-метку и GPT-UUID для дисков GPT). Определение по UUID является наиболее предпочтительным способом. Далее приведены примеры определений файловых систем с использованием каждого из способов. Вывод lsblk -f and blkid для этих примеров вы можете найти на странице Persistent block device naming.

По именам устройств

Запустите lsblk -f , чтобы отобразить список разделов. Укажите имена устройств с префиксом /dev/ :

По меткам

Запустите lsblk -f , чтобы отобразить список разделов. Укажите метки из столбца LABEL с префиксом LABEL= :

По UUID

Запустите lsblk -f, чтобы отобразить список разделов. Укажите идентификаторы из столбца UUID с префиксом UUID= :

Совет: Если вы хотите отобразить только UUID конкретного раздела, используйте команду lsblk -no UUID /dev/sda2.

По меткам GPT

Запустите blkid чтобы отобразить список разделов. Укажите значения PARTLABEL без кавычек:

По UUID GPT

Запустите blkid чтобы отобразить список разделов. Укажите значения PARTUUID без кавычек:

Дополнительная информация

Автоматическое монтирование с systemd

Если у вас большой раздел /home, вы можете разрешить службам, которые не обращаются к /home, запускаться в то время, как /home проверяется программой fsck. Для этого добавьте следующие параметры монтирования в запись /etc/fstab для точки монтирования /home:

При этом процедура проверки и монтирования /home будет запущена только при первой попытке доступа, и ядро будет держать в ожидании все создаваемые потоки ввода-вывода в /home, пока раздел не будет смонтирован.

Обратите внимание: Ускорение при автоматическом монтировании /home может составлять не более секунды-двух, в зависимости от конфигурации вашей системы. При этом разделу /home будет присвоен тип файловой системы autofs, который по умолчанию игнорируется mlocate. Используйте эту возможность с осторожностью.

Автоматическое монтирование может аналогичным образом использоваться и для монтирования удаленных файловых систем. В дополнение, вы можете использовать параметр x-systemd.device-timeout=# для указания времени ожидания удаленной файловой системы при перебоях в соединении.

Обратите внимание: Если вы намереваетесь использовать флаг exec при автоматическом монтировании, вам следует удалить флаг user, чтобы монтирование производилось корректно.

Если у вас имеются зашифрованные файловые системы, вы можете также добавить параметр noauto в соответствующие записи в /etc/crypttab . Тогда systemd не будет пытаться открыть зашифрованное устройство во время загрузки системы, а сделает это при первой попытке доступа к файловой системе на этом устройстве, применив указанный файл ключа и затем автоматически смонтировав ФС. Это может дать выигрыш в несколько секунд при загрузке системы, например, если у вас зашифрованный RAID массив: systemd не придется ожидать готовности устройства.

Пробелы в значениях полей

Так как пробельные символы используются в fstab для разделения полей, их нельзя напрямую использовать в значениях полей. Любые пробелы в полях (например, значения PARTLABEL, LABEL или точки монтирования) должны быть заменены специальными управляющими последовательностями, которые состоят из обратной косой черты (\) и трех восьмеричных цифр (например, для пробела это \040):

Внешние устройства

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

Параметры atime

Обратите внимание: Действие noatime перекрывает собой nodiratime. Нет необходимости указывать оба параметра.

Запись в FAT32 с правами обычного пользователя

Чтобы иметь возможность записи в разделе FAT32, вам следует указать правильные параметры монтирования в вашем файле /etc/fstab.

Флаг user означает, что любой пользователь сможет монтировать и размонтировать раздел /dev/sdX . Параметр rw дает доступ на чтение-запись; umask убирает указанные права — например, umask=111 удаляет права на выполнение. Проблема в том, что права на «выполнение» также удаляются у каталогов, поэтому мы должны исправить это при помощи параметра dmask=000 .
Без этих параметров все файлы будут восприниматься исполняемыми. Вы можете использовать параметр showexec вместо umask и dmask, при которой исполняемыми будут файлы, имеющие расширения исполняемых файлов Windows (.com, .exe, .bat).
Например, если ваш раздел FAT32 на /dev/sda9, и вы хотите смонтировать его в каталог /mnt/fat32, то вам следует использовать запись следующего вида:

Перемонтирование корневого раздела

Если по какой-то причине корневой раздел был неправильно смонтирован только на чтение, вы можете перемонтировать его с доступом на чтение-запись без перезагрузки, набрав

fstab

The fstab(5) file can be used to define how disk partitions, various other block devices, or remote file systems should be mounted into the file system.

Each file system is described in a separate line. These definitions will be converted into systemd mount units dynamically at boot, and when the configuration of the system manager is reloaded. The default setup will automatically fsck and mount file systems before starting services that need them to be mounted. For example, systemd automatically makes sure that remote file system mounts like NFS or Samba are only started after the network has been set up. Therefore, local and remote file system mounts specified in /etc/fstab should work out-of-the-box. See systemd.mount(5) for details.

The mount command will use fstab, if just one of either directory or device is given, to fill in the value for the other parameter. When doing so, mount options which are listed in fstab will also be used.

Usage

A simple /etc/fstab , using file system UUIDs:

  • <device> describes the block special device or remote file system to be mounted; see #Identifying file systems.
  • <dir> describes the mount directory.
  • <type> the file system type.
  • <options> the associated mount options; see mount(8) § FILESYSTEM-INDEPENDENT_MOUNT_OPTIONS and ext4(5) § MOUNT_OPTIONS .
  • <dump> is checked by the dump(8) utility. This field is usually set to 0 , which disables the check.
  • <fsck> sets the order for file system checks at boot time; see fsck(8) . For the root device it should be 1 . For other partitions it should be 2 , or 0 to disable checking.
  • The auto type lets the mount command guess what type of file system is used. This is useful for optical media (CD/DVD/Blu-ray).
  • If the root file system is btrfs or XFS, the fsck order should be set to 0 instead of 1 . See fsck.btrfs(8) and fsck.xfs(8) .

All specified devices within /etc/fstab will be automatically mounted on startup and when the -a flag is used with mount(8) unless the noauto option is specified. Devices that are listed and not present will result in an error unless the nofail option is used.

Identifying file systems

alt=»Tango-view-fullscreen.png» width=»48″ height=»48″ />This article or section needs expansion. alt=»Tango-view-fullscreen.png» width=»48″ height=»48″ />

There are different ways to identify file systems that will be mounted in /etc/fstab : kernel name descriptor, file system label and UUID, and GPT partition label and UUID for GPT disks. Kernel name descriptors should not be used, while UUIDs or PARTUUIDs should be preferred over labels. See Persistent block device naming for more explanations. It is recommended to read that article first before continuing with this article.

In this section, we will describe how to mount file systems using all the mount methods available via examples. The output of the commands lsblk -f and blkid used in the following examples are available in the article Persistent block device naming.

To use kernel name descriptors, use /dev/sdxy in the first column.

Kernel name descriptors

Run lsblk -f to list the partitions and prefix the values in the NAME column with /dev/ .

File system labels

Run lsblk -f to list the partitions, and prefix the values in the LABEL column with LABEL= or alternatively run blkid and use the LABEL values without the quotes:

File system UUIDs

Run lsblk -f to list the partitions, and prefix the values in the UUID column with UUID= or alternatively run blkid and use the UUID values without the quotes:

GPT partition labels

Run blkid to list the partitions, and use the PARTLABEL values without the quotes:

GPT partition UUIDs

Run blkid to list the partitions, and use the PARTUUID values without the quotes:

Tips and tricks

Automount with systemd

See systemd.mount(5) for all systemd mount options.

Local partition

In case of a large partition, it may be more efficient to allow services that do not depend on it to start while it is checked by fsck. This can be achieved by adding the following options to the /etc/fstab entry of the partition:

This will fsck and mount the partition only when it is first accessed, and the kernel will buffer all file access to it until it is ready. This method can be relevant if one has, for example, a significantly large /home partition.

Remote file system

The same applies to remote file system mounts. If you want them to be mounted only upon access, you will need to use the noauto,x-systemd.automount parameters. In addition, you can use the x-systemd.mount-timeout= option to specify how long systemd should wait for the mount command to finish. Also, the _netdev option ensures systemd understands that the mount is network dependent and order it after the network is online.

Encrypted file system

If you have encrypted file systems with keyfiles, you can also add the noauto parameter to the corresponding entries in /etc/crypttab . systemd will then not open the encrypted device on boot, but instead wait until it is actually accessed and then automatically open it with the specified keyfile before mounting it. This might save a few seconds on boot if you are using an encrypted RAID device for example, because systemd does not have to wait for the device to become available. For example:

Automatic unmount

You may also specify an idle timeout for a mount with the x-systemd.idle-timeout flag. For example:

This will make systemd unmount the mount after it has been idle for 1 minute.

External devices

External devices that are to be mounted when present but ignored if absent may require the nofail option. This prevents errors being reported at boot. For example:

The nofail option is best combined with the x-systemd.device-timeout option. This is because the default device timeout is 90 seconds, so a disconnected external device with only nofail will make your boot take 90 seconds longer, unless you reconfigure the timeout as shown. Make sure not to set the timeout to 0, as this translates to infinite timeout.

Filepath spaces

Since spaces are used in fstab to delimit fields, if any field (PARTLABEL, LABEL or the mount point) contains spaces, these spaces must be replaced by escape characters \ followed by the 3 digit octal code 040 :

atime options

Below atime options can impact drive performance.

  • The strictatime option updates the access time of the files every time they are accessed. This is more purposeful when Linux is used for servers; it does not have much value for desktop use. The drawback about the strictatime option is that even reading a file from the page cache (reading from memory instead of the drive) will still result in a write.
  • The noatime option fully disables writing file access times to the drive every time you read a file. This works well for almost all applications, except for those that need to know if a file has been read since the last time it was modified. The write time information to a file will continue to be updated anytime the file is written to with this option enabled.
  • The nodiratime option disables the writing of file access times only for directories while other files still get access times written.

When using Mutt or other applications that need to know if a file has been read since the last time it was modified, the noatime option should not be used; using the relatime option is acceptable and still provides a performance improvement.

Since kernel 4.0 there is another related option:

  • lazytime reduces writes to disk by maintaining changes to inode timestamps (access, modification and creation times) only in memory. The on-disk timestamps are updated only when either (1) the file inode needs to be updated for some change unrelated to file timestamps, (2) a sync to disk occurs, (3) an undeleted inode is evicted from memory or (4) if more than 24 hours passed since the the last time the in-memory copy was written to disk.

Note that the lazytime option works in combination with the aforementioned *atime options, not as an alternative. That is relatime by default, but can be even strictatime with the same or less cost of disk writes as the plain relatime option.

Remounting the root partition

If for some reason the root partition has been improperly mounted read only, remount the root partition with read-write access with the following command:

GPT partition automounting

When using UEFI/GPT, it is possible to omit certain partitions from /etc/fstab by partitioning according to the Discoverable Partitions Specification and have systemd-gpt-auto-generator(8) mount the partitions. See systemd#GPT partition automounting.

Что означает dev sdg1

Повесть о Linux и LVM (Logical Volume Manager).
+ дополнения

Автор: Иван Песин
Автор: Игорь Чубин (автор дополнений)

В основу этой страницы положена работа «Повесть о Linux и LVM» Ивана Песина, которая, в свою очередь, написана на основе Linux LVM HOWTO. Она дополнена новыми ссылками и небольшими уточнениями, а также углублённым рассмотрением нескольких дополнительных вопросов.

Один из вопросов это использование kpartx из пакета multipath-tools для построения карты устройства (device map) и рекурсивного доступа к томам LVM (когда LVM развёрнут на разделах, созданных внутри логического тома LVM более низкого уровня). Это может быть полезно при использовании LVM совместно с системами виртуализации.

Второй вопрос — это использование постоянных снимков (persistent snapshot) для быстрого клонирования разделов. Эта возможность может быть полезна как при выполнении резервного копирования, так и при быстром создании виртуальных машин в системах виртуализации (вопрос создания снимков затрагивался и в повести, но здесь он рассмотрен более детально).

Третий вопрос — это сравнение LVM и файловой системой ZFS, набирающей в последнее время большую популярность. На первый взгляд такое сравнение может показаться странным, ведь ZFS — это файловая система, а LVM — система управления томами, то есть нечто, что находится на уровень ниже файловой системы. В действительности, сравнение вполне имеет право на существование, поскольку ZFS это не просто файловая система, а нечто большее. В ней присутствует уровень «storage pool», который берёт на себя те же задачи, что и LVM.

Содержание

[править] Введение

Цель статьи — описать процесс установки и использования менеджера логических томов на Linux-системе. LVM (Logical Volume Manager), менеджер логических томов — это система управления дисковым пространством, абстрагирующаяся от физических устройств. Она позволяет эффективно использовать и легко управлять дисковым пространством. LVM обладает хорошей масштабируемостью, уменьшает общую сложность системы. У логических томов, созданных с помощью LVM, можно легко изменить размер, а их названия могут нести большую смысловую нагрузку, в отличие от традиционных /dev/sda, /dev/hda .

Реализации менеджеров логических томов существуют практически во всех UNIX-подобных операционных системах. Зачастую они сильно отличаются в реализации, но все они основаны на одинаковой идее и преследуют аналогичные цели. Одна из основных реализаций была выполнена Open Software Foundation (OSF) и сейчас входит в состав многих систем, например IBM AIX, DEC Tru64, HP/UX. Она же послужила и основой для Linux-реализации LVM.

Данная статья является переработкой и дополнением LVM-HOWTO.

[править] Терминология

Поскольку система управления логическими томами использует собственную модель представления дискового пространства, нам необходимо определиться с терминами и взаимосвязями понятий. Рассмотрим схему, основанную на диаграмме Эрика Бегфорса (Erik Bеgfors), приведенную им в списке рассылки linux-lvm. Она демонстрирует взаимосвязь понятий системы LVM:

Обозначения и понятия:

  • PV, Physical volume, физический том. Обычно это раздел на диске или весь диск. В том числе, устройства программного и аппаратного RAID (которые уже могут включать в себя несколько физических дисков). Физические тома входят в состав группы томов.
  • VG, Volume group, группа томов. Это самый верхний уровень абстрактной модели, используемой системой LVM. С одной стороны группа томов состоит из физических томов, с другой — из логических и представляет собой единую административную единицу.
  • LV, Logical volume, логический том. Раздел группы томов, эквивалентен разделу диска в не-LVM системе. Представляет собой блочное устройство и, как следствие, может содержать файловую систему.
  • PE, Physical extent, физический экстент. Каждый физический том делится на порции данных, называющиеся физическими экстентами. Их размеры те же, что и у логических экстентов.
  • LE, Logical extent, логический экстент. Каждый логический том делится на порции данных, называющиеся логическими экстентами. Размер логических экстентов не меняется в пределах группы томов.

Давайте теперь соединим все эти понятия в общую картину. Пусть у нас имеется группа томов VG00 с размером физического экстента 4Мб. В эту группу мы добавляем два раздела, /dev/hda1 и /dev/hdb1. Эти разделы становятся физическими томами, например PV1 и PV2 (символьные имена присваивает администратор, так что они могут быть более осмысленными). Физические тома делятся на 4-х мегабайтные порции данных, т.к. это размер физического экстента. Диски имеют разный размер: PV1 получается размером в 99 экстентов, а PV2 — размером в 248 экстентов. Теперь можно приступать к созданию логических томов, размером от 1 до 347 (248+99) экстентов. При создании логического тома, определяется отображение между логическими и физическими экстентами. Например, логический экстент 1 может отображаться в физический экстент 51 тома PV1. В этом случае, данные, записанные в первые 4Мб логического экстента 1, будут в действительности записаны в 51-й экстент тома PV1.

Администратор может выбрать алгоритм отображения логических экстентов в физические. На данный момент доступны два алгоритма:

1. Линейное отображение последовательно назначает набор физических экстентов области логического тома, т.е. LE 1 — 99 отображаются на PV1, а LE 100 — 347 — на PV2.

2. «Расслоенное» (striped) отображение разделяет порции данных логических экстентов на определенное количество физических томов. То есть:

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

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

[править] Работа с LVM

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

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

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

[править] Инициализация дисков и разделов

Перед использованием диска или раздела в качестве физического тома необходимо его инициализировать:

Для целого диска:

Эта команда создает в начале диска дескриптор группы томов.

Если вы получили ошибку инициализации диска с таблицей разделов — проверьте, что работаете именно с нужным диском, и когда полностью будете уверены в том, что делаете, выполните следующие команды

Эти команды уничтожат таблицу разделов на целевом диске.

Установите программой fdisk тип раздела в 0x8e.

Команда создаст в начале раздела /dev/hdb1 дескриптор группы томов.

[править] Создание группы томов

Для создания группы томов используется команда ‘vgcreate’

Если вы используете devfs важно указывать полное имя в devfs, а не ссылку в каталоге /dev. Таким образом приведенная команда должна выглядеть в системе с devfs так:

Кроме того, вы можете задать размер экстента при помощи ключа «-s», если значение по умолчанию в 4Мб вас не устраивает. Можно, также, указать ограничения возможного количества физических и логических томов.

[править] Активация группы томов

После перезагрузки системы или выполнения команды vgchange -an, ваши группы томов и логические тома находятся в неактивном состоянии. Для их активации необходимо выполнить команду

[править] Удаление группы томов

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

Деактивируйте группу томов:

Теперь можно удалить группу томов командой:

[править] Добавление физических томов в группу томов

Для добавления предварительно инициализированного физического тома в существующую группу томов используется команда ‘vgextend’:

[править] Удаление физических томов из группы томов

Убедитесь, что физический том не используется никакими логическими томами. Для этого используйте команду ‘pvdisplay’:

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

Затем можно использовать ‘vgreduce’ для удаления физических томов:

После этого используя pvremove можно удалить устройство, в котором больше нет необходимости, заполняя его метаданные нулями.

Эта процедура будет описана в следующих разделах.

[править] Создание логического тома

Для того, чтобы создать логический том «lv00», размером 1500Мб, выполните команду:

Без указания суффикса размеру раздела используется множитель «мегабайт» (в системе СИ равный 10 6 байт), что и продемонстрировано в примере выше. Суффиксы в верхнем регистре (KMGTPE) соответствуют единицам в системе СИ (с основанием 10), например, G — гигабайт равен 10 9 байт, а суффиксы в нижнем регистре (kmgtpe) соответствуют единицам в системе IEC (с основанием 2), например g — гибибайт равен 2 30 байт.

Для создания логического тома размером в 100 логических экстентов с расслоением по двум физическим томам и размером блока данных 4 KB:

Если вы хотите создать логический том, полностью занимающий группу томов, выполните команду vgdisplay, чтобы узнать полный размер группы томов, после чего используйте команду lvcreate.

Эти команды создают логический том lv02, полностью заполняющий группу томов. Тоже самое можно реализовать командой

[править] Удаление логических томов

Логический том должен быть размонтирован перед удалением:

[править] Увеличение логических томов

Для увеличения логического тома вам нужно просто указать команде lvextend до какого размера вы хотите увеличить том:

В результате /dev/vg00/home увеличится до 12Гбайт.

Эта команда увеличивает размер логического тома на 1Гб.

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

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

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

[править] ext2/ext3/ext4

Если вы не пропатчили ваше ядро патчем ext2online, вам будет необходимо размонтировать файловую систему перед изменением размера:

Если у вас нет пакета e2fsprogs 1.19 его можно загрузить с сайта ext2resize.sourceforge.net.

Для файловой системы ext2 есть и другой путь. В состав LVM входит утилита e2fsadm, которая выполняет и lvextend, и resize2fs (она также выполняет и уменьшение размера файловой системы, это описано в следующем разделе). Так что можно использовать одну команду:

что эквивалентно двум следующим:

вам все равно нужно будет размонтировать файловую систему перед выполнением e2fsadm.

[править] jfs
[править] reiserfs

Увеличивать размер файловых систем Reiserfs можно как в смонтированном, так и в размонтированном состоянии.

Увеличить размер смонтированной файловой системы:

Увеличить размер размонтированной файловой системы:

[править] xfs

Размер файловой системы XFS можно увеличить только в смонтированном состоянии. Кроме того, утилите в качестве параметра нужно передать точку монтирования, а не имя устройства:

[править] Уменьшение размера логического тома

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

[править] ext2

При использовании файловой системы ext2, как уже указывалось ранее, можно использовать команду e2fsadm:

Если вы хотите выполнить операцию по уменьшению логического тома вручную, вам нужно знать размер тома в блоках:

[править] ext2/ext3/ext4

Способ применимый в более современных системах.

Указываем размер явно и с некоторым с запасом:

[править] reiserfs

При уменьшении размера файловой системы Reiserfs, ее нужно размонтировать:

[править] xfs

Уменьшить размер файловой системы XFS нельзя.

Примечание: обратите внимание на то, что для уменьшения размера файловых систем, необходимо их размонтировать. Это вносит определенные трудности, если вы желаете уменьшить размер корневой файловой системы. В этом случае можно применить следующий метод: загрузится с CD дистрибутива, поддерживающего LVM. Перейти в командный режим (обычно это делается нажатием клавиш Alt+F2) и выполнить команды сканирования и активации группы томов:

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

[править] Перенос данных с физического тома

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

[править] Примеры

[править] Настройка LVM на трех SCSI дисках

В первом примере мы настроим логический том из трех SCSI дисков. Устройства дисков: /dev/sda, /dev/sdb и /dev/sdc.

Перед добавлением в группу томов диски нужно инициализировать:

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

Теперь создадим группу томов vg01, состоящую из этих дисков:

Проверим статус группы томов командой vgdisplay:

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

[править] Создание логического тома

После успешного создания группы томов, можно начать создавать логические тома в этой группе. Размер тома может быть любым, но, естественно, не более всего размера группы томов. В этом примере мы создадим один логический том размером 1 Гб. Мы не будем использовать «расслоение», поскольку при этом невозможно добавить диск в группу томов после создания логического тома, использующего данный алгоритм.

[править] Создание файловой системы

Создадим на логическом томе файловую систему ext2:

[править] Тестирование файловой системы

Смонтируйте логический том и проверьте все ли в порядке:

Если вы все сделали правильно, у вас должен появиться логический том с файловой системой ext2, смонтированный в точке /mnt.

[править] Создание логического тома с «расслоением»

Рассмотрим теперь вариант логического тома, использующего алгоритм «расслоения». Как уже указывалось выше, минусом этого решения является невозможность добавления дополнительного диска.

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

Для создания логического тома с «расслоением» на три физических тома с блоком данных 4Кб выполните команду:

После чего можно создавать файловую систему на логическом томе.

[править] Добавление нового диска

Рассмотрим систему со следующей конфигурацией:

Как видно из листинга, группы томов «dev» и «ops» практически заполнены. В систему добавили новый диск /dev/sdg. Его необходимо разделить между группами «ops» и «dev», поэтому разобьем его на разделы:

Перед тем как добавить разделы в группу томов, их необходимо инициализировать:

Теперь можно добавлять физические тома в группы томов:

Наконец, увеличим размеры логических томов и расширим файловые системы до размеров логических томов:

Нам осталось смонтировать системы и посмотреть их размеры:

[править] Резервное копирование при помощи «снапшотов»

Развивая приведенный пример, предположим, что нам нужно выполнить резервирование базы данных. Для этой задачи мы будем использовать устройство-«снапшот».

Этот тип устройства представляет собой доступную только на чтение (при использовании опции —permission r) копию другого тома на момент выполнения процедуры «снапшот». Это дает возможность продолжать работу не заботясь о том, что данные могут измениться в момент резервного копирования. Следовательно, нам не нужно останавливать работу базы данных на время выполнения резервного копирования. Остановка нужна только на момент создания устройства-«снапшот», который значительно короче самого копирования.

В группе томов ops у нас осталось около 600Мб свободного места, его мы и задействуем для «снапшот»-устройства. Размер «снапшот»-устройства не регламентируется, но должен быть достаточен для сохранения всех изменений, которые могут произойти с томом, с которого он сделан, за время жизни снапшота. 600Мб должно хватить для наших целей:

Если вы делаете «снапшот» файловой системы XFS, нужно выполнить на смонтированной файловой системе команду xfs_freeze, и лишь после этого создавать «снапшот»:

Если устройство-«снапшот» полностью заполняется, оно автоматически деактивируется. В этом случае «снапшот» не может более использоваться, потому крайне важно выделять достаточное пространство для него.

После того как мы создали «снапшот», его нужно смонтировать:

Если вы работаете с файловой системой XFS, вам будет нужно при монтировании указать опцию nouuid:

Выполним резервное копирование раздела:

После выполнения необходимых процедур, нужно удалить устройство-«снапшот»:

Запись данных на том, с которого сделан снимок, очень сильно замедлена по сравнению с обычной работой!

Элементарное сравнение производительности, наглядно демонстрирующее разницу между скоростью работы с томом, у которого нет снапшотов (смонтирован в /data/lv3/xxxx), и с томом, на котором есть снапшот (смонтирован в /data/lv4/qqqq).

Подробнее о снапшотах:

  • Consistent backup with Linux Logical Volume Manager (LVM) snapshots (англ.)
  • Back Up (And Restore) LVM Partitions With LVM Snapshots (англ.)
  • Linux Kernel Documentation: device-mapper/snapshot.txt (англ.)

Резервное копирование MySQL и LVM:

  • Using LVM for MySQL Backup and Replication Setup (англ.)
  • MySQL Backups using LVM Snapshots (англ.)
  • mylvmbackup (англ.)

[править] Удаление диска из группы томов

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

Учтите, что операция переноса физических экстентов занимает много времени. Если вы хотите наблюдать за процессом переноса экстентов, укажите в команде ключ -v .

После окончания процедуры переноса, удалите физический том из группы томов:

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

[править] Перенос группы томов на другую систему

Физический перенос группы томов на другую систему организовывается при помощи команд vgexport и vgimport.

Сперва необходимо размонтировать все логические тома группы томов и деактивировать группу:

После этого экспортируем группу томов. Процедура экспорта запрещает доступ к группе на данной системе и готовит ее к удалению:

Теперь можно выключить машину, отсоединить диски, составляющие группу томов и подключить их к новой системе. Остается импортировать группу томов на новой машине и смонтировать логические тома:

Все! Группа томов готова к использованию на новой системе.

[править] Конвертация корневой файловой системы в LVM

В данном примере имеется установленная система на двух разделах: корневом и /boot. Диск размером 2Гб разбит на разделы следующим образом:

Корневой раздел занимает все пространство, оставшееся после выделения swap и /boot разделов. Главное требование, предъявляемое к корневому разделу в нашем примере: он должен быть более чем на половину пуст. Это нужно, чтобы мы могли создать его копию. Если это не так, нужно будет использовать дополнительный диск. Процесс при этом останется тот же, но уменьшать корневой раздел будет не нужно.

Для изменения размера файловой системы мы будем использовать утилиту GNU parted.

Загрузитесь в однопользовательском режиме, это важно. Запустите программу parted для уменьшения размера корневого раздела. Ниже приведен пример диалога с утилитой parted:

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

Первое число — это номер раздела (hda3), второе — начало раздела hda3, не меняйте его. Последнее число — это конец раздела. Укажите приблизительно половину текущего размера раздела.

Создадим новый раздел:

Этот раздел будет содержать LVM. Он должен начинаться после раздела hda3 и заканчиваться в конце диска.

Выйдите из утилиты parted:

Перезагрузите систему. Убедитесь, что ваше ядро содержит необходимые установки. Для поддержки LVM должны быть включены параметры CONFIG_BLK_DEV_RAM и CONFIG_BLK_DEV_INITRD.

Для созданного раздела необходимо изменить тип на LVM (8e). Поскольку parted не знает такого типа, воспользуемся утилитой fdisk:

Инициализируем LVM, физический том; создаем группу томов и логический том для корневого раздела:

Создадим теперь файловую систему на логическом томе и перенесем туда содержимое корневого каталога:

Отредактируйте файл /mnt/etc/fstab на логическом томе соответствующем образом. Например, строку:

Создаем образ initrd, поддерживающий LVM:

Внимательно изучите вывод команды. Обратите внимание на имя нового образа и его размер. Отредактируйте файл /etc/lilo.conf. Он должен выглядеть приблизительно следующим образом:

KERNEL_IMAGE_NAME — имя ядра, поддерживающего LVM. INITRD_IMAGE_NAME — имя образа initrd, созданного командой lvmcreate_initrd. Возможно, вам будет нужно увеличить значение ramdisk, если у вас достаточно большая конфигурация LVM, но значения 8192 должно хватить в большинстве случаев. Значение по умолчанию параметра ramdisk равно 4096. Если сомневаетесь, проверьте вывод команды lvmcreate_initrd в строке lvmcreate_initrd — making loopback file (6189 kB).

После этого файл lilo.conf нужно скопировать и на логический том:

Выполните команду lilo:

Перезагрузитесь и выберите образ lvm. Для этого введите «lvm» в ответ на приглашение LILO. Система должна загрузится, а корневой раздел будет находиться на логическом томе.

После того как вы убедитесь, что все работает нормально, образ lvm нужно сделать загружаемым по умолчанию. Для этого укажите в конфигурационном файле LILO строку default=lvm, и выполните команду lilo.

Наконец, добавьте оставшийся старый корневой раздел в группу томов. Для этого измените тип раздела утилитой fdisk на 8е, и выполните команды:

[править] Организация корневой файловой системы в LVM для дистрибутива ALT Master 2.2

При установке данного дистрибутива оказалось невозможным разместить корневой раздел в системе LVM. Связано это с тем, как выяснилось позже, что в ядре, поставляемом с данным дистрибутивом, поддержка файловой системы ext2 организована в виде загружаемого модуля. Образ же initrd использует файловую систему romfs, поддержка которой вкомпилирована в ядро. При выполнении команды lvmcreate_initrd генерируется файл-образ initrd с системой ext2. Если после этого вы попытаетесь загрузиться, то получите примерно следующее:

Kernel panic: VFS: Unable to mount root fs on 3a:00

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

И копируйте туда модули, необходимые для работы с вашими дисковыми накопителями и файловыми системами (если они не вкомпилированы в ядро). Так, для системы с RAID-контроллером ICP-Vortex и корневой файловой системой reiserfs нужны модули: gdth.o mod_scsi.o sd_mod.o reiserfs.o. Добавьте их загрузку в файл /mnt/initrd/linuxrc.

Обратите внимание на оставшееся свободное место на образе:

Filesystem Size Used Avail Use% Mounted on . /boot/initrd-lvm-2.4.20-inp1-up-rootlvm

В файловой системе должно быть свободно еще 200-300Кб, в зависимости от вашей LVM-конфигурации. Если же у вас ситуация похожа на приведенную в листинге, будет необходимо создать новый образ, с большим размером файловой системы и повторить операции добавления модулей.

Наконец, отмонтируйте образ, сожмите его, запустите программу lilo и перезагрузитесь:

[править] Заключение

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

[править] Дополнительные вопросы по LVM

[править] Дисковые разделы и LVM внутри LVM

LVM может находиться рекурсивно внутри логического тома LVM.

Например, пусть есть три логических тома: LV1, LV2 и LV3. Один из которых, LV2 разбит на разделы, каждый из которых является физическим томом LVM, который в свою очередь объединены в группу томов, на которых созданы логические тома и так далее.

Такая ситуация очень легко может возникнуть при использовании виртуальных машин, например в том случае, если том LV2 выдан как диск виртуальной машине Xen или эмулятору QEMU.

Может возникнуть необходимость залезть внутрь системы томов, которые установлены внутрь логического тома. Например, это может произойти в случае, когда виртуальная машина (в результате сбоя или по какой-то другой причине), не загружается, а нужно добраться до её данных (напомним, что всё это при условии, что LVM используется не только снаружи, то есть в домене 0, но и внутри, то есть в домене U).

Решение, если говорить кратко, заключается в том, чтобы использовать kpartx из пакета multipath-tools, которая даёт возможность строить карты устройств (device maps) для разделов.

Далее процедура использования kpartx описывается подробно.

Блочное устройство, внутри которого находятся тома LVM может быть любым, в частности, это может быть том LVM, том EVMS, простой дисковый раздел или физическое устройство.

Убедитесь что пакет multipath-tools установлен:

Посмотрите как выполнено разбинение на разделы:

Создайте карту устройств для блочного устройства:

Карты находятся здесь:

Имена выглядят несколько странно, но вообще это нормально.

Можно попробовать смонтировать раздел:

В данном случае была смонтирована корневая файловая система виртуальной машины:

Аналогичным образом монтируем остальные разделы:

С разделами можно работать как обычно.

По завершению работы нужно

  • размонтировать разделы;
  • удалить карты устройств.

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

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

В данном примере loop0 это первое свободное loopback-устройство, но возможно, что оно будет занято, и тогда вместо loop0 нужно будет использовать loopX с более выскоим номерм X:

Можно монтировать, копировать, восстанавливать, форматировать эти разделы, короче, делать с ними всё, что делается с обычными дисковыми разделами.

С одной стороны при таком подходе:

  • не нужно вручную подключать loopback-устройства;
  • не нужно использовать kpartx;

Но с другой стороны:

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

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

Если внутри тома находится расширенный раздел, подход работает, но требует дополнительных манипуляций:

Найти начало интересующего раздела можно путём умножения значения поля Start (показанного fdiks) на 512.

Если мы хотим смонтировать корневой раздел:

[править] Создание зашифрованных томов LVM

Пример создания зашифрованного тома:

  • How to set up an encrypted filesystem in several easy steps (англ.)
  • Resizing Encrypted Filesystems (англ.)
  • How To Migrate to a full encrypted LVM system (англ.)

[править] Сравнение LVM и ZFS

На первый взгляд такое сравнение может показаться странным, ведь ZFS ­— это файловая система, а LVM ­— система для управления томами, то есть нечто, что находится на уровень ниже файловой системы.

В действительности, сравнение вполне имеет право на существование, поскольку ZFS это не просто файловая система, а нечто большее. В ней присутствует уровень «storage pool», который берёт на себя те же задачи, что и LVM.

В таком случае возникает вопрос, а какую функциональность ZFS может дать сама, без применения LVM, и если что-то она делает лучше, то что именно?

[править] Восстановления LVM после сбоя

  • Recover Data From RAID1 LVM Partitions With Knoppix Linux LiveCD (англ.)
  • LVM Recovery Tale (англ.)
  • Recovery of RAID and LVM2 Volumes (англ.)

[править] Слияние LVM

В августе 2008 появился патч для ядра Linux, который позволяет делать слияние снимка и тома: изменения, которые делаются на снимке, при желании можно перенести на том. Снимок при этом перестаёт существовать.

Начиная с ядра 2.6.33 [1] необходимый код присутствует в составе ядра Linux. Для того чтобы использовать его, необходим пакет LVM версии не менее 2.02.58 [2].

После выполнения этой команды изменения, сделанные в снимке lv1_snap будут перенесены в родительский том /dev/VG0/lv1, а снимок перестанет существовать.

  • http://kerneltrap.org/Linux/LVM_Snapshot_Merging
  • Merging Snapshot Volumes (англ.)

[править] Thin Provisioning

Начиная с 2012 года (полноценно с ядра Linux 3.4; май 2012) LVM поддерживает такую возможность как thin provisioning. Это возможность использовать какое-либо внешнее блочное устройство в режиме только для чтения как основу для создания новых логических томов LVM. Такие разделы при создании уже будут выглядеть так будто они заполнены данными исходного блочного устройства. Операции с томами изменяются налету таким образом, что чтение данных выполняется с исходного блочного устройства (или с тома если данные уже отличаются), а запись — на том.

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

  • New LVM2 release 2.02.89: Thinly-provisioned logical volumes (англ.)
  • https://github.com/jthornber/linux-2.6/blob/thin-stable/Documentation/device-mapper/thin-provisioning.txt (англ.)

[править] Поддержка LVM в NetBSD

В 2008 году в NetBSD появилась [1] начальная поддержка LVM.

Та часть, которая интегрируется в ядро, была написана с нуля и распространяется по лицензии BSD. Другая (большая) часть, которая работает в пространстве пользователя (userland), взята из Linux и осталась под лицензией GPL.

Пока что не работают такие вещи как создание снимков (snapshots), не работает pvmove и нет возможности совместной работы с LVM в кластере, как это можно делать с помощью CLVM (однако, использовать независимые логические тома в кластере, конечно же, можно).

  • How to use lvm on NetBSD (англ.)
  • The NetBSD Logical Volume Manager (англ.)
  • LVM Volume Manager on NetBSD (англ.) — пример использования LVM в NetBSD

[править] Работа с LVM в FreeBSD

Для монтирования LVM с EXT2/EXT3 файловой системой необходимо скомпилировать ядро с поддержкой EXT2FS:

либо добавить /boot/loader.conf строку:

Если после перезагрузки сервера необходимости в подключении данного диска не будет, тогда достаточно просто подгрузить модуль ядра kldload ext2fs

Для подключения LVM разделов необходимо перекомпилировать ядро с опцией:

либо добавить /boot/loader.conf

вручную можно произвести загрузку следующим образом

посмотреть результат (пример):

в /etc/fstab прописать следующим образом:

PS: Для монтирования LVM-раздела с другой FS, отличной от EXT2/EXT3 необходимо перекомпилировать ядро или загрузить соответствующие данной ФС модули ядра.

[править] Работа с LVM в Windows

LVM это чуждая для Windows система, и её поддержка в Windows отсутствует. Не предполагается, что вы будете работать с LVM из-под Windows. Однако, в некоторых случаях такая потребность всё же может возникнуть:

  • В случае, когда у вас на компьютере установлено две системы (dual boot), одна из которых Linux, а вторая Windows;
  • В случае, когда на переносном диске у вас LVM, внутри ценные файлы, а рядом только Windows-машины.

Программа Virtual Volumes позволяет обращаться к логическому тому LVM изнутри Windows-машины. Программа находится в процессе разработки. Пока она имеет некоторые ограничения.

  • http://www.chrysocome.net/virtualvolumes (англ.)

[править] Альтернативы LVM

LVM сегодня — это главная система управления томами, существующая в Linux. Раньше главным её конкурентом считалась система EVMS, но затем, после того как LVM была включена в ядро, а EVMS нет, конкуренция закончилась в пользу LVM.

Сейчас главными конкурентами LVM можно считать файловые системы с возможностями систем управления томами, такие как btrfs и ZFS [2] .

Кроме этого существует система Zumastor, которая отличается от LVM лучшей поддержкой управления снимками (snapshotting) и удалённой репликацией. Особенно печальным для LVM создатели Zumastor считают следующий факт: если в LVM сделать много снимков с одного тома, а потом в оригинальном томе изменить какой-то блок, то оригинальная информация будет копироваться теперь для каждого снимка [3] . Можно представить, какая будет производительность и расточительность при записи в оригинальный том, особенно в случае большого количества снимков с него. Большим недостатком Zumastor является то, что его развитие приостановлено несколько лет назад [4] .

Проблема неэффективных снапшотов в LVM считается одной из важнейших проблем LVM на сегодняшний день и работа по её устранению относится к одной из наиболее приоритетных [5] . Другой приоритетной задачей является поддержка снапшотов бесконечной глубины, то есть, возможность создания снапшотов со снапшотов [6] . Другие попытки решить эту задачу: [4], [5].

[править] Графические инструменты администрирования LVM

Есть несколько графических инструментов, помогающих использовать LVM. В частности:

  1. LVM GUI Project [7] ;
  2. system-config-lvm.

Первый уже давно не развивается. Второй является основным графическим инструментом для администрирования LVM в Redhat-подобных дистрибутивах. Он может быть установлен и в других. Например, в Debian [8] :

Вызвать его можно командой:

  • Using the LVM utility system-config-lvm (англ.) — подробно об использовании system-config-lvm

[править] Ограничение скорости доступа к LVM-томам

Ограничение делается на уровне cgroup:

В качестве X:Y используются мажорный и минорный номер соответствующего тома.

Что общего между LVM и матрешкой?

Доброго времени суток.
Хочу поделиться с сообществом практическим опытом построения системы хранения данных для KVM с использованием md RAID + LVM.

В программе будет:

  • Сборка md RAID 1 из NVMe SSD.
  • Сборка md RAID 6 из SATA SSD и обычных дисков.
  • Особенности работы TRIM/DISCARD на SSD RAID 1/6.
  • Создание загрузочного md RAID 1/6 массива на общем наборе дисков.
  • Установка системы на NVMe RAID 1 при отсутствии поддержки NVMe в BIOS.
  • Использование LVM cache и LVM thin.
  • Использование BTRFS снимков и send/recieve для резервного копирования.
  • Использование LVM thin снимков и thin_delta для резервного копирования в стиле BTRFS.

Заявление

Автор не несет никакой ответственности за последствия использования или не использования материалов/примеров/кода/советов/данных из этой статьи. Читая или каким-то образом используя данный материал вы берете на себя ответственность за все последствия от этих действий. К возможным последствиям относятся:

  • Зажаренные до хрустящей корочки NVMe SSD.
  • Полностью израсходованный ресурс записи и выход из строя SSD накопителей.
  • Полная потеря всех данных на всех накопителях, в том числе резервных копий.
  • Неисправное компьютерное железо.
  • Потраченное время, нервы и деньги.
  • Любые другие последствия, которые не перечислены выше.

Железо

В наличии было:

Материнская плата где-то 2013 года выпуска на чипсете Z87 в комплекте с Intel Core i7 / Haswell.

  • Процессор 4 ядра, 8 потоков
  • 32 Гигабайта оперативной памяти DDR3
  • 1 x 16 или 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 разъема
  1. Можно было в любой момент выкинуть этот адаптер и заменить на любой другой первый попавшийся.
  2. Нормально работал TRIM/Discard на дисках, т.к. в RAID прошивке эти команды не поддерживаются совсем, а HBA в общем-то все равно какие команды по шине передавать.
Дополнительно было добавлено:

6 штук SATA SSD модели Samsung 860 QVO 2TB. От этих SSD требовался большой объем, наличие SLC кэша, желательна надежность, и, невысокая цена. Обязательна была поддержка discard/zero которая проверяется строчкой в dmesg:

kernel: ata1.00: Enabling discard_zeroes_data

2 штуки NVMe SSD модели Samsung SSD 970 EVO 500GB.

Для этих SSD важна скорость случайного чтения/записи и ресурс под ваши нужды. Радиатор к ним. Обязательно. Совсем обязательно. Иначе, — прожарите их до хрустящей корочки при первой-же синхронизации RAIDa.

Адаптер StarTech PEX8M2E2 для 2 x NVMe SSD с установкой в PCIe 3.0 8x слот. Это, опять-же, просто HBA, но для NVMe. Отличается от дешевых адаптеров отсутствием требования поддержки PCIe bifurcation от материнской платы благодаря наличию встроенного PCIe коммутатора. Будет работать даже в самой древней системе где есть PCIe, даже если это будет x1 PCIe 1.0 слот. Естественно, с соответствующей скоростью. Никаких RAIDов там нет. Встроенного BIOS на борту нет. Так что, ваша система магически не научится загружаться с NVMe и тем более делать NVMe RAID благодаря этому устройству.

Компонент этот был обусловлен исключительно наличием только одного свободного 8x PCIe 3.0 в системе, и, при наличии 2х свободных слотов, легко заменяется на два копеечных PEX4M2E1 или аналоги, которых можно купить где угодно по цене от 600 рублей.

Отказ от всевозможных аппаратных или встроенных в чипсет/BIOS RAIDов был сделан осознанно, с целью иметь возможность полностью заменить всю систему, за исключением самих SSD/HDD, сохранив все данные. В идеале, чтобы можно было сохранить даже установленную операционную систему при переезде на совсем новое/другое железо. Главное чтобы были SATA и PCIe порты. Это как live CD или загрузочная флэшка, только очень быстрая и немного габаритная.

Ранее на железе была установлена Debian 8 Jessie которая близка к EOL. Был собран RAID 6 из выше упомянутых HDD в паре с LVM. На нем крутились виртуальные машины в kvm/libvirt.

Т.к. автор имеет подходящий опыт создания портативных загрузочных SATA/NVMe флэшек, а также, чтобы не рвать привычный apt-шаблон, в качестве целевой системы была выбрана Ubuntu 18.04 которая уже достаточно стабилизировалась, но до сих пор имеет 3 года поддержки в перспективе.

В упомянутой системе присутствуют все необходимые нам драйверы железа из коробки. Никакого стороннего софта и драйверов нам не потребуется.

Подготовка к установке

Для установки системы нам потребуется Ubuntu Desktop Image. У серверной системы какой-то ядреный установщик, который проявляет излишнюю не отключаемую самостоятельность обязательно впихивая UEFI системный раздел на один из дисков портя всю красоту. Соответственно устанавливается оно только в UEFI режиме. Вариантов не предлагает.

Нас это не устраивает.

К сожалению, UEFI загрузка крайне плохо совместима с загрузочным программным RAIDом, т.к. резервирования для UEFI ESP раздела нам никто не предлагает. В сети есть рецепты, которые предлагают разместить ESP раздел на флэшке в USB порте, но, это точка отказа. Есть рецепты с использованием программного mdadm RAID 1 с метаданными версии 0.9 которые не мешают UEFI BIOS видеть этот раздел, но, это живет до счастливого момента когда BIOS или другая ОС на железе запишет что-то в ESP забыв синхронизировать на другие зеркала.

Помимо этого, загрузка UEFI зависит от NVRAM, которая не переедет вместе с дисками на новую систему, т.к. является частью материнской платы.

Так что, мы не будем изобретать новый велосипед. У нас уже есть готовый, проверенный годами дедовский велосипед ныне называемый Legacy/BIOS boot, носящий гордое имя CSM на UEFI-совместимых системах. Мы просто достанем его с полки, смажем, подкачаем колеса и протрем влажной тряпочкой.

Desktop версия Ubuntu тоже не умеет нормально ставиться с Legacy загрузчиком, но тут, как говорится, хотя-бы есть варианты.

И так, собираем железо и грузим систему с загрузочной флэшки Ubuntu Live. Нам надо будет скачивать пакеты, так что настраиваем сеть, какая у вас заработала. Если не заработала, — нужные пакеты можно подгрузить на флешку заранее.

Заходим в Desktop окружение, запускаем эмулятор терминала, и, поехали:

#apt-get install mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc

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

С этой точки зрения ZFS — это Феррари, а mdadm+lvm больше походит на велосипед.

Субъективно автор предпочитает одалживать неизвестным личностям взятый в кредит велосипед вместо Феррари. Там и цена вопроса не высока. Не нужно прав. Проще ПДД. Парковки бесплатные. Проходимость лучше. К велосипеду всегда можно приделать ноги, да и починить велосипед можно своими руками.

Для того чтобы загрузить операционную систему нам потребуется файловая система поддерживаемая в Legacy/BIOS GRUB из коробки, и, при этом, поддерживающая снимки на-живую. Мы будем использовать ее для /boot раздела. Помимо этого, автор предпочитает использовать эту ФС для / (корня) не забывая отметить, что для любого другого софта можно создать отдельные разделы на LVM и монтировать в нужные каталоги.

Ни образы виртуальных машин, ни базы данных мы на этой ФС хранить не будем.
Использоваться эта ФС будет только для создания мгновенных снимков системы без ее выключения с последующим перекачиванием этих снимков на резервный диск при помощи send/recieve.

Помимо этого, автор вообще предпочитает держать минимум программного обеспечения непосредственно на железе и гонять весь остальной софт в виртуальных машинах используя такие штуки как пробрасывание GPU и PCI-USB Host-контроллеров в KVM через IOMMU.

На железе остаются только — хранение данных, виртуализация и резервное копирование.

Если вы больше доверяете ZFS, то, в принципе, для указанного применения они взаимозаменяемы.

Тем не менее, автор сознательно игнорирует встроенные функции зеркалирования / RAID и избыточности которые есть в ZFS, BRTFS и LVM.

В качестве дополнительного аргумента, BTRFS имеет свойство превращать случайную запись в последовательную, что крайне позитивно сказывается на скорости синхронизации снимков / резервных копий на HDD.

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

#udevadm control —reload-rules && udevadm trigger

#lsscsi && nvme list
[0:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sda
[1:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdb
[2:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdc
[3:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdd
[4:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sde
[5:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdf
[6:0:0:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdg
[6:0:1:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdh
[6:0:2:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdi
[6:0:3:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdj
[6:0:4:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdk
[6:0:5:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdl
[6:0:6:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdm
[6:0:7:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdn
Node SN Model Namespace Usage Format FW Rev
—————- ——————— —————————————- ——— ————————— —————- ———
/dev/nvme0n1 S466NXXXXXXX15L Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7
/dev/nvme1n1 S5H7NXXXXXXX48N Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7

Разметка «дисков»

NVMe SSD

А вот никак мы их не будем размечать. Все равно наш BIOS не видит эти накопители. Так что, они целиком пойдут в программный RAID. Даже разделов создавать там не будем. Если хочется по «канону» или «принципиально» — создайте один большой раздел, как у HDD.

SATA HDD

Тут особо изобретать ничего не надо. Мы создадим один раздел на все. Раздел создадим потому, что эти диски видит BIOS и даже может попытаться с них загрузиться. Мы даже установим позже на эти диски GRUB чтобы у системы это внезапно получилось.

#cat >hdd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sdg
unit: sectors

/dev/sdg1 : start= 2048, size= 1953523120, type=fd, bootable
EOF
#sfdisk /dev/sdg < hdd.part
#sfdisk /dev/sdh < hdd.part
#sfdisk /dev/sdi < hdd.part
#sfdisk /dev/sdj < hdd.part
#sfdisk /dev/sdk < hdd.part
#sfdisk /dev/sdl < hdd.part
#sfdisk /dev/sdm < hdd.part
#sfdisk /dev/sdn < hdd.part

SATA SSD

Тут у нас интереснее всего.

Во-первых накопители у нас размером 2 ТБ. Это в пределах допустимого для MBR, чем мы и воспользуемся. При необходимости можно заменить на GPT. У GPT дисков есть слой совместимости который позволяет MBR-совместимым системам видеть первые 4 раздела если они расположены в пределах первых 2х терабайт. Главное, чтобы загрузочный раздел и раздел bios_grub на этих дисках были в начале. Это позволяет даже делать с GPT дисков Legacy/BIOS загрузку.

Но, это не наш случай.

Здесь мы будем создавать два раздела. Первый будет размером 1 Гб и использован для RAID 1 /boot.

Второй будет будет использоваться для RAID 6 и занимать все оставшееся свободное место за исключением небольшой не размеченной области в конце накопителя.

Согласно источникам в сети наши SATA SSD имеют на борту динамически расширяемый SLC кэш размером от 6 до 78 гигабайт. 6 гигабайт мы получаем «бесплатно» за счет разницы между «гигабайтами» и «гибибайтами» в техпаспорте накопителя. Остальные 72 гигабайта выделяются за счет неиспользуемого пространства.

Тут надо заметить, что кэш у нас SLC, а место занимается в режиме 4 bit MLC. Что для нас эффективно означает, что за каждые 4 гигабайта свободного пространства мы получим только 1 гигабайт SLC кэша.

Умножаем 72 гигабайта на 4 и получаем 288 гигабайт. Это и есть то свободное место которое мы не будем размечать, чтобы позволить накопителям на полную использовать SLC кэш.

Таким образом, мы получим эффективно до 312 гигабайт SLC кэша суммарно от шести накопителей. Из всех накопителей 2 будут использоваться в RAID для избыточности.

Такое количество кэша позволит нам крайне редко в живой практике сталкиваться с ситуацией, когда запись идет не в кэш. Это чрезвычайно хорошо компенсирует самый печальный недостаток QLC памяти, — крайне низкую скорость записи когда данные пишутся в обход кэша. Если ваши нагрузки этому не соответствуют, то, я рекомендую вам сильно задуматься о том, сколько проживут ваши SSD под такой нагрузкой учитывая TBW из техпаспорта.

#cat >ssd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sda
unit: sectors

/dev/sda1 : start= 2048, size= 2097152, type=fd, bootable
/dev/sda2 : start= 2099200, size= 3300950016, type=fd
EOF
#sfdisk /dev/sda < ssd.part
#sfdisk /dev/sdb < ssd.part
#sfdisk /dev/sdc < ssd.part
#sfdisk /dev/sdd < ssd.part
#sfdisk /dev/sde < ssd.part
#sfdisk /dev/sdf < ssd.part

Создание массивов

Для начала нам нужно переименовать машину. Нужно потому, что имя хоста является частью имени массива где-то внутри mdadm и где-то на что-то влияет. Массивы конечно можно позже переименовать, но, это лишние действия.

#mcedit /etc/hostname
#mcedit /etc/hosts
#hostname
vdesk0

NVMe SSD

#mdadm —create —verbose —assume-clean /dev/md0 —level=1 —raid-devices=2 /dev/nvme[0-1]n1

Чтобы не инициализировать массивы. Для обоих уровней RAID 1 и 6 это допустимо. Все может работать и без инициализации, если это новый массив. Более того, инициализация массива SSD при создании — это пустая трата ресурса TBW. Мы используем TRIM/DISCARD где возможно на собранных массивах SSD чтобы их «инициализировать».

У массивов SSD RAID 1 DISCARD поддерживается из коробки.

У массивов SSD RAID 6 DISCARD надо включать в параметрах модуля ядра.

Это стоит делать только в том случае, когда вообще все SSD используемые в массивах уровней 4/5/6 в этой системе имеют работающую поддержку discard_zeroes_data. Иногда попадаются странные накопители, которые сообщают ядру о поддержке этой функции, но, по-факту, ее нет, или функция работает не всегда. На данный момент поддержка есть практически везде, однако, старые накопители и прошивки с ошибками встречаются. По этой причине поддержка DISCARD по-умолчанию выключена для RAID 6.

Внимание, следующая команда уничтожит все данные на NVMe накопителях «инициализировав» массив «нулями».

Если что-то пошло не так, то попробуйте указать шаг.

#blkdiscard —step 65536 /dev/md0

SATA SSD

#mdadm —create —verbose —assume-clean /dev/md1 —level=1 —raid-devices=6 /dev/sd[a-f]1
#blkdiscard /dev/md1
#mdadm —create —verbose —assume-clean /dev/md2 —chunk-size=512 —level=6 —raid-devices=6 /dev/sd[a-f]2

Увеличение chunk-size позитивно влияет на скорость случайного чтения блоками до chunk-size включительно. Происходит это потому, что одна операция соответствующего размера или меньше может быть полностью выполнена на одном устройстве. Поэтому, IOPS от всех устройств суммируется. По статистике 99% IO не превышает 512K.

У RAID 6 IOPS на запись всегда меньше или равно IOPS у одного накопителя. Когда как на случайное чтение IOPS может быть больше такового у одного накопителя в несколько раз, и тут размер блока имеет ключевое значение.
Автор не видит смысла в попытках оптимизировать параметр который плох у RAID 6 by-design и вместо этого оптимизирует то, в чем RAID 6 показывает себя хорошо.
Плохую случайную запись RAID 6 мы будем компенсировать кэшем на NVMe и трюками с thin-provisioning.

Мы пока не включили DISCARD для RAID 6. Так что «инициализировать» этот массив пока не будем. Сделаем это позже, — после установки ОС.

SATA HDD

#mdadm —create —verbose —assume-clean /dev/md3 —chunk-size=512 —level=6 —raid-devices=8 /dev/sd[g-n]1

LVM на NVMe RAID

Для скорости мы хотим разместить корневую ФС на NVMe RAID 1 который /dev/md0.
Тем не менее, этот быстрый массив нам еще понадобится для других нужд, таких как swap, метаданные и кэш LVM-cache и метаданные LVM-thin, потому, на этом массиве мы создадим LVM VG.

#pvcreate /dev/md0
#vgcreate root /dev/md0

Создадим раздел для корневой ФС.

#lvcreate -L 128G —name root root

Создадим раздел для подкачки по размеру оперативной памяти.

#lvcreate -L 32G —name swap root

Установка ОС

Итого, у нас есть все необходимое, чтобы установить систему.

Запускаем мастер установки системы из окружения Ubuntu Live. Обычная установка. Только на этапе выбора дисков для установки нужно указать следующее:

  • /dev/md1, — точка монтирования /boot, ФС — BTRFS
  • /dev/root/root (a.k.a /dev/mapper/root-root), — точка монтирования / (корень), ФС — BTRFS
  • /dev/root/swap (a.k.a /dev/mapper/root-swap), — использовать как раздел подкачки
  • Загрузчик установить на /dev/sda

Установка завершится модальным диалоговым окном сообщающем об ошибке установки загрузчика. К сожалению, выйти из этого диалога штатными средствами и продолжить установку не получится. Делаем логаут из системы и снова логинимся, попадая в чистый рабочий стол Ubuntu Live. Открываем терминал, и снова:

Создаем chroot окружение, чтобы продолжить установку:

#mkdir /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@ /dev/mapper/root-root /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@home /dev/mapper/root-root /mnt/chroot/home
#mount -o defaults,space_cache,noatime,nodiratime,discard /dev/md1 /mnt/chroot/boot
#mount —bind /proc /mnt/chroot/proc
#mount —bind /sys /mnt/chroot/sys
#mount —bind /dev /mnt/chroot/dev

Настроим сеть и hostname в chroot:

#cat /etc/hostname >/mnt/chroot/etc/hostname
#cat /etc/hosts >/mnt/chroot/etc/hosts
#cat /etc/resolv.conf >/mnt/chroot/etc/resolv.conf

Заходим в chroot окружение:

#chroot /mnt/chroot

Первым делом доставим пакеты:

apt-get install —reinstall mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc debsums hdparm

Проверим и исправим все пакеты которые криво установились из-за незаконченной установки системы:

#CORRUPTED_PACKAGES=$(debsums -s 2>&1 | awk ‘‘ | uniq)
#apt-get install —reinstall $CORRUPTED_PACKAGES

Если что-то не срослось, возможно, вам понадобится перед этим подредактировать /etc/apt/sources.list

Поправим параметры для модуля RAID 6 чтобы включить TRIM/DISCARD:

#cat >/etc/modprobe.d/raid456.conf << EOF
options raid456 devices_handle_discard_safely=1
EOF

Немного поднастроим наши массивы:

#cat >/etc/udev/rules.d/60-md.rules << EOF
SUBSYSTEM==»block», KERNEL==»md*», ACTION==»change», TEST==»md/stripe_cache_size», ATTR=»32768″
SUBSYSTEM==»block», KERNEL==»md*», ACTION==»change», TEST==»md/sync_speed_min», ATTR=»48000″
SUBSYSTEM==»block», KERNEL==»md*», ACTION==»change», TEST==»md/sync_speed_max», ATTR=»300000″
EOF
#cat >/etc/udev/rules.d/62-hdparm.rules << EOF
SUBSYSTEM==»block», ACTION==»add|change», KERNEL==»sd[a-z]», ATTR==»1″, RUN+=»/sbin/hdparm -B 254 /dev/%k»
EOF
#cat >/etc/udev/rules.d/63-blockdev.rules << EOF
SUBSYSTEM==»block», ACTION==»add|change», KERNEL==»sd[a-z]», ATTR==»1″, RUN+=»/sbin/blockdev —setra 1024 /dev/%k»
SUBSYSTEM==»block», ACTION==»add|change», KERNEL==»sd[a-z]», ATTR==»0″, RUN+=»/sbin/blockdev —setra 0 /dev/%k»
SUBSYSTEM==»block», ACTION==»add|change», KERNEL==»nvme[0-9]n1″, RUN+=»/sbin/blockdev —setra 0 /dev/%k»
SUBSYSTEM==»block», ACTION==»add|change», KERNEL==»dm-*», ATTR==»0″, RUN+=»/sbin/blockdev —setra 0 /dev/%k»
SUBSYSTEM==»block», ACTION==»add|change», KERNEL==»md*», RUN+=»/sbin/blockdev —setra 0 /dev/%k»

Мы создали набор udev правил которые будут делать следующее:

  • Выставлять адекватный для 2020-ого года размер кэша блоков для RAID 6. Значение по-умолчанию, кажется, не менялось со времен создания Linux, и уже давно не адекватно.
  • Резервировать на время проверок/синхронизаций массивов минимум IO. Это нужно, чтобы ваши массивы не застревали в состоянии вечной синхронизации под нагрузкой.
  • Ограничивать на время проверок/синхронизаций массивов максимум IO. Это нужно, чтобы синхронизация/проверка SSD RAID-ов не прожарила ваши накопители до хрустящей корочки. Особенно актуально для NVMe. ( Помните про радиатор? Я ведь не шутил. )
  • Запрещать через APM дискам останавливать вращение шпинделя (HDD) и устанавливать таймаут для сна контроллеров дисков на 7 часов. Можно совсем отключить APM если ваши диски это умеют (-B 255). Со значением по-умолчанию диски будут останавливаться через пять секунд. Потом ОС захочет сбросить дисковый кэш, диски раскрутятся снова, и, все по-новой. У дисков ограничено максимальное число раскручиваний шпинделя. Такой нехитрый цикл по-умолчанию может легко убить ваши диски за пару лет. Этим страдают не все диски, но, наши-то «ноутбучные», с соответствующими настройками по-умолчанию, которые делают из RAID-а кривое подобие mini-MAID-а.
  • Устанавливать readahead на дисках (вращающихся) в 1 мегабайт — два последовательных блока/chunk RAID 6
  • Выключать readahead на SATA SSD
  • Выключать readahead на NVMe SSD
  • Выключать readahead на всех LVM томах собранных из SSD.
  • Выключать readahead на всех RAID массивах.

#cat >/etc/fstab << EOF
# /etc/fstab: static file system information.
#
# Use ‘blkid’ to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
# file-system mount-point type options dump pass
/dev/mapper/root-root / btrfs defaults,space_cache,noatime,nodiratime,discard,subvol=@ 0 1
UUID=$(blkid -o value -s UUID /dev/md1) /boot btrfs defaults,space_cache,noatime,nodiratime,discard 0 2
/dev/mapper/root-root /home btrfs defaults,space_cache,noatime,nodiratime,discard,subvol=@home 0 2
/dev/mapper/root-swap none swap sw 0 0
EOF

Раздел /boot мы будем искать по UUID т.к. именование массивов теоретически может измениться.

Остальные разделы мы будем искать по LVM именам в нотации /dev/mapper/vg-lv, т.к. они достаточно уникально идентифицируют разделы.

Не используем UUID для LVM т.к. UUID у LVM томов и их снапшотов может совпадать.

Да. Именно так. Особенность BTRFS. Эту ФС можно монтировать несколько раз с разными subvol.

В следствии этой-же особенности рекомендую никогда не создавать LVM снапшоты активных BTRFS томов. Можете получить сюрприз при перезагрузке.

Перегенерируем конфиг mdadm:

#/usr/share/mdadm/mkconf | sed ‘s/#DEVICE/DEVICE/g’ >/etc/mdadm/mdadm.conf

Подкорректируем настройки LVM:

#cat >>/etc/lvm/lvmlocal.conf << EOF

activation <
thin_pool_autoextend_threshold=90
thin_pool_autoextend_percent=5
>
allocation <
cache_pool_max_chunks=2097152
>
devices <
global_filter=[«r|^/dev/.*_corig$|»,»r|^/dev/.*_cdata$|»,»r|^/dev/.*_cmeta$|»,»r|^/dev/.*gpv$|»,»r|^/dev/images/.*$|»,»r|^/dev/mapper/images.*$|»,»r|^/dev/backup/.*$|»,»r|^/dev/mapper/backup.*$|»]
issue_discards=1
>
EOF

Мы включили автоматическое расширение пулов LVM thin по достижении 90% занятого места на 5% от объема.

Мы увеличили максимальное количество блоков кэша для LVM cache.

Мы запретили LVM искать LVM тома (PV) на:

  • устройствах содержащих LVM cache (cdata)
  • устройствах кэшированных при помощи LVM cache в обход кэша (<lv_name>_corig). При этом само кэшированное устройство все равно будет просканировано через кэш (просто <lv_name>).
  • устройствах содержащих метаданные LVM cache (cmeta)
  • всех устройствах в VG с названием images. Тут у нас будут образы дисков виртуальных машин, и, мы не хотим чтобы LVM на хосте активировал тома принадлежащие гостевой ОС.
  • всех устройствах в VG с названием backup. Тут у нас будут резервные копии образов виртуальных машин.
  • всех устройствах имя которых заканчивается на «gpv» ( guest physical volume )

Обновим образ initramfs:

#update-initramfs -u -k all

Установим и сконфигурируем grub:

#apt-get install grub-pc
#apt-get purge os-prober
#dpkg-reconfigure grub-pc

За излишнюю самостоятельность и шаловливые ручки.

Он не работает корректно если один из RAID-ов находится в деградированном состоянии. Он пытается искать ОС на разделах, которые используются в виртуальных машинах работающих на этом железе.

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

На этом мы завершили начальную установку. Пришло время перезагрузиться в только что установленную ОС. Не забудьте вынуть загрузочный Live CD/USB.

В качестве устройства для загрузки выбираем любой из SATA SSD.

LVM на SATA SSD

К этому моменту мы уже загрузились в новую ОС, настроили сеть, apt, открыли эмулятор терминала, и запустили:

«Инициализируем» массив из SATA SSD:

Если не прокатило, то пробуем:

#blkdiscard —step 65536 /dev/md2
Создаем LVM VG на SATA SSD:

#pvcreate /dev/md2
#vgcreate data /dev/md2

В самом деле, у нас уже есть VG с именем root. Почему бы не добавить все в одну VG?

Если в VG есть несколько PV, то для корректной активации VG все PV должны присутствовать (online). Исключением является LVM RAID, который мы намеренно не используем.

Мы очень хотим, чтобы при отвале (читай потере данных) на любом из RAID 6 массивов операционная система загрузилась штатно и дала нам возможность решить проблему.

Для этого, на первом уровне абстракции мы будем изолировать каждый тип физического «носителя» в отдельную VG.

Если по-научному, то разные RAID массивы относятся к разным «доменам надежности». Не стоит создавать для них дополнительную общую точку отказа, запихивая в одну VG.

Наличие LVM на «железном» уровне позволит нам произвольно нарезать кусочки разных RAID массивов по-разному их комбинируя. Например, — запустить одновременно bcache + LVM thin, bcache + BTRFS, LVM cache + LVM thin, сложную конфигурацию ZFS с кэшами или любую другую адскую смесь, чтобы все это пощупать и сравнить.

На «железном» уровне мы ничего, кроме старых-добрых «толстых» LVM-томов, использовать не будем. Исключением из этого правила, возможно, будет раздел для резервного копирования.

Думаю, к этому моменту, многие читатели уже начали что-то подозревать касательно матрешки.

LVM на SATA HDD

#pvcreate —metadatasize 64m /dev/md3
#vgcreate backup /dev/md3

Настройка LVM cache

Создадим LV на NVMe RAID 1 чтобы использовать его в качестве кэширующего устройства.

#lvcreate -L 70871154688B —name cache root

Дело в том, что у наших NVMe SSD тоже есть SLC кэш. 4 гигабайта «бесплатного» и 18 гигабайт динамического за счет свободного пространства занимаемого в 3-bit MLC. По-исчерпании этого кэша NVMe SSD станут не на много быстрее нашего SATA SSD с кэшем. Собственно, по этой причине нам нет смысла делать LVM cache раздел сильно больше двукратного объема SLC кэша NVMe накопителя. Для используемых NVMe накопителей автор считает разумным сделать 32-64 гигабайта кэша.

Приведенный размер раздела необходим для организации 64 гигабайт кэша, размещения метаданнных кэша и резервной копии метаданных.

Дополнительно замечу, что после грязного выключения системы LVM пометит весь кэш как грязный и будет синхронизировать заново. Более того, это будет повторяться при каждом использовании lvchange на этом устройстве до новой перезагрузки системы. Потому, рекомендую сразу пересоздать кэш соответствующим скриптом.

Создадим LV на SATA RAID 6 чтобы использовать его в качестве кэшируемого устройства.

#lvcreate -L 3298543271936B —name cache data

Создадим новую VG для кэширования.

#pvcreate /dev/root/cache
#pvcreate /dev/data/cache
#vgcreate cache /dev/root/cache /dev/data/cache

Создадим LV на кэшируемом устройстве.

#lvcreate -L 3298539077632B —name cachedata cache /dev/data/cache

Тут мы сразу заняли все свободное место на /dev/data/cache чтобы все остальные нужные разделы создавались сразу на /dev/root/cache. Если у вас что-то создалось не там, можно переместить при помощи pvmove.

Создадим и включим кэш:

#lvcreate -y -L 64G -n cache cache /dev/root/cache
#lvcreate -y -L 1G -n cachemeta cache /dev/root/cache
#lvconvert -y —type cache-pool —cachemode writeback —chunksize 64k —poolmetadata cache/cachemeta cache/cache
#lvconvert -y —type cache —cachepool cache/cache cache/cachedata

Методом практических экспериментов автору удалось выяснить, что наилучший результат достигается если размер блока LVM cache совпадает с размером блока LVM thin. При этом, чем меньше размер, тем лучше себя показывает конфигурация на случайной записи.

64к — это минимальный размер блока допустимый для LVM thin.

Да. Этот тип кэша откладывает синхронизацию записи на кэшируемое устройство. Это приводит к тому, что, в случае потери кэша, можно потерять данные на кэшируемом устройстве. Позже автор расскажет, какие меры, помимо NVMe RAID 1 можно предпринять, чтобы компенсировать этот риск.

Данный тип кэша выбран намерено, чтобы компенсировать низкую производительность RAID 6 на случайной записи.

Проверим, что у нас получилось:

#lvs -a -o lv_name,lv_size,devices —units B cache
LV LSize Devices
[cache] 68719476736B cache_cdata(0)
[cache_cdata] 68719476736B /dev/root/cache(0)
[cache_cmeta] 1073741824B /dev/root/cache(16384)
cachedata 3298539077632B cachedata_corig(0)
[cachedata_corig] 3298539077632B /dev/data/cache(0)
[lvol0_pmspare] 1073741824B /dev/root/cache(16640)

На /dev/data/cache должен располагаться только [cachedata_corig]. Если что-то не так, то используйте pvmove.

Отключить кэш при необходимости можно одной командой:

#lvconvert -y —uncache cache/cachedata

Это делается on-line. LVM просто синхронизирует кэш на диск, удалит его и переименует cachedata_corig обратно в cachedata.

Настройка LVM thin

Приблизительно оценим сколько места нам потребуется для метаданных LVM thin:

#thin_metadata_size —block-size=64k —pool-size=6terabytes —max-thins=100000 -u bytes
thin_metadata_size — 3385794560 bytes estimated metadata area size for «—block-size=64kibibytes —pool-size=6terabytes —max-thins=100000»

Округлим до 4х гигабайт: 4294967296B

Умножим на два и прибавим 4194304B для метаданных LVM PV: 8594128896B
Создадим отдельный раздел на NVMe RAID 1 чтобы разметисть на нем метаданные LVM thin и их резервную копию:

#lvcreate -L 8594128896B —name images root

Тут может возникнуть вопрос, зачем размещать метаданные LVM thin отдельно, если они все равно будут кэшироваться на NVMe и будут работать быстро.

Скорость тут хоть и является важной, но далеко не основной причиной. Все дело в том, что кэш, это точка отказа. С ним может что-то случиться, и, если метаданные LVM thin будут кэшированы, это приведет к полной потере всего. Без целых метаданных собрать тонкие тома будет практически невозможно.

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

Более того, если ранее был сделан мгновенный снимок тонкого тома, и, после этого, кэш был хотябы один раз полностью синхронизирован, то, в силу особенностей внутреннего устройства LVM thin, целостность снимка будет гарантирована в случае утери кэша.

Создадим новую VG которая будет отвечать за thin-provisioning:

#pvcreate /dev/root/images
#pvcreate /dev/cache/cachedata
#vgcreate images /dev/root/images /dev/cache/cachedata
Создадим пул:

#lvcreate -L 274877906944B —poolmetadataspare y —poolmetadatasize 4294967296B —chunksize 64k -Z y -T images/thin-pool

Переместим LV на соответствующие PV:

#pvmove -n images/thin-pool_tdata /dev/root/images /dev/cache/cachedata
#pvmove -n images/lvol0_pmspare /dev/cache/cachedata /dev/root/images
#pvmove -n images/thin-pool_tmeta /dev/cache/cachedata /dev/root/images

Проверим:

#lvs -a -o lv_name,lv_size,devices —units B images
LV LSize Devices
[lvol0_pmspare] 4294967296B /dev/root/images(0)
thin-pool 274877906944B thin-pool_tdata(0)
[thin-pool_tdata] 274877906944B /dev/cache/cachedata(0)
[thin-pool_tmeta] 4294967296B /dev/root/images(1024)

Создадим тонкий том для тестов:

#lvcreate -V 64G —thin-pool thin-pool —name test images

Поставим пакеты для тестов и наблюдения:

#apt-get install sysstat fio

Вот так можно наблюдать за поведением нашей конфигурации хранилища в реальном времени:

#watch ‘lvs —rows —reportformat basic —quiet -ocache_dirty_blocks,cache_settings cache/cachedata && (lvdisplay cache/cachedata | grep Cache) && (sar -p -d 2 1 | grep -E «sd|nvme|DEV|md1|md2|md3|md0» | grep -v Average | sort)’

Вот так можно протестировать нашу конфигурацию:

#fio —loops=1 —size=64G —runtime=4 —filename=/dev/images/test —stonewall —ioengine=libaio —direct=1 \
—name=4kQD32read —bs=4k —iodepth=32 —rw=randread \
—name=8kQD32read —bs=8k —iodepth=32 —rw=randread \
—name=16kQD32read —bs=16k —iodepth=32 —rw=randread \
—name=32KQD32read —bs=32k —iodepth=32 —rw=randread \
—name=64KQD32read —bs=64k —iodepth=32 —rw=randread \
—name=128KQD32read —bs=128k —iodepth=32 —rw=randread \
—name=256KQD32read —bs=256k —iodepth=32 —rw=randread \
—name=512KQD32read —bs=512k —iodepth=32 —rw=randread \
—name=4Kread —bs=4k —rw=read \
—name=8Kread —bs=8k —rw=read \
—name=16Kread —bs=16k —rw=read \
—name=32Kread —bs=32k —rw=read \
—name=64Kread —bs=64k —rw=read \
—name=128Kread —bs=128k —rw=read \
—name=256Kread —bs=256k —rw=read \
—name=512Kread —bs=512k —rw=read \
—name=Seqread —bs=1m —rw=read \
—name=Longread —bs=8m —rw=read \
—name=Longwrite —bs=8m —rw=write \
—name=Seqwrite —bs=1m —rw=write \
—name=512Kwrite —bs=512k —rw=write \
—name=256Kwrite —bs=256k —rw=write \
—name=128Kwrite —bs=128k —rw=write \
—name=64Kwrite —bs=64k —rw=write \
—name=32Kwrite —bs=32k —rw=write \
—name=16Kwrite —bs=16k —rw=write \
—name=8Kwrite —bs=8k —rw=write \
—name=4Kwrite —bs=4k —rw=write \
—name=512KQD32write —bs=512k —iodepth=32 —rw=randwrite \
—name=256KQD32write —bs=256k —iodepth=32 —rw=randwrite \
—name=128KQD32write —bs=128k —iodepth=32 —rw=randwrite \
—name=64KQD32write —bs=64k —iodepth=32 —rw=randwrite \
—name=32KQD32write —bs=32k —iodepth=32 —rw=randwrite \
—name=16KQD32write —bs=16k —iodepth=32 —rw=randwrite \
—name=8KQD32write —bs=8k —iodepth=32 —rw=randwrite \
—name=4kQD32write —bs=4k —iodepth=32 —rw=randwrite \
| grep -E ‘read|write|test’ | grep -v ioengine

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

Помимо прочего, рекомендую замерить скорость на уже заполненном тонком томе, с которого только что был сделан снапшот. Автор имел возможность наблюдать, как случайная запись резко ускоряется сразу после создания первого снапшота, особенно, когда кэш еще не полностью заполнен. Происходит это благодаря copy-on-write семантике записи, выравниваню блоков кэша и тонкого тома, и тому, что случайная запись на RAID 6 преврящается в случайное чтение с RAID 6 с последующей записью в кэш. В нашей же конфигурации случайное чтение с RAID 6 до 6ти раз (число SATA SSD в массиве) быстрее записи. Т.к. блоки для CoW выделяются последовательно из тонкого пула, то запись, по большей части, еще и превращается в последовательную.

Обе эти особенности можно выгодно использовать.

Кэш-«когерентные» снапшоты

Для уменьшения риска потери данных в случае повреждения/потери кэша автор предлагает ввести практику ротации снапшотов гарантирующую их целостность в этом случае.

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

Следующий цикл ротации снапшотов дает гарантию целостности данных внутри снапшотов в случае утери кэша:

  1. Для каждого тонкого тома с именем <имя> создаем снапшот с именем <имя>.cached
  2. Установим migration threshold на разумное высокое значение: #lvchange —quiet —cachesettings «migration_threshold=16384» cache/cachedata
  3. В цикле проверяем количество грязных блоков в кэше: #lvs —rows —reportformat basic —quiet -ocache_dirty_blocks cache/cachedata | awk ‘‘ пока не получим ноль. Если ноля нет слишком долго, его можно создать временно переведя кэш в writethrough режим. Однако, учитывая скоростные характеристики наших массивов SATA и NVMe SSD, а также, их ресурс TBW, вы либо сможете достаточно быстро поймать момент и без изменения режима кэша, либо ваше железо полностью скушает весь свой ресурс за несколько дней. Из-за ограничений ресурса система в принципе не способна находиться под 100% нагрузкой на запись постоянно. Наши NVMe SSD под 100% нагрузкой на запись полностью израсходуют ресурс за 3-4 дня. SATA SSD проживут всего-то раза в два дольше. Потому, мы будем считать, что большая часть нагрузки идет на чтение, а на запись у нас, — относительно кратковременные всплески крайне высокой активности в сочетании с низкой нагрузкой в среднем.
  4. Как только поймали (или сделали) нолик — переименовываем <имя>.cached в <имя>.committed. Старый <имя>.committed при этом удаляем.
  5. Опционально, если кэш заполнен на 100%, его можно пересоздать скриптом, таким образом очистив. С полупустым кэшем система работает гораздо быстрее на запись.
  6. Установим migration threshold на ноль: #lvchange —quiet —cachesettings «migration_threshold=0» cache/cachedata Это временно запретит синхронизировать кэш на основной носитель.
  7. Ждем, пока в кэше накопится достаточно много изменений #lvs —rows —reportformat basic —quiet -ocache_dirty_blocks cache/cachedata | awk ‘‘ или сработает таймер.
  8. Повторяем заново.

Все дело в том, что в реальной практике «случайная» запись на самом деле не совсем случайна. Если мы записали что-то в сектор размером 4 килобайта, велика вероятность того, что ближайшую пару минут будет сделана запись в этот-же или один из соседних (+- 32K) секторов.

Выставляя migration threshold в ноль мы откладываем синхронизацию записи на SATA SSD и агрегируем несколько изменений одного блока 64K в кэше. Таким образом заметно экономится ресурс SATA SSD.

К сожалению, автор считает себя недостаточно компетентным по части разработки bash скриптов ибо является на 100% самоучкой и практирует «google»-driven development, потому считает, что тот страшный код, который выходит из под его рук, лучше не использовать никому другому.

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

Подобная нехитрая схема ротации снапшотов позволит нам не только постоянно иметь один полностью синхронизированный на SATA SSD снапшот, но и позволит при помощи утилиты thin_delta узнать, какие блоки были изменены после его создания, и, таким образом, локализовать повреждения на основных томах, многократно упрощая восстановление.

TRIM/DISCARD в libvirt/KVM

Т.к. хранилище данных будет использоваться для KVM под управлением libvirt, то было бы неплохо научить наши VM не только занимать свободное место, но и освобождать уже ненужное.

Это делается посредством эмуляции поддержки TRIM/DISCARD на виртуальных дисках. Для этого надо изменить тип контроллера на virtio-scsi и подредактировать xml.

#virsh edit vmname
<disk type=’block’ device=’disk’>
<driver name=’qemu’ type=’raw’ cache=’writethrough’ io=’threads’ discard=’unmap’/>
<source dev=’/dev/images/vmname’/>
<backingStore/>
<target dev=’sda’ bus=’scsi’/>
<alias name=’scsi0-0-0-0’/>
<address type=’drive’ controller=’0′ bus=’0′ target=’0′ unit=’0’/>
</disk>

<controller type=’scsi’ index=’0′ model=’virtio-scsi’>
<alias name=’scsi0’/>
<address type=’pci’ domain=’0x0000′ bus=’0x04′ slot=’0x00′ function=’0x0’/>
</controller>

Подобные DISCARDы из гостевых ОС корректно обрабатываются LVMом, и блоки корректно освобождаются как в кэше, так и в тонком пуле. В нашем случае, это происходит, в основном, отложенно, при удалении очередного снапшота.

Резервное копирование BTRFS

Использовать готовые скрипты с крайней осторожностью и на свой страх и риск. Автор писал этот код сам и исключительно для себя. Уверен, что у многих опытных пользователей Linux имеются подобные костыли наработки, и копировать чужие не понадобится.

Создадим том на резервном устройстве:

#lvcreate -L 256G —name backup backup

Отформатируем в BTRFS:

Создадим точки монтирования и примонтируем корневые подразделы ФС:

#mkdir /backup
#mkdir /backup/btrfs
#mkdir /backup/btrfs/root
#mkdir /backup/btrfs/back
#ln -s /boot /backup/btrfs
# cat >>/etc/fstab << EOF

/dev/mapper/root-root /backup/btrfs/root btrfs defaults,space_cache,noatime,nodiratime 0 2
/dev/mapper/backup-backup /backup/btrfs/back btrfs defaults,space_cache,noatime,nodiratime 0 2
EOF
#mount -a
#update-initramfs -u
#update-grub

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

#mkdir /backup/btrfs/back/remote
#mkdir /backup/btrfs/back/remote/root
#mkdir /backup/btrfs/back/remote/boot

Создадим каталог для скриптов резервного копирования:

#cat >/root/btrfs-backup/btrfs-backup.sh << EOF
#!/bin/bash
PATH=»/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin»

SCRIPT_FILE=»$(realpath $0)»
SCRIPT_DIR=»$(dirname $SCRIPT_FILE)»
SCRIPT_NAME=»$(basename -s .sh $SCRIPT_FILE)»

LOCK_FILE=»/dev/shm/$SCRIPT_NAME.lock»
DATE_PREFIX=’%Y-%m-%d’
DATE_FORMAT=$DATE_PREFIX’-%H-%M-%S’
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]’
BASE_SUFFIX=».@base»
PEND_SUFFIX=».@pend»
SNAP_SUFFIX=».@snap»
MOUNTS=»/backup/btrfs/»
BACKUPS=»/backup/btrfs/back/remote/»

function terminate ()
<
echo «$1» >&2
exit 1
>

function wait_lock()
<
flock 98
>

function wait_lock_or_terminate()
<
echo «Wating for lock. »
wait_lock || terminate «Failed to get lock. Exiting. »
echo «Got lock. »
>

function suffix()
<
FORMATTED_DATE=$(date +»$DATE_FORMAT»)
echo «$SNAP_SUFFIX.$FORMATTED_DATE»
>

function filter()
<
FORMATTED_DATE=$(date —date=»$1″ +»$DATE_PREFIX»)
echo «$SNAP_SUFFIX.$FORMATTED_DATE»
>

function backup()
<
SOURCE_PATH=»$MOUNTS$1″
TARGET_PATH=»$BACKUPS$1″
SOURCE_BASE_PATH=»$MOUNTS$1$BASE_SUFFIX»
TARGET_BASE_PATH=»$BACKUPS$1$BASE_SUFFIX»
TARGET_BASE_DIR=»$(dirname $TARGET_BASE_PATH)»
SOURCE_PEND_PATH=»$MOUNTS$1$PEND_SUFFIX»
TARGET_PEND_PATH=»$BACKUPS$1$PEND_SUFFIX»
if [ -d «$SOURCE_BASE_PATH» ]
then
echo «$SOURCE_BASE_PATH found»
else
echo «$SOURCE_BASE_PATH File not found creating snapshot of $SOURCE_PATH to $SOURCE_BASE_PATH»
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_BASE_PATH
sync
if [ -d «$TARGET_BASE_PATH» ]
then
echo «$TARGET_BASE_PATH found out of sync with source. removing. »
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
fi
fi
if [ -d «$TARGET_BASE_PATH» ]
then
echo «$TARGET_BASE_PATH found»
else
echo «$TARGET_BASE_PATH not found. Synching to $TARGET_BASE_DIR»
btrfs send $SOURCE_BASE_PATH | btrfs receive $TARGET_BASE_DIR
sync
fi
if [ -d «$SOURCE_PEND_PATH» ]
then
echo «$SOURCE_PEND_PATH found removing. »
btrfs subvolume delete -c $SOURCE_PEND_PATH
sync
fi
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_PEND_PATH
sync
if [ -d «$TARGET_PEND_PATH» ]
then
echo «$TARGET_PEND_PATH found removing. »
btrfs subvolume delete -c $TARGET_PEND_PATH
sync
fi
echo «Sending $SOURCE_PEND_PATH to $TARGET_PEND_PATH»
btrfs send -p $SOURCE_BASE_PATH $SOURCE_PEND_PATH | btrfs receive $TARGET_BASE_DIR
sync
TARGET_DATE_SUFFIX=$(suffix)
btrfs subvolume snapshot -r $TARGET_PEND_PATH «$TARGET_PATH$TARGET_DATE_SUFFIX»
sync
btrfs subvolume delete -c $SOURCE_BASE_PATH
sync
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
mv $SOURCE_PEND_PATH $SOURCE_BASE_PATH
mv $TARGET_PEND_PATH $TARGET_BASE_PATH
sync
>

function list()
<
LIST_TARGET_BASE_PATH=»$BACKUPS$1$BASE_SUFFIX»
LIST_TARGET_BASE_DIR=»$(dirname $LIST_TARGET_BASE_PATH)»
LIST_TARGET_BASE_NAME=»$(basename -s .$BASE_SUFFIX $LIST_TARGET_BASE_PATH)»
find «$LIST_TARGET_BASE_DIR» -maxdepth 1 -mindepth 1 -type d -printf «%f\n» | grep «$.$DATE_REGEX»
>

function remove()
<
REMOVE_TARGET_BASE_PATH=»$BACKUPS$1$BASE_SUFFIX»
REMOVE_TARGET_BASE_DIR=»$(dirname $REMOVE_TARGET_BASE_PATH)»
btrfs subvolume delete -c $REMOVE_TARGET_BASE_DIR/$2
sync
>

function removeall()
<
DATE_OFFSET=»$2″
FILTER=»$(filter «$DATE_OFFSET»)»
while read -r SNAPSHOT ; do
remove «$1» «$SNAPSHOT»
done < <(list «$1» | grep «$FILTER»)

case «$COMMAND» in
«—help»)
echo «Help»
;;
«suffix»)
suffix
;;
«filter»)
filter «$1»
;;
«backup»)
wait_lock_or_terminate
backup «$1»
;;
«list»)
list «$1»
;;
«remove»)
wait_lock_or_terminate
remove «$1» «$2»
;;
«removeall»)
wait_lock_or_terminate
removeall «$1» «$2»
;;
*)
echo «None..»
;;
esac
) 98>$LOCK_FILE

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

Еще один скрипт который запихнем в cron:

#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
PATH=»/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin»

SCRIPT_FILE=»$(realpath $0)»
SCRIPT_DIR=»$(dirname $SCRIPT_FILE)»
SCRIPT_NAME=»$(basename -s .sh $SCRIPT_FILE)»

BACKUP_SCRIPT=»$SCRIPT_DIR/btrfs-backup.sh»
RETENTION=»-60 day»
$BACKUP_SCRIPT backup root/@
$BACKUP_SCRIPT removeall root/@ «$RETENTION»
$BACKUP_SCRIPT backup root/@home
$BACKUP_SCRIPT removeall root/@home «$RETENTION»
$BACKUP_SCRIPT backup boot/
$BACKUP_SCRIPT removeall boot/ «$RETENTION»
EOF

Дадим коду права на выполнение:

#chmod +x /root/btrfs-backup/cron-daily.sh
#chmod +x /root/btrfs-backup/btrfs-backup.sh

Проверим и запихнем в крон:

#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup
#cat /var/log/syslog | grep btrfs-backup
#crontab -e
0 2 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup

Резервное копирование LVM thin

Создадим тонкий пул на резервном устройстве:

#lvcreate -L 274877906944B —poolmetadataspare y —poolmetadatasize 4294967296B —chunksize 64k -Z y -T backup/thin-pool

Установим ddrescue, т.к. скрипты будут использовать этот инструмент:

#apt-get install gddrescue

Создадим каталог для скриптов:

#cat >/root/lvm-thin-backup/lvm-thin-backup.sh << EOF
#!/bin/bash
PATH=»/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin»

SCRIPT_FILE=»$(realpath $0)»
SCRIPT_DIR=»$(dirname $SCRIPT_FILE)»
SCRIPT_NAME=»$(basename -s .sh $SCRIPT_FILE)»

LOCK_FILE=»/dev/shm/$SCRIPT_NAME.lock»
DATE_PREFIX=’%Y-%m-%d’
DATE_FORMAT=$DATE_PREFIX’-%H-%M-%S’
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]’
BASE_SUFFIX=».base»
PEND_SUFFIX=».pend»
SNAP_SUFFIX=».snap»
BACKUPS=»backup»
BACKUPS_POOL=»thin-pool»

function terminate ()
<
echo «$1» >&2
exit 1
>

function wait_lock()
<
flock 98
>

function wait_lock_or_terminate()
<
echo «Wating for lock. »
wait_lock || terminate «Failed to get lock. Exiting. »
echo «Got lock. »
>

function suffix()
<
FORMATTED_DATE=$(date +»$DATE_FORMAT»)
echo «$SNAP_SUFFIX.$FORMATTED_DATE»
>

function filter()
<
FORMATTED_DATE=$(date —date=»$1″ +»$DATE_PREFIX»)
echo «$SNAP_SUFFIX.$FORMATTED_DATE»
>

function read_thin_id <
lvs —rows —reportformat basic —quiet -othin_id «$1/$2» | awk ‘
>

function read_pool_lv <
lvs —rows —reportformat basic —quiet -opool_lv «$1/$2» | awk ‘
>

function read_lv_dm_path <
lvs —rows —reportformat basic —quiet -olv_dm_path «$1/$2» | awk ‘
>

function read_lv_active <
lvs —rows —reportformat basic —quiet -olv_active «$1/$2» | awk ‘
>

function read_lv_chunk_size <
lvs —rows —reportformat basic —quiet —units b —nosuffix -ochunk_size «$1/$2» | awk ‘
>

function read_lv_size <
lvs —rows —reportformat basic —quiet —units b —nosuffix -olv_size «$1/$2» | awk ‘
>

function activate_volume <
lvchange -ay -Ky «$1/$2»
>

function deactivate_volume <
lvchange -an «$1/$2»
>

function read_thin_metadata_snap <
dmsetup status «$1» | awk ‘
>

function thindiff()
<
DIFF_VG=»$1″
DIFF_SOURCE=»$2″
DIFF_TARGET=»$3″
DIFF_SOURCE_POOL=$(read_pool_lv $DIFF_VG $DIFF_SOURCE)
DIFF_TARGET_POOL=$(read_pool_lv $DIFF_VG $DIFF_TARGET)

if [ «$DIFF_SOURCE_POOL» == «» ]
then
(>&2 echo «Source LV is not thin.»)
exit 1
fi

if [ «$DIFF_TARGET_POOL» == «» ]
then
(>&2 echo «Target LV is not thin.»)
exit 1
fi

if [ «$DIFF_SOURCE_POOL» != «$DIFF_TARGET_POOL» ]
then
(>&2 echo «Source and target LVs belong to different thin pools.»)
exit 1
fi

DIFF_POOL_PATH=$(read_lv_dm_path $DIFF_VG $DIFF_SOURCE_POOL)
DIFF_SOURCE_ID=$(read_thin_id $DIFF_VG $DIFF_SOURCE)
DIFF_TARGET_ID=$(read_thin_id $DIFF_VG $DIFF_TARGET)
DIFF_POOL_PATH_TPOOL=»$DIFF_POOL_PATH-tpool»
DIFF_POOL_PATH_TMETA=»$DIFF_POOL_PATH»_tmeta
DIFF_POOL_METADATA_SNAP=$(read_thin_metadata_snap $DIFF_POOL_PATH_TPOOL)

if [ «$DIFF_POOL_METADATA_SNAP» != «-» ]
then
(>&2 echo «Thin pool metadata snapshot already exist. Assuming stale one. Will release metadata snapshot in 5 seconds.»)
sleep 5
dmsetup message $DIFF_POOL_PATH_TPOOL 0 release_metadata_snap
fi

dmsetup message $DIFF_POOL_PATH_TPOOL 0 reserve_metadata_snap
DIFF_POOL_METADATA_SNAP=$(read_thin_metadata_snap $DIFF_POOL_PATH_TPOOL)

if [ «$DIFF_POOL_METADATA_SNAP» == «-» ]
then
(>&2 echo «Failed to create thin pool metadata snapshot.»)
exit 1
fi

#We keep output in variable because metadata snapshot need to be released early.
DIFF_DATA=$(thin_delta -m$DIFF_POOL_METADATA_SNAP —snap1 $DIFF_SOURCE_ID —snap2 $DIFF_TARGET_ID $DIFF_POOL_PATH_TMETA)

dmsetup message $DIFF_POOL_PATH_TPOOL 0 release_metadata_snap

echo $»$DIFF_DATA» | grep -E ‘different|left_only|right_only’ | sed ‘s/</»/g’ | sed ‘s/ /»/g’ | awk -F’\»‘ ‘‘ | sed ‘s/different/copy/g’ | sed ‘s/left_only/copy/g’ | sed ‘s/right_only/discard/g’

function thinsync()
<
SYNC_VG=»$1″
SYNC_PEND=»$2″
SYNC_BASE=»$3″
SYNC_TARGET=»$4″
SYNC_PEND_POOL=$(read_pool_lv $SYNC_VG $SYNC_PEND)
SYNC_BLOCK_SIZE=$(read_lv_chunk_size $SYNC_VG $SYNC_PEND_POOL)
SYNC_PEND_PATH=$(read_lv_dm_path $SYNC_VG $SYNC_PEND)

activate_volume $SYNC_VG $SYNC_PEND

while read -r SYNC_ACTION SYNC_OFFSET SYNC_LENGTH ; do
SYNC_OFFSET_BYTES=$((SYNC_OFFSET * SYNC_BLOCK_SIZE))
SYNC_LENGTH_BYTES=$((SYNC_LENGTH * SYNC_BLOCK_SIZE))
if [ «$SYNC_ACTION» == «copy» ]
then
ddrescue —quiet —force —input-position=$SYNC_OFFSET_BYTES —output-position=$SYNC_OFFSET_BYTES —size=$SYNC_LENGTH_BYTES «$SYNC_PEND_PATH» «$SYNC_TARGET»
fi

if [ «$SYNC_ACTION» == «discard» ]
then
blkdiscard -o $SYNC_OFFSET_BYTES -l $SYNC_LENGTH_BYTES «$SYNC_TARGET»
fi
done < <(thindiff «$SYNC_VG» «$SYNC_PEND» «$SYNC_BASE»)
>

function discard_volume()
<
DISCARD_VG=»$1″
DISCARD_LV=»$2″
DISCARD_LV_PATH=$(read_lv_dm_path «$DISCARD_VG» «$DISCARD_LV»)
if [ «$DISCARD_LV_PATH» != «» ]
then
echo «$DISCARD_LV_PATH found»
else
echo «$DISCARD_LV not found in $DISCARD_VG»
exit 1
fi
DISCARD_LV_POOL=$(read_pool_lv $DISCARD_VG $DISCARD_LV)
DISCARD_LV_SIZE=$(read_lv_size «$DISCARD_VG» «$DISCARD_LV»)
lvremove -y —quiet «$DISCARD_LV_PATH» || exit 1
lvcreate —thin-pool «$DISCARD_LV_POOL» -V «$DISCARD_LV_SIZE»B —name «$DISCARD_LV» «$DISCARD_VG» || exit 1
>

function backup()
<
SOURCE_VG=»$1″
SOURCE_LV=»$2″
TARGET_VG=»$BACKUPS»
TARGET_LV=»$SOURCE_VG-$SOURCE_LV»
SOURCE_BASE_LV=»$SOURCE_LV$BASE_SUFFIX»
TARGET_BASE_LV=»$TARGET_LV$BASE_SUFFIX»
SOURCE_PEND_LV=»$SOURCE_LV$PEND_SUFFIX»
TARGET_PEND_LV=»$TARGET_LV$PEND_SUFFIX»
SOURCE_BASE_LV_PATH=$(read_lv_dm_path «$SOURCE_VG» «$SOURCE_BASE_LV»)
SOURCE_PEND_LV_PATH=$(read_lv_dm_path «$SOURCE_VG» «$SOURCE_PEND_LV»)
TARGET_BASE_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_BASE_LV»)
TARGET_PEND_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_PEND_LV»)

if [ «$SOURCE_BASE_LV_PATH» != «» ]
then
echo «$SOURCE_BASE_LV_PATH found»
else
echo «Source base not found creating snapshot of $SOURCE_VG/$SOURCE_LV to $SOURCE_VG/$SOURCE_BASE_LV»
lvcreate —quiet —snapshot —name «$SOURCE_BASE_LV» «$SOURCE_VG/$SOURCE_LV» || exit 1
SOURCE_BASE_LV_PATH=$(read_lv_dm_path «$SOURCE_VG» «$SOURCE_BASE_LV»)
activate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
echo «Discarding $SOURCE_BASE_LV_PATH as we need to bootstrap.»
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SOURCE_BASE_CHUNK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
discard_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
sync
if [ «$TARGET_BASE_LV_PATH» != «» ]
then
echo «$TARGET_BASE_LV_PATH found out of sync with source. removing. »
lvremove -y —quiet $TARGET_BASE_LV_PATH || exit 1
TARGET_BASE_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_BASE_LV»)
sync
fi
fi
SOURCE_BASE_SIZE=$(read_lv_size «$SOURCE_VG» «$SOURCE_BASE_LV»)
if [ «$TARGET_BASE_LV_PATH» != «» ]
then
echo «$TARGET_BASE_LV_PATH found»
else
echo «$TARGET_VG/$TARGET_LV not found. Creating empty volume.»
lvcreate —thin-pool «$BACKUPS_POOL» -V «$SOURCE_BASE_SIZE»B —name «$TARGET_BASE_LV» «$TARGET_VG» || exit 1
echo «Have to rebootstrap. Discarding source at $SOURCE_BASE_LV_PATH»
activate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SOURCE_BASE_CHUNK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
discard_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
TARGET_BASE_POOL=$(read_pool_lv $TARGET_VG $TARGET_BASE_LV)
TARGET_BASE_CHUNK_SIZE=$(read_lv_chunk_size $TARGET_VG $TARGET_BASE_POOL)
TARGET_BASE_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_BASE_LV»)
echo «Discarding target at $TARGET_BASE_LV_PATH»
discard_volume «$TARGET_VG» «$TARGET_BASE_LV»
sync
fi
if [ «$SOURCE_PEND_LV_PATH» != «» ]
then
echo «$SOURCE_PEND_LV_PATH found removing. »
lvremove -y —quiet «$SOURCE_PEND_LV_PATH» || exit 1
sync
fi
lvcreate —quiet —snapshot —name «$SOURCE_PEND_LV» «$SOURCE_VG/$SOURCE_LV» || exit 1
SOURCE_PEND_LV_PATH=$(read_lv_dm_path «$SOURCE_VG» «$SOURCE_PEND_LV»)
sync
if [ «$TARGET_PEND_LV_PATH» != «» ]
then
echo «$TARGET_PEND_LV_PATH found removing. »
lvremove -y —quiet $TARGET_PEND_LV_PATH
sync
fi
lvcreate —quiet —snapshot —name «$TARGET_PEND_LV» «$TARGET_VG/$TARGET_BASE_LV» || exit 1
TARGET_PEND_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_PEND_LV»)
SOURCE_PEND_LV_SIZE=$(read_lv_size «$SOURCE_VG» «$SOURCE_PEND_LV»)
lvresize -L «$SOURCE_PEND_LV_SIZE»B «$TARGET_PEND_LV_PATH»
activate_volume «$TARGET_VG» «$TARGET_PEND_LV»
echo «Synching $SOURCE_PEND_LV_PATH to $TARGET_PEND_LV_PATH»
thinsync «$SOURCE_VG» «$SOURCE_PEND_LV» «$SOURCE_BASE_LV» «$TARGET_PEND_LV_PATH» || exit 1
sync

TARGET_DATE_SUFFIX=$(suffix)
lvcreate —quiet —snapshot —name «$TARGET_LV$TARGET_DATE_SUFFIX» «$TARGET_VG/$TARGET_PEND_LV» || exit 1
sync
lvremove —quiet -y «$SOURCE_BASE_LV_PATH» || exit 1
sync
lvremove —quiet -y «$TARGET_BASE_LV_PATH» || exit 1
sync
lvrename -y «$SOURCE_VG/$SOURCE_PEND_LV» «$SOURCE_BASE_LV» || exit 1
lvrename -y «$TARGET_VG/$TARGET_PEND_LV» «$TARGET_BASE_LV» || exit 1
sync
deactivate_volume «$TARGET_VG» «$TARGET_BASE_LV»
deactivate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
>

function verify()
<
SOURCE_VG=»$1″
SOURCE_LV=»$2″
TARGET_VG=»$BACKUPS»
TARGET_LV=»$SOURCE_VG-$SOURCE_LV»
SOURCE_BASE_LV=»$SOURCE_LV$BASE_SUFFIX»
TARGET_BASE_LV=»$TARGET_LV$BASE_SUFFIX»
TARGET_BASE_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_BASE_LV»)
SOURCE_BASE_LV_PATH=$(read_lv_dm_path «$SOURCE_VG» «$SOURCE_BASE_LV»)

if [ «$SOURCE_BASE_LV_PATH» != «» ]
then
echo «$SOURCE_BASE_LV_PATH found»
else
echo «$SOURCE_BASE_LV_PATH not found»
exit 1
fi
if [ «$TARGET_BASE_LV_PATH» != «» ]
then
echo «$TARGET_BASE_LV_PATH found»
else
echo «$TARGET_BASE_LV_PATH not found»
exit 1
fi
activate_volume «$TARGET_VG» «$TARGET_BASE_LV»
activate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
echo Comparing «$SOURCE_BASE_LV_PATH» with «$TARGET_BASE_LV_PATH»
cmp «$SOURCE_BASE_LV_PATH» «$TARGET_BASE_LV_PATH»
echo Done.
deactivate_volume «$TARGET_VG» «$TARGET_BASE_LV»
deactivate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
>

function resync()
<
SOURCE_VG=»$1″
SOURCE_LV=»$2″
TARGET_VG=»$BACKUPS»
TARGET_LV=»$SOURCE_VG-$SOURCE_LV»
SOURCE_BASE_LV=»$SOURCE_LV$BASE_SUFFIX»
TARGET_BASE_LV=»$TARGET_LV$BASE_SUFFIX»
TARGET_BASE_LV_PATH=$(read_lv_dm_path «$TARGET_VG» «$TARGET_BASE_LV»)
SOURCE_BASE_LV_PATH=$(read_lv_dm_path «$SOURCE_VG» «$SOURCE_BASE_LV»)

if [ «$SOURCE_BASE_LV_PATH» != «» ]
then
echo «$SOURCE_BASE_LV_PATH found»
else
echo «$SOURCE_BASE_LV_PATH not found»
exit 1
fi
if [ «$TARGET_BASE_LV_PATH» != «» ]
then
echo «$TARGET_BASE_LV_PATH found»
else
echo «$TARGET_BASE_LV_PATH not found»
exit 1
fi
activate_volume «$TARGET_VG» «$TARGET_BASE_LV»
activate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SYNC_BLOCK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)

echo Syncronizing «$SOURCE_BASE_LV_PATH» to «$TARGET_BASE_LV_PATH»

CMP_OFFSET=0
while [[ «$CMP_OFFSET» != «» ]] ; do
CMP_MISMATCH=$(cmp -i «$CMP_OFFSET» «$SOURCE_BASE_LV_PATH» «$TARGET_BASE_LV_PATH» | grep differ | awk ‘‘ | sed ‘s/,//g’ )
if [[ «$CMP_MISMATCH» != «» ]] ; then
CMP_OFFSET=$(( CMP_MISMATCH + CMP_OFFSET ))
SYNC_OFFSET_BYTES=$(( ( CMP_OFFSET / SYNC_BLOCK_SIZE ) * SYNC_BLOCK_SIZE ))
SYNC_LENGTH_BYTES=$(( SYNC_BLOCK_SIZE ))
echo «Synching $SYNC_LENGTH_BYTES bytes at $SYNC_OFFSET_BYTES from $SOURCE_BASE_LV_PATH to $TARGET_BASE_LV_PATH»
ddrescue —quiet —force —input-position=$SYNC_OFFSET_BYTES —output-position=$SYNC_OFFSET_BYTES —size=$SYNC_LENGTH_BYTES «$SOURCE_BASE_LV_PATH» «$TARGET_BASE_LV_PATH»
else
CMP_OFFSET=»»
fi
done
echo Done.
deactivate_volume «$TARGET_VG» «$TARGET_BASE_LV»
deactivate_volume «$SOURCE_VG» «$SOURCE_BASE_LV»
>

function list()
<
LIST_SOURCE_VG=»$1″
LIST_SOURCE_LV=»$2″
LIST_TARGET_VG=»$BACKUPS»
LIST_TARGET_LV=»$LIST_SOURCE_VG-$LIST_SOURCE_LV»
LIST_TARGET_BASE_LV=»$LIST_TARGET_LV$SNAP_SUFFIX»
lvs -olv_name | grep «$LIST_TARGET_BASE_LV.$DATE_REGEX»
>

function remove()
<
REMOVE_TARGET_VG=»$BACKUPS»
REMOVE_TARGET_LV=»$1″
lvremove -y «$REMOVE_TARGET_VG/$REMOVE_TARGET_LV»
sync
>

function removeall()
<
DATE_OFFSET=»$3″
FILTER=»$(filter «$DATE_OFFSET»)»
while read -r SNAPSHOT ; do
remove «$SNAPSHOT»
done < <(list «$1» «$2» | grep «$FILTER»)

case «$COMMAND» in
«—help»)
echo «Help»
;;
«suffix»)
suffix
;;
«filter»)
filter «$1»
;;
«backup»)
wait_lock_or_terminate
backup «$1» «$2»
;;
«list»)
list «$1» «$2»
;;
«thindiff»)
thindiff «$1» «$2» «$3»
;;
«thinsync»)
thinsync «$1» «$2» «$3» «$4»
;;
«verify»)
wait_lock_or_terminate
verify «$1» «$2»
;;
«resync»)
wait_lock_or_terminate
resync «$1» «$2»
;;
«remove»)
wait_lock_or_terminate
remove «$1»
;;
«removeall»)
wait_lock_or_terminate
removeall «$1» «$2» «$3»
;;
*)
echo «None..»
;;
esac
) 98>$LOCK_FILE

Еще один скрипт, который мы запихнем в крон:

#cat >/root/lvm-thin-backup/cron-daily.sh << EOF
#!/bin/bash
PATH=»/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin»

SCRIPT_FILE=»$(realpath $0)»
SCRIPT_DIR=»$(dirname $SCRIPT_FILE)»
SCRIPT_NAME=»$(basename -s .sh $SCRIPT_FILE)»

BACKUP_SCRIPT=»$SCRIPT_DIR/lvm-thin-backup.sh»
RETENTION=»-60 days»

$BACKUP_SCRIPT backup images linux-dev
$BACKUP_SCRIPT backup images win8
$BACKUP_SCRIPT backup images win8-data
#etc

$BACKUP_SCRIPT removeall images linux-dev «$RETENTION»
$BACKUP_SCRIPT removeall images win8 «$RETENTION»
$BACKUP_SCRIPT removeall images win8-data «$RETENTION»
#etc

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

#chmod +x /root/lvm-thin-backup/cron-daily.sh
#chmod +x /root/lvm-thin-backup/lvm-thin-backup.sh

Проверим и запихнем в крон:

#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup
#cat /var/log/syslog | grep lvm-thin-backup
#crontab -e
0 3 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup

Первый запуск будет долгим, т.к. тонкие тома будут полностью синхронизированы копированием всего используемого пространства. Благодаря метаданным LVM thin мы знаем какие блоки используются на самом деле, так что, копироваться будут только реально используемые блоки тонких томов.

Последующие запуски будут копировать данные инкрементально благодаря отслеживанию изменений через метаданные LVM thin.

Посмотрим, что получилось:

#time /root/btrfs-backup/cron-daily.sh
real 0m2,967s
user 0m0,225s
sys 0m0,353s

#time /root/lvm-thin-backup/cron-daily.sh
real 1m2,710s
user 0m12,721s
sys 0m6,671s

#ls -al /backup/btrfs/back/remote/*
/backup/btrfs/back/remote/boot:
total 0
drwxr-xr-x 1 root root 1260 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 322 мар 26 02:00 .@base
drwxr-xr-x 1 root root 516 мар 6 09:39 .@snap.2020-03-06-09-39-37
drwxr-xr-x 1 root root 516 мар 6 09:39 .@snap.2020-03-06-09-39-57
.
/backup/btrfs/back/remote/root:
total 0
drwxr-xr-x 1 root root 2820 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 240 мар 26 09:11 @.@base
drwxr-xr-x 1 root root 22 мар 26 09:11 @home.@base
drwxr-xr-x 1 root root 22 мар 6 09:39 @home.@snap.2020-03-06-09-39-35
drwxr-xr-x 1 root root 22 мар 6 09:39 @home.@snap.2020-03-06-09-39-57
.
drwxr-xr-x 1 root root 240 мар 6 09:39 @.@snap.2020-03-06-09-39-26
drwxr-xr-x 1 root root 240 мар 6 09:39 @.@snap.2020-03-06-09-39-56
.

#lvs -olv_name,lv_size images && lvs -olv_name,lv_size backup
LV LSize
linux-dev 128,00g
linux-dev.base 128,00g
thin-pool 1,38t
win8 128,00g
win8-data 2,00t
win8-data.base 2,00t
win8.base 128,00g
LV LSize
backup 256,00g
images-linux-dev.base 128,00g
images-linux-dev.snap.2020-03-08-10-09-11 128,00g
images-linux-dev.snap.2020-03-08-10-09-25 128,00g
.
images-win8-data.base 2,00t
images-win8-data.snap.2020-03-16-14-11-55 2,00t
images-win8-data.snap.2020-03-16-14-19-50 2,00t
.
images-win8.base 128,00g
images-win8.snap.2020-03-17-04-51-46 128,00g
images-win8.snap.2020-03-18-03-02-49 128,00g
.
thin-pool <2,09t

Причем тут матрешки?

Скорее всего при том, что логические тома LVM LV могут быть физическими томами LVM PV для других VG. LVM может быть рекурсивен, как матрешки. Это дает LVM чрезвычайную гибкость.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *