Categories
SysOps

How to use compressed RAM based block devices

Take advantage of compressed RAM based block devices to create temporary filesystems and swap disks.

Preliminary information

Operating system.

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.1 LTS
Release:        20.04
Codename:       focal

Verify that zram module is available.

$ modinfo zram
modinfo: ERROR: Module zram not found.

Install extra modules for the running kernel.

$ sudo apt install linux-modules-extra-$(uname -r)

Inspect module information.

$ modinfo zram
filename:       /lib/modules/5.4.0-54-generic/kernel/drivers/block/zram/zram.ko
description:    Compressed RAM Block Device
author:         Nitin Gupta <ngupta@vflare.org>
license:        Dual BSD/GPL
srcversion:     74320660DB5936B392634A5
depends:        
retpoline:      Y
intree:         Y
name:           zram
vermagic:       5.4.0-54-generic SMP mod_unload 
sig_id:         PKCS#7
signer:         Build time autogenerated kernel key
sig_key:        47:AF:FC:F1:86:66:29:ED:36:CF:32:E5:45:0F:C1:C8:85:38:3E:AF
sig_hashalgo:   sha512
signature:      30:27:58:D1:C9:B7:7B:E2:2D:92:3B:30:D1:AC:DC:A5:82:5D:20:8D:
                A0:59:BE:82:BB:97:47:5F:F8:0F:66:41:70:2B:D4:CE:75:DB:62:6A:
                B6:05:28:45:95:7B:4C:6B:A4:56:26:CC:7C:74:B8:DC:06:82:9E:53:
                16:67:95:5F:12:4A:47:1F:36:12:9D:2C:5E:96:00:9E:E4:CD:25:2C:
                CD:59:2E:53:6B:4A:B0:84:EF:F6:8B:B3:8D:7E:F9:23:5D:45:CC:50:
                E6:18:2E:C0:63:01:C7:23:D1:3B:58:B0:2B:24:84:C1:E5:49:FE:D6:
                82:37:AC:A5:54:3A:B7:C9:26:53:6C:9F:D3:82:0E:9C:41:A9:FF:85:
                54:A8:76:C9:12:4F:4B:60:6B:5E:97:FC:8C:F2:90:44:97:3A:31:E2:
                F0:C6:2A:88:5C:F6:F6:9B:F6:D2:80:BC:79:8B:B0:89:0A:BA:17:3B:
                C8:F9:E6:8E:BF:EA:ED:A4:4C:F3:6C:E8:F6:00:35:6A:EC:23:C9:4D:
                63:93:3F:F4:4B:EC:75:80:8E:57:01:12:F6:09:8A:34:07:AA:ED:D2:
                D1:89:09:60:C4:8B:A5:8D:4E:44:FE:77:F1:6A:F4:DD:9A:73:C1:FC:
                6F:90:42:BC:AD:D0:5F:C6:06:7F:EC:7B:C7:5B:7D:0B:D6:A7:C1:7D:
                BF:7F:BA:25:CB:9C:89:14:BD:31:6D:2C:A3:EC:46:DD:C6:AC:61:94:
                B1:E0:66:28:08:FA:21:EC:34:4A:BA:4B:1C:78:8A:CE:97:87:2E:31:
                43:CC:8E:3C:54:43:88:25:49:5C:1E:A1:63:52:ED:88:D0:76:66:31:
                3A:3C:BD:5F:92:68:11:92:BB:33:DE:5C:E5:96:95:5F:5E:07:24:45:
                3B:0C:6D:9E:6C:27:83:12:C3:EE:00:1E:A5:1F:32:21:32:9E:E6:88:
                7D:A3:B9:87:45:8E:B6:BF:35:E5:5A:33:19:B2:CE:99:A5:38:87:91:
                67:D1:26:91:CA:FF:ED:73:D8:31:A4:8C:E0:B6:0E:89:85:FE:8E:55:
                C0:61:02:8B:C1:60:C0:41:61:66:5A:93:0D:3F:5D:F1:17:C1:2B:DC:
                7D:1F:93:99:62:57:C9:2A:1F:AF:18:3B:0D:5A:DC:22:50:1A:A6:B4:
                9F:CD:7D:36:5D:BF:11:05:63:80:65:4F:EB:86:06:33:30:8D:D2:9A:
                20:7F:A0:3B:F4:6A:E8:61:D3:B1:20:E1:3E:ED:4B:03:0B:4C:4F:3A:
                BA:04:05:80:C5:68:8C:79:60:4B:E3:2D:66:28:DB:7B:25:2C:1F:7C:
                F9:B9:56:1D:36:AE:F0:30:DD:F2:F2:1E
parm:           num_devices:Number of pre-created zram devices (uint)

Load zram module. You can use num_devices parameter to create multiple devices immediately, but this is purely optional as you can always get the additional free device, one at a time.

$ sudo modprobe zram

Ensure that zram module will load at boot.

$ echo zram | sudo tee /etc/modules-load.d/zram.conf

If required, set num_devices parameter at boot.

$ echo options zram num_devices=4 | sudo tee /etc/modprobe.d/zram.conf

Familiarize yourself with the zramctl utility, which is included in the util-linux package.

$ zramctl --help
Usage:
 zramctl [options] <device>
 zramctl -r <device> [...]
 zramctl [options] -f | <device> -s <size>

Set up and control zram devices.

Options:
 -a, --algorithm lzo|lz4|lz4hc|deflate|842   compression algorithm to use
 -b, --bytes               print sizes in bytes rather than in human readable format
 -f, --find                find a free device
 -n, --noheadings          don't print headings
 -o, --output <list>       columns to use for status output
     --output-all          output all columns
     --raw                 use raw status output format
 -r, --reset               reset all specified devices
 -s, --size <size>         device size
 -t, --streams <number>    number of compression streams

 -h, --help                display this help
 -V, --version             display version

Available output columns:
        NAME  zram device name
    DISKSIZE  limit on the uncompressed amount of data
        DATA  uncompressed size of stored data
       COMPR  compressed size of stored data
   ALGORITHM  the selected compression algorithm
     STREAMS  number of concurrent compress operations
  ZERO-PAGES  empty pages with no allocated memory
       TOTAL  all memory including allocator fragmentation and metadata overhead
   MEM-LIMIT  memory limit used to store compressed data
    MEM-USED  memory zram have been consumed to store compressed data
    MIGRATED  number of objects migrated by compaction
  MOUNTPOINT  where the device is mounted

For more details see zramctl(8).

Create a temporary filesystem

Get a first free device. Use sudo, always use sudo to find and initialize the device or you will end up with a missing entry in /dev which can be hard to debug.

$ sudo zramctl --find
/dev/zram0

Create a new device with 1G disk size, using lz4 compression algorithm and two compression streams, which should be equal to the number of CPUs.

$ sudo zramctl --size 1G --algorithm lz4 --streams 2 /dev/zram0

Create a filesystem on this device with usage type indicating the need of inodes. The funny part is that it is very easy to hit limits on such small filesystems. This will allow 262144 instead of 65536 inodes.

$ sudo mkfs.ext2 -T news /dev/zram0
mke2fs 1.45.5 (07-Jan-2020)
Discarding device blocks: done                            
Creating filesystem with 262144 4k blocks and 65536 inodes
mke2fs 1.45.5 (07-Jan-2020)
Discarding device blocks: done                            
Creating filesystem with 262144 4k blocks and 262144 inodes
Filesystem UUID: 89ef9d1f-8c6b-46dd-891f-ae5b6e2795c4
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

Mount created filesystem and use it.

$ sudo mkdir /media/temporary
$ sudo mount /dev/zram0 /media/temporary/

Display usage information.

$ zramctl --output-all
NAME       DISKSIZE   DATA  COMPR ALGORITHM STREAMS ZERO-PAGES  TOTAL MEM-LIMIT MEM-USED MIGRATED MOUNTPOINT
/dev/zram0       1G 476.9M 154.7M lz4             2          8 162.4M        0B   162.4M       0B /media/temporary

This means that we are using 162.4M of memory to keep 476.9M data.

To remove device unmount it and reset.

$ sudo umount /dev/zram0
$ sudo zramctl --reset /dev/zram0

Create a temporary swap disk

Get a first free device.

$ sudo zramctl --find
/dev/zram1

Create a new device with 512M disk size, using lz4 compression algorithm and two compression streams.

$ sudo zramctl --size 512M --algorithm lz4 --streams 2 /dev/zram1

Create swap area.

$ sudo mkswap /dev/zram1
Setting up swapspace version 1, size = 512 MiB (536866816 bytes)
no label, UUID=f72a24f4-7b4f-45c8-bff5-38401af6a5ee

Activate swap using a high priority.

$ sudo swapon --priority 100 /dev/zram1

Display swap summary.

$ swapon  --summary
Filename                                Type            Size    Used    Priority
/dev/zram1                              partition       524284  256     100

Display usage information.

$ zramctl --output-all
NAME       DISKSIZE   DATA  COMPR ALGORITHM STREAMS ZERO-PAGES  TOTAL MEM-LIMIT MEM-USED MIGRATED MOUNTPOINT
/dev/zram1     512M    68K  11.2K lz4             2          0   136K        0B     136K       0B [SWAP]
/dev/zram0       1G 667.5M 245.9M lz4             2         16 257.4M      300M   257.4M       0B /media/temporary

To remove device disable it and reset.

$ sudo swapoff /dev/zram1
$ sudo zramctl --reset /dev/zram1

Additional notes

Read zram: Compressed RAM based block devices documentation for more information.

Every option used to create zram device is available in the sys filesystem.

$ ls /sys/block/zram0/
alignment_offset  comp_algorithm     disksize           hidden     integrity         mm_stat    reset   subsystem        writeback_limit_enable
backing_dev       compact            events             holders    io_stat           power      ro      trace
bd_stat           debug_stat         events_async       idle       max_comp_streams  queue      size    uevent
bdi               dev                events_poll_msecs  inflight   mem_limit         range      slaves  writeback
capability        discard_alignment  ext_range          initstate  mem_used_max      removable  stat    writeback_limit

You can use it to impose a memory limit which can be handy for a filesystem, but do not use it for swap disk.

$ echo 300M | sudo tee /sys/block/zram0/mem_limit

Create device.

$ sudo cat /sys/class/zram-control/hot_add
4

Remove specific device.

$ echo 3 | sudo tee /sys/class/zram-control/hot_remove
3

We created zram devices up to zram4, and removed zram3.

$ find /dev -maxdepth 1 -name "zram*"
/dev/zram4
/dev/zram2
/dev/zram1
/dev/zram0