Использование ramdisk в Linux (ramdisk, ramfs, tmpfs) или препарирование рамдисков

Апрель 11th, 2013 Рубрики: Linux, Настройка сервера Linux, основы Linux

ramfs,tmpfs,ramdisk

Приветствую, уважаемые гости и постоянные читатели моего блога о 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...):

  1. имеет строго фиксированный размер (задается при компиляции ядра). За рамки этого размера наполняемые данные выйти не смогут, выдав соответствующее сообщение о нехватке места.
  2. должен быть отформатирован в какую-либо файловую систему. Обычно для этой цели рекомендуется ext2, т.к. для данных хранимых в оперативной памяти нет необходимости обладать свойством журналирования.
  3. ramdisk должен быть примонтирован в какую-либо точку монтирования. Приложения с примонтированным диском ramdisk будут работать как с обычным жестким диском, но инструментами ядра драйверами - все данные "физически" будут размещаться в ОЗУ.

Недостатки ramdisk:

  1. Так как ramdisk работает как обычное блочное устройство с файловой системой, оно точно так же использует возможности кэширования данных записываемых на файловую систему и считываемых оттуда. Из этого можно сделать вывод, что данный вид рамдиска использует дополнительные ресурсы памяти и CPU для управления файловой системой, кэшем.
  2. Имея фиксированный размер, ramdisk не может использовать swap раздел, если не хватает свободной физической памяти.
  3. Стоит так же отметить, что изменить размер 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 »

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 »

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 »

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 »

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

out of memory при переполнении ramdisk

Как говориться, за что боролись, на то и напоролись ) Следующий нюанс при работе с ramdisk, который я бы хотел затронуть - это как изменить размер ramdisk. С учетом примеров выше, становится понятно, что подключив нужный модуль в ядро с помощью нужной команды (insmod) и подходящих параметров (rd_size), можно изменить размер без перезагрузки. Но как же нам поступить в случае, если ramdisk интегрирован в ядро? В данном случае имеется два пути (по крайней мере, я больше не знаю...):

  1. Указать в параметрах загрузки ядра значение в виде ramdisk=xxxK. (В Debian, например, это делается в /etc/default/grub. В RedHat - это (вроде) /etc/sysconfig/grub, но могу ошибаться)
  2. Есть более серьезный путь - пересобрать ядро, изменив параметр CONFIG_BLK_DEV_RAM_SIZE на необходимое значение.

Итак подведем маленький итог ramdisk, допустим, не дочитав статью Вам ужас как хочется использовать данный рамдиск в работе, вам необходимо:

  1. Подключить модуля ядра (rd.ko или brd.ko), если ramdisk собран в ядре в модульном виде.
  2. Создать файловую систему на рамдиске
  3. Примонтировать рамдиск
  4. Пользоваться
  5. Если есть желание, чтобы данный диск монтировался при загрузке, то необходимо создать соответствующий скрипт с учетом вышеприведенных шагов и добавить с какой-нибудь загрузочный файл (например, /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.

Показать управление 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 crash test

Давайте попробуем разобраться в листинге. Как видно, при монтировании рамдиска ramfs размер оперативной памяти не изменился. Далее, записали 200Мб в примонтированный раздел. Интересный нюанс: ramfs использует область памяти, используемую в качестве cached. При этом, нужно понимать, что память забранная под cached ramfs'ом не будет возвращена приложениям при запросе!!! Далее, удаляем созданные 200Мб и ядро освобождает выданную ранее память. Ну и проверяем последнее утверждение, что рамдиск не ограничен по росту и видим как ядро в шоке )

tmpfs в linux

Особенности tmpfs в linux.

На текущий момент, tmpfs это самый совершенный рамдиск. Tmpfs ранее именовалась как shmfs (shared memory filesystem). Данная файловая система учла все достоинства прошлых рамдисков и включила исправленные недостатки:

  1. Раздел tmpfs можно ограничить по размеру,
  2. tmpfs при нехватке основной памяти научился использовать swap раздел.
  3. Если размер рамдиска не указан явно, то диск монтируется в половину размера ОЗУ.

В современных дистрибутивах 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:

Показать работа с tmpfs »

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М). Наполняем диск до предела и видим, что:

  1. скорость записи упала до 28,5 Мб
  2. 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



Теги: , , ,

Есть 6 коммент. к “Использование ramdisk в Linux (ramdisk, ramfs, tmpfs) или препарирование рамдисков”

  1. Павел
    Апрель 12th, 2013 at 11:16
    1

    Все подробно и по делу — вам надо переводы man-ов писать :).

  2. Vass
    Июль 16th, 2013 at 07:57
    2

    А как проверить скорость чтения, записи?

    • Июль 24th, 2013 at 09:53
      3

      В статье приведены примеры команды 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 и есть скорость.

  3. Арсен
    Апрель 18th, 2014 at 11:26
    4

    То есть можно сделать вывод, что из всех указанных параметров не отработал только max_part=2 (Почему?…решения пока не нашел)

    А ты уверен, что ОЗУ может создать страницу памяти в 52 метра?

    • Июнь 24th, 2014 at 19:48
      5

      Я могу ошибаться, но мне кажется, что страницы памяти тут не при чем…

  4. JKC
    Май 16th, 2014 at 16:22
    6

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

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

Написать комментарий