Использование ramdisk в Linux (ramdisk, ramfs, tmpfs) или препарирование рамдисков
Приветствую, уважаемые гости и постоянные читатели моего блога о linux. Еще одна заметочка из истории) Тема статьи tmpfs – файловая система в оперативной памяти. Данная фича довольно полезна, если у Вас имеется некоторое количество не используемой оперативной памяти и у вас имеются часто записываемые\считываемые на\с жесткого диска файлы, которые нет необходимости хранить долговременно. С помощью tmpfs можно значительно сократить количество операций IO на жестком диске и тем самым увеличить производительность. Перед прочтением статьи настоятельно рекомендую ознакомиться со статьями: файловая система Linux, пару статей о ядре linux и права доступа linux.
Введение в tmpfs (история)
Существуют 3 реализации технологии диска в оперативной памяти. В интернете я наткнулся на очень большое количество статей, в которых путаются местами эти три разные, но похожие технологии. Для того чтобы не возникало этой путаницы, я в статье буду применять слово рамдиск (по-русски) в качестве общего названия технологии используемой в linux. В статье я буду использовать дистрибутив Debian для приведения примеров, но также постараюсь обозначить отличия технологии в других дистрибутивах.
Всего ступеней эволюции рамдиска было три. Все началось с технологии ramdisk. Аналогичное именование используется и по сей день в ОС Windows. В далеком 1995 году (может и раньше) в ядро linux (вроде еще в версии до 2.0) была добавлена возможность использовать физическую память как блочное устройство. Интересно, в те времена действительно у кого-то было столько памяти, что в ней хранили данные…) После доработки технологии ramdisk, в ядро была добавлена поддержка следующей более продвинутой технологии рамдиска под названием ramfs (приблизительных дат, когда это произошло, я не нашел), которая устранила некоторые недостатки рамдиска в ramdisk виде. И последним шагом стало появление в ядре linux поддержки tmpfs. Которая, кстати, ранее именовалась как shmfs (shared memory filesystems). Давайте от младшего к старшему рассмотрим каждую технологию.
ramdisk в Linux
Особенности ramdisk.
Рамдиск в виде ramdisk в зародыше представлял собой блочное устройство в каталоге /dev. Точно так же как и любое другое блочное устройство (жесткий диск /dev/sda, флоппи /dev/fd…):
- имеет строго фиксированный размер (задается при компиляции ядра). За рамки этого размера наполняемые данные выйти не смогут, выдав соответствующее сообщение о нехватке места.
- должен быть отформатирован в какую-либо файловую систему. Обычно для этой цели рекомендуется ext2, т.к. для данных хранимых в оперативной памяти нет необходимости обладать свойством журналирования.
- ramdisk должен быть примонтирован в какую-либо точку монтирования. Приложения с примонтированным диском ramdisk будут работать как с обычным жестким диском, но
инструментами ядрадрайверами – все данные “физически” будут размещаться в ОЗУ.
Недостатки ramdisk:
- Так как ramdisk работает как обычное блочное устройство с файловой системой, оно точно так же использует возможности кэширования данных записываемых на файловую систему и считываемых оттуда. Из этого можно сделать вывод, что данный вид рамдиска использует дополнительные ресурсы памяти и CPU для управления файловой системой, кэшем.
- Имея фиксированный размер, ramdisk не может использовать swap раздел, если не хватает свободной физической памяти.
- Стоит так же отметить, что изменить размер ramdisk не так-то просто… (это относится к рамдиску, интегрированному в ядро. Не модулем)
Чтобы убедиться, что Ваша система поддерживает рамдиск ramdisk, необходимом проверить следующие параметры для запущенного ядра:
ramdisk-host ~ # grep DEV_RAM /boot/config-`uname -r` CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192
Что мы видим в данных параметрах? CONFIG_BLK_DEV_RAM=m нам говорит, что устройство ramdisk поддерживается ядром в виде модуля. Если бы вместо m стояла y, то это бы означало, что ramdisk интегрирован в ядро и при загрузке в каталоге /dev будет создано 16 устройств (CONFIG_BLK_DEV_RAM_COUNT=16). Например, RedHad дистрибутивы (Fedora, CentOS, AltLinux…) так и поступают:
[root@localhost /]# ls -l /dev/ram* brw-rw---- 1 root disk 1, 0 2010-03-04 03:44 /dev/ram0 brw-rw---- 1 root disk 1, 1 2010-03-04 03:44 /dev/ram1 brw-rw---- 1 root disk 1, 10 2010-03-04 03:44 /dev/ram10 brw-rw---- 1 root disk 1, 11 2010-03-04 03:44 /dev/ram11 brw-rw---- 1 root disk 1, 12 2010-03-04 03:44 /dev/ram12 brw-rw---- 1 root disk 1, 13 2010-03-04 03:44 /dev/ram13 brw-rw---- 1 root disk 1, 14 2010-03-04 03:44 /dev/ram14 brw-rw---- 1 root disk 1, 15 2010-03-04 03:44 /dev/ram15 brw-rw---- 1 root disk 1, 2 2010-03-04 03:44 /dev/ram2 brw-rw---- 1 root disk 1, 3 2010-03-04 03:44 /dev/ram3 brw-rw---- 1 root disk 1, 4 2010-03-04 03:44 /dev/ram4 brw-rw---- 1 root disk 1, 5 2010-03-04 03:44 /dev/ram5 brw-rw---- 1 root disk 1, 6 2010-03-04 03:44 /dev/ram6 brw-rw---- 1 root disk 1, 7 2010-03-04 03:44 /dev/ram7 brw-rw---- 1 root disk 1, 8 2010-03-04 03:44 /dev/ram8 brw-rw---- 1 root disk 1, 9 2010-03-04 03:44 /dev/ram9
но в Debian дистрибутивах этого не замечено. Далее, CONFIG_BLK_DEV_RAM_SIZE=8192 указывает нам, что размер одного устройства будет равен 8192 Кб. Необходимо понимать, что пока данные диски не отформатированы и не примонтированы и не заполнены – они не занимают место в оперативной памяти.
Работа с ramdisk.
Давайте на примерах ниже поэкспериментируем с рамдиском. (не забываем обращать внимание на символ прав рута – #). Предположим, что у нас Debian и ramdisk в виде модуля, значит при загрузке системы диски автоматически не созданы. Опытным путем было установлено, что модуль, ответственный за ramdisk называется brd (в некоторых старых дистрибутивах – rd).
ramdisk-host ~ # modinfo /lib/modules/2.6.32-5-686/kernel/drivers/block/brd.ko filename: /lib/modules/2.6.32-5-686/kernel/drivers/block/brd.ko alias: rd alias: block-major-1-* license: GPL depends: vermagic: 2.6.32-5-686 SMP mod_unload modversions 686 parm: rd_nr:Maximum number of brd devices (int) parm: rd_size:Size of each RAM disk in kbytes. (int) parm: max_part:Maximum number of partitions per RAM disk (int)
Как видно, у модуля имеются некоторые параметры. Давайте попробуем ими воспользоваться:
ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 43 332 0 6 18 -/+ buffers/cache: 17 357 Swap: 382 0 382 ramdisk-host ~ # insmod /lib/modules/2.6.32-5-686/kernel/drivers/block/brd.ko rd_nr=3 rd_size=102400 max_part=2 ramdisk-host ~ # ls -la /dev/|grep ram drwxr-xr-x 2 root root 40 Мар 24 22:17 .initramfs -rw-r--r-- 1 root root 0 Мар 24 22:17 .initramfs-tools brw-rw---- 1 root disk 1, 0 Мар 24 22:21 ram0 brw-rw---- 1 root disk 1, 1 Мар 24 22:21 ram1 brw-rw---- 1 root disk 1, 2 Мар 24 22:21 ram2 ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 45 329 0 8 18 -/+ buffers/cache: 18 357 Swap: 382 0 382 ramdisk-host ~ # fdisk /dev/ram1 Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel with disk identifier 0xc57a43c9. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won't be recoverable. Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite) WARNING: DOS-compatible mode is deprecated. It's strongly recommended to switch off the mode (command 'c') and change display units to sectors (command 'u'). Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks. ramdisk-host ~ # fdisk /dev/ram1 WARNING: DOS-compatible mode is deprecated. It's strongly recommended to switch off the mode (command 'c') and change display units to sectors (command 'u'). Command (m for help): a Partition number (1-4): 1 Warning: partition 1 has empty type Command (m for help): p Disk /dev/ram1: 104 MB, 104857600 bytes 255 heads, 63 sectors/track, 12 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0xc57a43c9 Device Boot Start End Blocks Id System /dev/ram1p1 * 1 1 0 0 Empty Partition 1 has different physical/logical beginnings (non-Linux?): phys=(0, 0, 0) logical=(0, 0, 1) Partition 1 has different physical/logical endings: phys=(0, 0, 0) logical=(267349, 89, 4) Partition 1 does not end on cylinder boundary. Command (m for help): q
Как видно, я указал создать 3 диска (rd_nr=3) размером 102400 Кб (rd_size=102400) и максимальное количество партиций на диск – 2 (max_part=2). Далее, я проверил работоспособность всех 3х параметров. Как видно, создалось именно 3 файла ram* в каталоге /dev, далее я попытался командой fdisk создать разделы на диске, на что при первом обращении к диску, fdisk ругнулся на некорректную таблицу разделов и предложил ее поправить. Поправили. При втором обращении ошибки не оказалось, но создать даже одного раздела так и не получилось… (может для работы с рамдисками нуобходим какой-то особый fdisk?… но parted так же не справился с задачей). Но при выводе таблицы разделов мы видим, что размер 104Мб. То есть можно сделать вывод, что из всех указанных параметров не отработал только max_part=2 (Почему?…решения пока не нашел). Так же из вывода видно, что при создании дисков свободная память уменьшилась не значительно (видимо только на объем, необходимый для подключения модуля). Поехали дальше…
Показать форматирование и монтирование рамдиск »
ramdisk-host ~ # mkfs -T ext2 /dev/ram0 mke2fs 1.41.12 (17-May-2010) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 6400 inodes, 25600 blocks 1280 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=29360128 1 block group 32768 blocks per group, 32768 fragments per group 6400 inodes per group Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 27 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 47 327 0 8 18 -/+ buffers/cache: 20 355 Swap: 382 0 382 ramdisk-host ~ # mkdir /mnt/ramdisk ramdisk-host ~ # mount -v -t ext2 /dev/ram0 /mnt/ramdisk/ /dev/ram0 on /mnt/ramdisk type ext2 (rw) ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 48 327 0 8 19 -/+ buffers/cache: 20 355 Swap: 382 0 382
Итак, создали на диске файловую систему ext2. Память опять почти не изменилась. Хм… Почти все источники в интернете утверждают, что после форматирования диска, кусок размером с объем раздела отрезается от свободного пространства памяти. (Видимо, в последних версиях ядра данный модуль переделан и более так себя не ведет.) Примонтировали. Память как был свободна, так и осталась. Далее…
ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 48 327 0 8 19 -/+ buffers/cache: 20 355 Swap: 382 0 382 ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramdisk/fullramdisk dd: запись в «/mnt/ramdisk/fullramdisk»: На устройстве кончилось место 201265+0 записей считано 201264+0 записей написано скопировано 103047168 байт (103 MB), 0,409461 c, 252 MB/c ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 219 155 0 9 117 -/+ buffers/cache: 93 282 Swap: 382 0 382 ramdisk-host ~ # df /dev/ram0 Файловая система 1K-блоков Исп Доступно Исп% смонтирована на /dev/ram0 100784 100784 0 100% /mnt/ramdisk
Итак, диск у нас наполнился файлом на весь доступный объем. Как видно, памяти отрезано по размеру диска. Вот тут, я бы хотел, кое-что прокомментировать:
Примечание (или что показывает free в столбце used). used=shared+buffers+cached+память_используемая_работающими_программами_в_пользовательском_режиме. При этом, память используемую под buffers+cached можно считать свободной, т.к. эта память будет отдана приложениям, как только она понадобится. Так же стоит отметить, что данную занятую память вы не увидите не в команде top, ни htop, ни в других, т.к. занята она ядром.
Еще пару экспериментов:
ramdisk-host ~ # rm /mnt/ramdisk/fullramdisk rm: удалить обычный файл «/mnt/ramdisk/fullramdisk»? y ramdisk-host ~ # df /dev/ram0 Файловая система 1K-блоков Исп Доступно Исп% смонтирована на /dev/ram0 100784 48 95616 1% /mnt/ramdisk ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 147 227 0 9 19 -/+ buffers/cache: 119 256 Swap: 382 0 382 ramdisk-host ~ # umount /mnt/ramdisk ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 147 228 0 8 19 -/+ buffers/cache: 118 256 Swap: 382 0 382
Итак, грохнули файл на ramdisk – память как была занята, так и осталась. Отмонтировали /dev/ram0 – память как была занята, так и осталась. Вывод – ядро не возвращает освобожденное на диске место. Перезагружаем Linux и еще пару экспериментов…
ramdisk-host ~ # insmod /lib/modules/2.6.32-5-686/kernel/drivers/block/brd.ko rd_nr=5 rd_size=102400 max_part=2 ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 43 332 0 6 18 -/+ buffers/cache: 18 357 Swap: 382 0 382 ramdisk-host ~ # mkfs -T ext2 /dev/ram0 mke2fs 1.41.12 (17-May-2010) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 6400 inodes, 25600 blocks 1280 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=29360128 1 block group 32768 blocks per group, 32768 fragments per group 6400 inodes per group Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 28 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. ramdisk-host ~ # mkfs -T ext2 /dev/ram1 mke2fs 1.41.12 (17-May-2010) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 6400 inodes, 25600 blocks 1280 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=29360128 1 block group 32768 blocks per group, 32768 fragments per group 6400 inodes per group Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 39 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. ramdisk-host ~ # mkfs -T ext2 /dev/ram2 mke2fs 1.41.12 (17-May-2010) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 6400 inodes, 25600 blocks 1280 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=29360128 1 block group 32768 blocks per group, 32768 fragments per group 6400 inodes per group Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 21 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. ramdisk-host ~ # mkfs -T ext2 /dev/ram3 mke2fs 1.41.12 (17-May-2010) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 6400 inodes, 25600 blocks 1280 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=29360128 1 block group 32768 blocks per group, 32768 fragments per group 6400 inodes per group Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 39 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. ramdisk-host ~ # mkdir -v /mnt/ramdisk{1,2,3,4} mkdir: невозможно создать каталог «/mnt/ramdisk1»: Файл существует mkdir: невозможно создать каталог «/mnt/ramdisk2»: Файл существует mkdir: создан каталог «/mnt/ramdisk3» mkdir: создан каталог «/mnt/ramdisk4» ramdisk-host ~ # mount -t ext2 /dev/ram0 /mnt/ramdisk ramdisk-host ~ # mount -v -t ext2 /dev/ram1 /mnt/ramdisk1 /dev/ram1 on /mnt/ramdisk1 type ext2 (rw) ramdisk-host ~ # mount -v -t ext2 /dev/ram2 /mnt/ramdisk2 /dev/ram2 on /mnt/ramdisk2 type ext2 (rw) ramdisk-host ~ # mount -v -t ext2 /dev/ram3 /mnt/ramdisk3 /dev/ram3 on /mnt/ramdisk3 type ext2 (rw) ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 50 324 0 6 19 -/+ buffers/cache: 24 350 Swap: 382 0 382 ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramdisk/fulldisk dd: запись в «/mnt/ramdisk/fulldisk»: На устройстве кончилось место 201265+0 записей считано 201264+0 записей написано скопировано 103047168 байт (103 MB), 0,437373 c, 236 MB/c ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramdisk1/fulldisk dd: запись в «/mnt/ramdisk1/fulldisk»: На устройстве кончилось место 201265+0 записей считано 201264+0 записей написано скопировано 103047168 байт (103 MB), 0,525683 c, 196 MB/c ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramdisk2/fulldisk dd: запись в «/mnt/ramdisk2/fulldisk»: На устройстве кончилось место 201265+0 записей считано 201264+0 записей написано скопировано 103047168 байт (103 MB), 0,3226 c, 319 MB/c ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 370 5 0 2 49 -/+ buffers/cache: 318 57 Swap: 382 0 382 ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramdisk3/fulldisk
Как говориться, за что боролись, на то и напоролись ) Следующий нюанс при работе с ramdisk, который я бы хотел затронуть – это как изменить размер ramdisk. С учетом примеров выше, становится понятно, что подключив нужный модуль в ядро с помощью нужной команды (insmod) и подходящих параметров (rd_size), можно изменить размер без перезагрузки. Но как же нам поступить в случае, если ramdisk интегрирован в ядро? В данном случае имеется два пути (по крайней мере, я больше не знаю…):
- Указать в параметрах загрузки ядра значение в виде ramdisk=xxxK. (В Debian, например, это делается в /etc/default/grub. В RedHat – это (вроде) /etc/sysconfig/grub, но могу ошибаться)
- Есть более серьезный путь – пересобрать ядро, изменив параметр CONFIG_BLK_DEV_RAM_SIZE на необходимое значение.
Итак подведем маленький итог ramdisk, допустим, не дочитав статью Вам ужас как хочется использовать данный рамдиск в работе, вам необходимо:
- Подключить модуля ядра (rd.ko или brd.ko), если ramdisk собран в ядре в модульном виде.
- Создать файловую систему на рамдиске
- Примонтировать рамдиск
- Пользоваться
- Если есть желание, чтобы данный диск монтировался при загрузке, то необходимо создать соответствующий скрипт с учетом вышеприведенных шагов и добавить с какой-нибудь загрузочный файл (например, /etc/rc.local).
ramfs в Linux
Особенности рамдиска ramfs.
Ramfs это более грамотная и усовершенствованная реализация технологии рамдиск. Особенностью ее является то, что нет необходимости создавать специальное блочное устройство и форматировать его. В man mount так и сказано: “Mount options for ramfs: Ramfs is a memory based filesystem. Mount it and you have it. Unmount it and it is gone. Present since Linux 2.3.99pre4. There are no mount options.” То есть, остается просто смонтировать файловую систему ramfs и она у Вас будет. При этом, использованная, но уже не используемая память теперь умеет освобождаться. Стоит отметить, что данный рамдиск умеет монтироваться из /etc/fstab.
Недостатки ramfs.
Но ramfs не осталось без недостатков. Фактически, при монтировании данного типа файловой системы не представляется возможным указать предельный размер. То есть, существует параметр задающий размер диска, но этот параметр задает размер куска, который отрубается от оперативной памяти сразу при монтировании (Скажем так, стартовый размер.). При этом, ограничить рост занимаемых данных более стартового размера – невозможно. Этот недостаток требует от приложений, которые будут писать в что-либо ramfs, контроля размера записываемых данных.
Чтобы убедится, что Ваша система поддерживает рамдиск ramfs, можно выполнить следующее:
ramdisk-host ~ # grep ram /proc/filesystems nodev ramfs
Работа с ramfs
Давайте попробуем препарировать ramfs.
ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 23 352 0 0 4 -/+ buffers/cache: 17 358 Swap: 382 0 382 ramdisk-host ~ # ramdisk-host ~ # mount -v -t ramfs ramfs /mnt/ramfs/ ramfs on /mnt/ramfs type ramfs (rw) ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 24 351 0 1 5 -/+ buffers/cache: 17 358 Swap: 382 0 382 ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramfs/test-200m bs=1M count=200 200+0 записей считано 200+0 записей написано скопировано 209715200 байт (210 MB), 0,0917934 c, 2,3 GB/c ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 225 150 0 1 206 -/+ buffers/cache: 17 358 Swap: 382 0 382 ramdisk-host ~ # rm -v /mnt/ramfs/test-200m rm: удалить обычный файл «/mnt/ramfs/test-200m»? y удалён «/mnt/ramfs/test-200m» ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 25 350 0 1 6 -/+ buffers/cache: 17 358 Swap: 382 0 382 ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramfs/test-full
Давайте попробуем разобраться в листинге. Как видно, при монтировании рамдиска ramfs размер оперативной памяти не изменился. Далее, записали 200Мб в примонтированный раздел. Интересный нюанс: ramfs использует область памяти, используемую в качестве cached. При этом, нужно понимать, что память забранная под cached ramfs’ом не будет возвращена приложениям при запросе!!! Далее, удаляем созданные 200Мб и ядро освобождает выданную ранее память. Ну и проверяем последнее утверждение, что рамдиск не ограничен по росту и видим как ядро в шоке )
tmpfs в linux
Особенности tmpfs в linux.
На текущий момент, tmpfs это самый совершенный рамдиск. Tmpfs ранее именовалась как shmfs (shared memory filesystem). Данная файловая система учла все достоинства прошлых рамдисков и включила исправленные недостатки:
- Раздел tmpfs можно ограничить по размеру,
- tmpfs при нехватке основной памяти научился использовать swap раздел.
- Если размер рамдиска не указан явно, то диск монтируется в половину размера ОЗУ.
В современных дистрибутивах tmpfs используется довольно активно, например он используется udev’ом для обслуживания устройств в каталоге /dev, так же часто в виде tmpfs монтируются каталоги /tmp или /var/tmp, содержимое которых нет необходимости хранить долговременно. Проверить, поддерживает ли Ваша система tmpfs можно следующей командой:
ramdisk-host ~ # grep tmpfs /proc/filesystems nodev tmpfs
Tmpfs обладает рядом специфичных параметров, которые возможно указать при монтировании, давайте разберем их:
- size=ххх – Задает максимальный размер монтируемого tmpfs. Указывается в битах (или в процентах) и при монтировании округляется до целых страниц памяти. Как я уже сказал, если не задать данный параметр, то рамдиск будет примонтирован с размером, равным половине физической памяти.
- nr_blocks=xxx – Также, задает размер tmpfs, но в блоках PAGE_CACHE_SIZE. (частно сказать, я не понял что еть данный параметр…)
- nr_inodes=xxx – Задает максимальное число inod. По-умолчанию, данный параметр имеет значение, равное половине количества физических страниц ОЗУ (если используется ядро hightmem, то половина страниц lowmem-памяти). Какой порядок цифр выделения inod при определенном size? Я не смог найти какой-либо статистической информации, но могу дать следующий совет: если планируется записывать большое количество мелких файлов на раздел tmpfs, то рекомендуется указать значение, заведомо большее, чем количество записываемых файлов.
- Примечание: Все вышеуказанные параметры могут указываться с суффиксами k,m,g или Ki, Mi, Gi и могут изменяться “налету” с командой mount и опцией remount.
- mode=xxx – Задает права доступа к корню примонтированного раздела.
- uid=nnn – Задает ID пользователя для вышеуказанных прав доступа.
- gid=nnn – Задает ID группы для вышеуказанных прав доступа.
- mpol=[default|prefer:Node|bind:NodeList|interleave|interleave:NodeList] – Довольно специфичный параметр, который устанавливает приоритет использования памяти в многосокетных серверах. Если уж очень интересно, то можно об этом почитать в ссылках в конце статьи.
Работа с tmpfs
Ну и несколько команд, показывающих использование tmpfs в Linux:
ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 20 354 0 0 4 -/+ buffers/cache: 16 359 Swap: 382 0 382 ramdisk-host ~ # mount -t tmpfs tmpfs /mnt/tmpfs/ -o size=100M ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 20 354 0 0 5 -/+ buffers/cache: 15 359 Swap: 382 0 382 ramdisk-host ~ # dd if=/dev/zero of=/mnt/tmpfs/testfull dd: запись в «/mnt/tmpfs/testfull»: На устройстве кончилось место 204593+0 записей считано 204592+0 записей написано скопировано 104751104 байта (105 MB), 0,253756 c, 413 MB/c ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 121 253 0 0 105 -/+ buffers/cache: 15 359 Swap: 382 0 382 ramdisk-host ~ # rm /mnt/tmpfs/testfull rm: удалить обычный файл «/mnt/tmpfs/testfull»? y ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 22 352 0 0 5 -/+ buffers/cache: 16 359 Swap: 382 0 382 ramdisk-host ~ # df -h | grep tmpfs tmpfs 100M 0 100M 0% /mnt/tmpfs ramdisk-host ~ # dd if=/dev/zero of=/mnt/tmpfs/testfull dd: запись в «/mnt/tmpfs/testfull»: На устройстве кончилось место 204593+0 записей считано 204592+0 записей написано скопировано 104751104 байта (105 MB), 0,177131 c, 591 MB/c ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 132 243 0 4 109 -/+ buffers/cache: 18 356 Swap: 382 0 382 ramdisk-host ~ # df -h | grep tmpfs tmpfs 100M 100M 0 100% /mnt/tmpfs ramdisk-host ~ # mount -t tmpfs tmpfs /mnt/tmpfs/ -o size=150M,remount ramdisk-host ~ # df -h | grep tmpfs tmpfs 150M 100M 50M 67% /mnt/tmpfs ramdisk-host ~ # dd if=/dev/zero of=/mnt/tmpfs/testfull2 dd: запись в «/mnt/tmpfs/testfull2»: На устройстве кончилось место 102289+0 записей считано 102288+0 записей написано скопировано 52371456 байт (52 MB), 0,112835 c, 464 MB/c ramdisk-host ~ # df -h | grep tmpfs tmpfs 150M 150M 0 100% /mnt/tmpfs ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 184 191 0 4 161 -/+ buffers/cache: 18 356 Swap: 382 0 382 ramdisk-host ~ # umount /mnt/tmpfs ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 219 155 0 0 6 -/+ buffers/cache: 212 163 Swap: 382 8 374 ramdisk-host ~ # mount -t tmpfs tmpfs /mnt/tmpfs/ -o size=250M,remount ramdisk-host ~ # dd if=/dev/zero of=/mnt/tmpfs/full dd: запись в «/mnt/tmpfs/full»: На устройстве кончилось место 511489+0 записей считано 511488+0 записей написано скопировано 261881856 байт (262 MB), 9,20088 c, 28,5 MB/c ramdisk-host ~ # free -m total used free shared buffers cached Mem: 375 370 5 0 0 149 -/+ buffers/cache: 220 154 Swap: 382 152 230 ramdisk-host ~ # df -h | grep tmpfs tmpfs 250M 250M 0 100% /mnt/tmpfs
Давайте попробуем разобраться, что мы тут увидели? Смотрим, что исходно у нас памяти used 20 и cached 4 Мб. Монтируем tmpfs размером 100Мб. Объем памяти почти не изменился. Это подтверждает, что система не отрезает сразу целый кусок, равный диску. Далее, наполняем файл testfull (командой dd) на примонтированном разделе до предельного размера и видим, что он после наполнения уперся в объем диска и наполнение останавливается. free -m показывает, что заполнена память из области cached. Удаляем созданный на tmpfs файл и место освобождается. Далее, снова до предела наполняем примонтированный раздел. Пытаемся изменить размер tmpfs раздела до 150Мб без размонтирования. и командой df наблюдаем, что на разделе прибавилось свободных 50Мб. Класс! При этом, все данные, которые были до перемонтирования на диске, остались неизменными. Заполняем оставшееся место файлом testfull2. Диск наполнен. Система вполне продолжает свою работоспособность )
Еще один эксперимент. Размонтируем раздел tmpfs – память освободилась. Далее, предположим, что какие-то пользовательские приложения заняли 200 с лишним Мб памяти (219Мб). Примонтируем диск, заведомо больше, чем доступная свободная память (250М). Наполняем диск до предела и видим, что:
- скорость записи упала до 28,5 Мб
- swap наполнился данными, что говорит нам, что записанные в tmpfs данные писались в swap
Стоит так же отметить, что повредить систему мне удалось лишь заполнив рамдиск tmpfs, задав размер tmpfs более чем сумма оперативной памяти и swap.
Пример использования tmpfs для сервера печати в домене AD
Вот живой пример использования tmpfs для ускорения работы очереди печати SAMBA+CUPS. Создаем tmpfs раздел /spooler при загрузке системы, в который размещаем спулер очереди печати демонов CUPS и SAMBA:
ramdisk-host ~ # grep tmp /etc/fstab tmpfs /spooler tmpfs noexec,size=4000M 0 0 ramdisk-host ~ # grep -A5 printers /etc/smb.conf [printers] comment = Очередь печати SMB path = /spooler/samba printable = Yes browseable = No ramdisk-host ~ # grep spool /etc/cupsd.conf
Таким образом, мы сильно ускорим печать, особенно крупных графических заданий и узким местом для заданий печати становится уже не жесткий диск, а сетевой интерфейс.
Безопасность ramdisk, ramfs, tmpfs
Особое внимание стоит уделить безопасности рамдиска ramfs, т.к. данный вид рамдиска никак не ограничивает рост занимаемой ОЗУ. Для того чтобы защитить ваш Linux от краха, необходимо ограничить права доступа на запись в примонтированный раздел. Для этого, в tmpfs имеются параметры монтирования mode=, uid= и gid=nnn. Для ramfs это реализуется посредством задания прав доступа на точку монтирования. Для ramdisk используются стандартные параметры монтирования любой файловой системы с указанием прав и ID групп и пользователя. Стоит понимать, что кроме специфических параметров монтирования рамдиск имеются и стандартные опции, такие как noexec, nosuid и др., ограничивающие возможности неправомерного использования раздела.
Tips & Tricks tmpfs
Bind-монтирование для куска файловой системы
Про bind mounting можно почитать в ссылках в конце статьи. Далее, интересный пример с сайта ibm.com: вы монтируете tmpfs к /dev/shm, его “традиционной” точке, но одновременно хотите использовать tmpfs для /tmp. Вместо монтирования еще одной tmpfs к /tmp (что возможно), вы решаете объединить /tmp с /dev/shm. Но, bind mount /dev/shm к /tmp нужно сделать так, чтобы каталоги из /dev/shm не были видны в /tmp. Как это сделать? Пример:
# mkdir /dev/shm/tmp # chmod 1777 /dev/shm/tmp # mount --bind /dev/shm/tmp /tmp
В этом примере сначала создается каталог /dev/shm/tmp и назначаются права доступа 1777
(обычные для /tmp). Далее можно монтировать только отдельный /dev/shm/tmp. После этого файл /tmp/foo будет дополнительно виден как /dev/shm/tmp/foo, но файл /dev/shm/bar в каталоге /tmp отображен не будет.
Swap без изменений в структуре файловой системы
Если Вам необходимо разово расширить объем виртуальной памяти за счет своп раздела, при этом нет возможности изменить таблицу разделов, есть возможность добавить кусок свопа в виде файла. Это может понадобиться, например, для сборки крупного пакета. Пример данной конфигурации:
# dd if=/dev/zero of=/home/swap.img bs=1M count=1024 # chmod 600 /home/swap.img # mkswap /home/swap.img # swapon /home/swap.img
Стоит учитывать, что на linux архитектуре x86 возможно использовать размер свопа не более 2 Гб. Но этих файлов можно подключать несколько.
Сравнение рамдисков (итог)
Давайте подведем краткий итог вышеизложенного. Для большинства задач наиболее подходящим является реализация tmpfs, как обладающая наибольшим функционалом и отсутствием недостатков. Ниже маленькая сводная таблица:
ramdisk | ramfs | tmpfs | |
Лимит размера диска | Да | Нет | Да |
Изменение размера |
Да (ограниченно) | Да | Да (без прерывания работы) |
Использование swap |
Нет | Нет | Да |
Монтирование через fstab | Нет | Да | Да |
Высвобождение неиспользуемого пространства | Нет | Да | Да |
Что еще почитать о tmpfs
Документация ядра linux:
https://www.kernel.org/doc/Documentation/blockdev/ramdisk.txt
https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt
https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
Дополнительные ссылки:
http://www.vanemery.com/Linux/Ramdisk/rd-c.txt – что-то похожее на исходники модуля ядра rd
http://linux-mm.org/ – wiki с кучей информации о работе оперативной памяти в Linux
http://0pointer.de/blog/projects/tmp.html – статья о использовании tmpfs в /tmp или /var/tmp
Man-страницы
man mknod
man mount
man fstab
С Уважением, Mc.Sim
Другие материалы в категории основы Linux
- Текстовый редактор VIM, основы работы
- ddrescue или спасаем данные с HDD
- Резервное копирование файлов сайта по ssh
- Седьмой релиз Debian
- Использование ramdisk в Linux (ramdisk, ramfs, tmpfs) или препарирование рамдисков
- SNMP протокол (основы)
- Установка антивирусного сканера ClamAV на Debian
- HOWTO использование backports в Debian
- Конспект установки Debian на сервер
- SSH сервер на Debian
Все подробно и по делу – вам надо переводы man-ов писать :).
А как проверить скорость чтения, записи?
В статье приведены примеры команды dd if=/dev/zero of=/mnt/ramdisk/fullramdisk. В своем выводе она показывает скорость. Пример:
ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramdisk/fullramdisk
dd: запись в «/mnt/ramdisk/fullramdisk»: На устройстве кончилось место
201265+0 записей считано
201264+0 записей написано
скопировано 103047168 байт (103 MB), 0,409461 c, 252 MB/c
252 MB/c и есть скорость.
А ты уверен, что ОЗУ может создать страницу памяти в 52 метра?
Я могу ошибаться, но мне кажется, что страницы памяти тут не при чем…
И даже еще раньше, как мне помнится. Суть использования оперативки для рамдиска в то время была в простом способе ускорения работы компьютера. Работа с файлами на стандартном диске была многократно медленнее чем с файлами на рамдиске, потому использование системных или пользовательских данных, к которым постоянно обращается пользователь или система, очень серьезно ускоряло работу за компьютером.
Вот здесь видно, что для ramfs скорость чтения/записи 2.3Гб/с:
ramdisk-host ~ # dd if=/dev/zero of=/mnt/ramfs/test-200m bs=1M count=200
200+0 записей считано
200+0 записей написано
скопировано 209715200 байт (210 MB), 0,0917934 c, 2,3 GB/c
это в 10 раз быстрее, чем для ramdisk и tmpfs. В tmpfs это может быть связано с использованием swap. Но все же, как еще можно объяснить такую скорость?
можно объяснить быстрой памятью )
Здравствуйте, господа любители линуксов.
Как можно объяснить, не побоюсь этого слова, безобразие?
# cat /etc/fstab | grep shm
shm /dev/shm ramfs defaults 0 0
# mount | grep shm
tmpfs on /dev/shm type tmpfs (rw,relatime)
Для вопросов типа “а нафига мне этот ущербный рамфс, когда есть тмпфс?”, ответ простой: требование инсталлятора оракла…
INFO: INFO: ERROR: [Result.addErrorDescription:635] PRVE-0420 : /dev/shm is not found mounted on node ""
INFO: INFO: FINE: [Task.perform:594]
INFO: PluggableTask(DEV_SHM_MOUNT):/dev/shm mounted as temporary file system[DEV_SHM_MOUNT]:TASK_SUMMARY:FAILED:IGNORABLE:VERIFICATION_FAILED
INFO: ERRORMSG(racnode2): PRVE-0420 : /dev/shm is not found mounted on node ""
так как же быть?
А что за дистрибутив, что за версия? Она соответствует System Requerements для инсталлятора оракла?
Скорее всего – в дистрибутиве выпелена поддержка ramfs и при парсинге /etc/fstab во время загрузки – просто монтируется как tmpfs.
Спасибо за пост. Недавно нужно было сравнить продуктивность(скорось), попал на этого пост – http://sysadm.pp.ua/linux/ram-and-tmp-fs.html . Было сравнение ram,tmp и ext4 файловых систем. Может пригодиться.
Да, статья интересная.
У меня ЦентОС и ядро ml-4x
И появилось 16 Рамдисков по 16Мб
И да ядро так скомпилировано, зачем не пойму? Не нашел как отключить или уменьшить в grub, еще поищу
[root@hp8200 etc]# free -h
total used free shared buffers cached
Mem: 15G 175M 15G 232K 8.0M 61M
-/+ buffers/cache: 106M 15G
Swap: 0B 0B 0B
[root@hp8200 etc]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 79G 1.3G 74G 2% /
tmpfs 7.8G 0 7.8G 0% /dev/shm
[root@hp8200 etc]#
А что это за память такая 7.8G ? Как она используется? Возможно в нее сама Ос грузится?
Можно ли как-то эти 16 Рамдиском с пользой, использовать, так чтобы создать к примеру рамдиск для /tmp, чтобы не убивать SSD – он же /dev/sda1.
Спасибо.
Я раздел shm постоянно использую.
Например, полезно при создании бэкапов.
Пишешь туда все что нужно забэкапить – там же жмешь и копируешь куда-нибудь.
Очень быстро работает )
Для чего ОС использует shm с ходу не скажу )
Нужно погуглить.
Имхо было бы очень полезно дополнить статью чисто практическими примерами, как перенести в рамдиск временные файлы, кэш браузеров и разместить там папку с торрентами, чтобы при раздаче не дёргать винчестер.
Спасибо за предложение, Влад.
И спасибо что читаете блог. Один из примеров есть в статье – tmpfs для сервера печати.
В целом, подход везде один – изменить настройки приложения, чтобы запись была на примонтированный раздел tmpfs.