Включение TRIM на (внешнем) SSD
Введение
Статья является адаптацией к реалиям ALT Linux статьи Включение TRIM на внешнем SSD на Raspberry Pi (eng) .
Теория взята из Как правильно активировать TRIM для вашего SSD в Linux (eng).
В отличие от жестких дисков (HDD), флэш-память NAND, которая лежит в основе SSD дисков, не может перезаписывать существующие данные. Это означает, что вы должны сначала удалить старые данные, прежде чем записывать новые. Флэш-память разделена на блоки, которые далее делятся на страницы. Минимальная единица записи — это страница, а наименьшая единица стирания — блок.
Данные можно записывать прямо на пустую страницу, но стирать можно только целые блоки. Поэтому, для того, чтобы освободить пространство, занятое удалёнными данными, все имеющиеся данные из одного блока должны быть сначала скопированы и записаны на пустые страницы нового блока. Только после этого данные в исходном блоке могут быть окончательно стерты, что делает блок готовым для записи новых данных.
Проблема в том, что со временем возникнет "куча" не полностью занятых страниц и быстродействие диска сильно упадёт. Это связано с тем, что при удалении файла операционная система просто помечает данные блоки как свободные, но не сообщает об этом контроллеру диска. И вне зависимости от оставшегося места, контроллер диска не сможет найти куда записать новые данные. Для решения этой проблемы и используется TRIM.
Что такое ТРИМ?
TRIM был придуман для решения этой проблемы. TRIM — это имя команды, которую операционная система может отправить, чтобы сообщить SSD, какие блоки в файловой системе свободны. SSD использует эту информацию для внутренней дефрагментации блоков и сохранения свободных страниц для быстрой и эффективной записи.
Файловая система | Опция discard | Поддержка fstrim | Замечания |
---|---|---|---|
ext4 | Yes | Yes | "discard, nodiscard(*)" [1] |
ext3 | Yes | Yes | |
Btfs | Yes | Yes | |
F2F2FS | Yes | Yes | |
JFS | Yes | Yes | [2] |
XFS | Yes | Yes | [3] |
NILFS2 | Yes | Yes | [4] |
NTFS-3G | No | Yes | начиная с версии 2015.3.14 [5] |
VFAT | Yes | Yes | fstrim поддерживается начиная с ядра 4.19 [6] |
ExFAT | Yes | Yes | fstrim поддерживается начиная с ядра 5.13, [7] |
Классический способ включения TRIM в Linux , это прописать в /etc/fstab опцию discard, например так (если корень находится на SSD диске):
UUID="6ff0461b-4796-4s0f-a8c0-1fs5f884a593 / ext4 discard,noatime 1 1
rootflags=discard
В файловой системе ext4 флаг discard также может быть установлен как опция монтирования по умолчанию для "внутренних дисков" с помощью tune2fs, например[1]:
# tune2fs -o discard /dev/sda1
Очистка ТРИМ
Использование опций монтирования по умолчанию вместо записи в /etc/fstab особенно полезно для внешних дисков, поскольку такой раздел будет монтироваться с опциями по умолчанию и на других машинах. Таким образом, нет необходимости редактировать /etc/fstab на каждой машине.
Пакет util-linux предоставляет fstrim.service и fstrim.timer файлы модулей systemd. Enabling таймера активирует службу еженедельно. Служба выполняет fstrim(8) на всех смонтированных файловых системах на устройствах, поддерживающих операцию discard.
Таймер полагается на метку времени /var/lib/systemd/timers/stamp-fstrim.timer (которую он создаст при первом вызове), чтобы узнать, прошла ли неделя с момента его последнего запуска. Поэтому нет необходимости беспокоиться о слишком частых вызовах, в стиле anacron.
Чтобы запросить активность и состояние блоков, смотрите journalctl. Чтобы изменить периодичность таймера или выполнените команду systemctl edit fstrim.timer или создайте файл /etc/systemd/system/timers.target.wants/fstrim.timer с заданной периодичностью (по умолчанию раз в неделю). fstrim.timer запускает fstrim, беря пути для разделов из /etc/fstab.
Альтернативный способ периодичной проверки, это установить пакет auto-fstrim и запустить anacron. Особенностью auto-fstrim является то, что он проверяет все смонтированные разделы, не обращая внимание есть ли они в /etc/fstab или нет, и запуск fstrim проходит ежедневно.
Непрерывный TRIM ведёт к некоторому замедлению файловых операций, так как после каждой из них выполняются операции по по очистке неиспользуемых блоков. Поэтому в большинстве дистрибутивах Linux советуют настроить периодический запуск fstrim.
Можно также самому очищать TRIM вручную с помощью команды fstrim время от времени, или после больших операций с диском.
Конкретный раздел:
fstrim -v /mnt/disk
Все смонтированные разделы:
fstrim -av
Поддерживает ли мой SSD TRIM
Для проверки, поддерживает ли ваш SSD диск TRIM, надо выполнить команду:
# fstrim -v путь_до_точки_монтирования_раздела
Например, если у вас раздел c SSD диска смонтирован в /mnt/arhiv, то при поддерживаемом TRIM вы увидите:
# fstrim -v /mnt/arhiv/
/mnt/arhiv/: 0 B (0 bytes) trimmed
Если диск не поддерживает TRIM, то вы увидите что-то подобное:
# fstrim -v /mnt/arhiv/
/mnt/arhiv: the discard operation is not supported
Ещё одним вариантом является запуск команды:
$ lsblk -Df
Если столбец DISC-GRAN или DISC-MAX имеют ненулевые значения, то раздел поддерживается TRIM.
Проверка поддержки TRIM прошивкой (firmware) диска
Для того чтобы проверить это, установите sg3_utils (обязательно) и lsscsi (не обязательно, но желательно):
# apt-get install sg3_utils lsscsi
Запустите следующие команды для проверки параметра Maximum unmap LBA count и Unmap command supported (LBPU):
# sg_vpd -p bl /dev/sdc | grep -i unmap
Maximum unmap LBA count: 4194240
Maximum unmap block descriptor count: 1
....
# sg_vpd -p lbpv /dev/sdc | grep LBPU
Unmap command supported (LBPU): 1
Если Maximum unmap LBA count и Unmap command supported (LBPU) имеют ненулевые значения, значит устройство умеет работать с TRIM.
Пробное включение TRIM
Если ядро не обнаружило способность вашего устройства к разметке данных, то, скорее всего, будет возвращено значение "full". Кроме "full", драйвер SCSI-накопителя ядра в настоящее время знает следующие значения для provisioning_mode:
unmap
writesame_16
writesame_10
writesame_zero
disabled
Проверим все значения provisioning_mode
у всех устройств подключенных к компьютеру, например имеем такую картину:
# find /sys/ -name provisioning_mode -exec grep -H . {} + | sort
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb4/4-1/4-1.1/4-1.1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb5/5-2/5-2:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb5/5-4/5-4:1.0/host4/target4:0:0/4:0:0:0/scsi_disk/4:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:11.0/ata1/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0/provisioning_mode:writesame_16
/sys/devices/pci0000:00/0000:00:11.0/ata2/host1/target1:0:0/1:0:0:0/scsi_disk/1:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:12.2/usb1/1-4/1-4:1.3/host11/target11:0:0/11:0:0:0/scsi_disk/11:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:13.2/usb2/2-4/2-4:1.0/host7/target7:0:0/7:0:0:0/scsi_disk/7:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:13.2/usb2/2-4/2-4:1.0/host7/target7:0:0/7:0:0:1/scsi_disk/7:0:0:1/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:13.2/usb2/2-4/2-4:1.0/host7/target7:0:0/7:0:0:2/scsi_disk/7:0:0:2/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:13.2/usb2/2-4/2-4:1.0/host7/target7:0:0/7:0:0:3/scsi_disk/7:0:0:3/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:13.2/usb2/2-6/2-6:1.0/host8/target8:0:0/8:0:0:0/scsi_disk/8:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:14.1/ata6/host10/target10:0:0/10:0:0:0/scsi_disk/10:0:0:0/provisioning_mode:full
/sys/devices/pci0000:00/0000:00:14.1/ata6/host10/target10:0:1/10:0:1:0/scsi_disk/10:0:1:0/provisioning_mode:full
# lsscsi
[0:0:0:0] disk ATA HS-SSD-E100 512G 002 /dev/sda
[1:0:0:0] disk ATA WDC WD5000AACS-0 1B01 /dev/sdb
[2:0:0:0] cd/dvd ATAPI iHAS124 D 8L07 /dev/sr0
[4:0:0:0] disk StoreJet Transcend 0 /dev/sde
[5:0:0:0] disk Samsung SSD 870 EVO 1TB 0 /dev/sdc
[6:0:0:0] disk USSD USSD 5.00 /dev/sdd
[7:0:0:0] disk Generic- SD/MMC 1.00 /dev/sdg
[7:0:0:1] disk Generic- Compact Flash 1.01 /dev/sdh
[7:0:0:2] disk Generic- SM/xD-Picture 1.02 /dev/sdi
[7:0:0:3] disk Generic- MS/MS-Pro 1.03 /dev/sdj
[8:0:0:0] disk ASMT 2235 0 /dev/sdf
[10:0:0:0] disk ATA SAMSUNG HM250JI 0-08 /dev/sdk
[10:0:1:0] disk ATA ST31000524AS JC4B /dev/sdl
[11:0:0:0] disk TF CARD Storage 2.31 /dev/sdm
Мы раньше узнали, что прошивка диска /dev/sdc поддерживает TRIM. Запускаем команду:
# find /sys/ -name provisioning_mode -exec grep -H . {} + | grep 5:0:0:0
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb5/5-2/5-2:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0/provisioning_mode:full
И завершающий "укол":
echo unmap > /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb5/5-2/5-2:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0/provisioning_mode
Теперь provisioning_mode имеет значение unmap.
Следующий шаг
Правильно установим переменную discard_max_bytes
Получаем значение Мaximum unmap LBA count:
# sg_vpd -p bl /dev/sdc | grep "unmap LBA"
Maximum unmap LBA count: 4194240
Получаем значение logical block length:
# sg_readcap -l /dev/sdc | grep length
Logical block length=512 bytes
Расчитываем discard_max_bytes умножая Мaximum unmap LBA count на logical block length:
# echo $((4194240*512))
2147450880
Устанавливаем значение discard_max_bytes:
# echo 2147450880 > /sys/block/sdс/queue/discard_max_bytes
Запускаем fstrim
# fstrim -v /mnt/arhiv/
/mmnt/arhiv/: 0 B (0 bytes) trimmed
Всё заработало.
Создание правила UDEV
По умолчанию на внешних носителях TRIM отключен, а при попытке запустить fstrim путь до внешнего носителя, мы получаем сообщение the discard operation is not supported, если мы проведём вышеуказанные операции, то можно запустить fstrim, но это будет работать только до перезагузки компьютера. Для того, чтобы внешний диск работал всегда надо создать правило udev.
Первым делом узнаём значение idVendor и idProduct жесткого диска:
1 Вариант (работает только для USB устройств):
$ cat /sys/block/sdc/../../../../../../idVendor
174c
$ cat /sys/block/sdc/../../../../../../idProduct
55aa
2 Вариант — использовать lsusb:
# lsusb
Bus 004 Device 003: ID 174c:55aa ASMedia Technology Inc. ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge, ASM1153E SATA 6Gb/s bridge
Создаём правило udev:
# echo 'ACTION=="add|change", ATTRS{idVendor}=="174c", ATTRS{idProduct}=="55aa", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap"' >>/etc/udev/rules.d/10-uas-discard.rules
Или открываем в редакторе и вписываем строку:
ACTION=="add|change", ATTRS{idVendor}=="174c", ATTRS{idProduct}=="55aa", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap"
# mcedit /etc/udev/rules.d/10-uas-discard.rules
Перезагружаю правила udev:
# udevadm control -R -S
Монтирую устройство:
$ udisksctl mount -b /dev/sdd1
Проверяю работу ftrim:
# lsblk -Df
...
─sdd1 0 512B 4G 0 ext4 1.0 Arhiv2 be4327fe-6153-4698-ad46-03a4b74abce6
...
Для точки монтирования /media/Arhiv/:
# fstrim -v /media/Arhiv/
/media/Arhiv/: 0 B (0 bytes) trimmed
Ссылки
- Solid_state_drive_(Русский)
- Включение TRIM на внешнем SSD на Raspberry Pi (eng)
- Как правильно активировать TRIM для вашего SSD в Linux (eng)
- Fstrim (periodic trim) and SSD raid (raid5)
- ↑ Мне не удалось так включить TRIM на внешнем диске