A swapfile, when active, is a file-backed swap area.  It is supported since kernel 5.0.
Use :manref:`swapon(8)` to activate it, until then (respectively again after deactivating it
with :manref:`swapoff(8)`) it's just a normal file (with NODATACOW set), for which the special
restrictions for active swapfiles don't apply.

There are some limitations of the implementation in BTRFS and Linux swap
subsystem:

* filesystem - must be only single device
* filesystem - must have only *single* data profile
* subvolume - cannot be snapshotted if it contains any active swapfiles
* swapfile - must be preallocated (i.e. no holes)
* swapfile - must be NODATACOW (i.e. also NODATASUM, no compression)

The limitations come namely from the COW-based design and mapping layer of
blocks that allows the advanced features like relocation and multi-device
filesystems. However, the swap subsystem expects simpler mapping and no
background changes of the file block location once they've been assigned to
swap. The constraints mentioned above (single device and single profile) are
related to the swapfile itself, i.e. the extents and their placement. It is
possible to create swapfile on multi-device filesystem as long as the extents
are on one device but this cannot be affected by user and depends on free space
fragmentation and available unused space for new chunks.

With active swapfiles, the following whole-filesystem operations will skip
some block groups or may fail:

* balance - block groups with extents of any active swapfiles are skipped and
  reported through dmesg, the rest will be processed normally
* scrub - ditto
* resize grow - unaffected
* resize shrink - works as long as the extents of any active swapfiles are
  outside of the shrunk range
* device add - if the new devices do not interfere with any already active swapfiles
  this operation will work, though no new swapfile can be activated
  afterwards
* device delete - if the device has been added as above, it can be also deleted
* device replace - ditto

The above limitations will significantly affect btrfs maintenance routines,
namely balance and scrub.  Balance and scrub will skip those block groups which
have extents of an active swapfile on them, and those block groups may also
contain extents belonging to other files.  This means swapfiles will have an
amplified impact, much larger than the size of the swapfile itself.

For balance, it means data block groups may not be properly balanced, causing
unbalanced data/metadata usage, which can lead to early ENOSPC errors.

For scrub, it means data block groups may not be verified, degrading the
integrity of data.

Users should be aware of the impact when using swapfiles alongside other data.
This is especially discouraged for root filesystem.

When there are no active swapfiles and a whole-filesystem exclusive operation
is running (e.g. balance, device delete, shrink), the swapfiles cannot be
temporarily activated. The operation must finish first.

To create and activate a swapfile run the following commands:

.. code-block:: bash

        # truncate -s 0 swapfile
        # chattr +C swapfile
        # fallocate -l 2G swapfile
        # chmod 0600 swapfile
        # mkswap swapfile
        # swapon swapfile

Since version 6.1 it's possible to create the swapfile in a single command
(except the activation):

.. code-block:: bash

        # btrfs filesystem mkswapfile --size 2G swapfile
        # swapon swapfile

Please note that the UUID returned by the *mkswap* utility identifies the swap
"filesystem" and because it's stored in a file, it's not generally visible and
usable as an identifier unlike if it was on a block device.

Once activated the file will appear in :file:`/proc/swaps`:

.. code-block:: none

        # cat /proc/swaps
        Filename          Type          Size           Used      Priority
        /path/swapfile    file          2097152        0         -2

The swapfile can be created as one-time operation or, once properly created,
activated on each boot by the :command:`swapon -a` command (usually started by the
service manager). Add the following entry to */etc/fstab*, assuming the
filesystem that provides the */path* has been already mounted at this point.
Additional mount options relevant for the swapfile can be set too (like
priority, not the BTRFS mount options).

.. code-block:: none

        /path/swapfile        none        swap        defaults      0 0

From now on the subvolume with the active swapfile cannot be snapshotted until
the swapfile is deactivated again by :command:`swapoff`. Then the swapfile is a
regular file and the subvolume can be snapshotted again, though this would prevent
another activation any swapfile that has been snapshotted. New swapfiles (not
snapshotted) can be created and activated.

Otherwise, an inactive swapfile does not affect the containing subvolume. Activation
creates a temporary in-memory status and prevents some file operations, but is
not stored permanently.

Hibernation
-----------

A swapfile can be used for hibernation but it's not straightforward. Before
hibernation a resume offset must be written to file */sys/power/resume_offset*
or the kernel command line parameter *resume_offset* must be set.

The value is the physical offset on the device. Note that **this is not the same
value that** :command:`filefrag` **prints as physical offset!**

Btrfs filesystem uses mapping between logical and physical addresses but here
the physical can still map to one or more device-specific physical block
addresses. It's the device-specific physical offset that is suitable as resume
offset.

Since version 6.1 there's a command :ref:`btrfs inspect-internal map-swapfile<man-inspect-map-swapfile>`
that will print the device physical offset and the adjusted value for
:file:`/sys/power/resume_offset`.  Note that the value is divided by page size, i.e.
it's not the offset itself.

.. code-block:: bash

        # btrfs filesystem mkswapfile swapfile
        # btrfs inspect-internal map-swapfile swapfile
        Physical start: 811511726080
        Resume offset:     198122980

For scripting and convenience the option *-r* will print just the offset:

.. code-block:: bash

        # btrfs inspect-internal map-swapfile -r swapfile
        198122980

The command :command:`map-swapfile` also verifies all the requirements, i.e. no holes,
single device, etc.


Troubleshooting
---------------

If the swapfile activation fails please verify that you followed all the steps
above or check the system log (e.g. :command:`dmesg` or :command:`journalctl`) for more
information.

Notably, the :command:`swapon` utility exits with a message that does not say what
failed:

.. code-block:: none

        # swapon /path/swapfile
	swapon: /path/swapfile: swapon failed: Invalid argument

The specific reason is likely to be printed to the system log by the btrfs
module:

.. code-block:: none

	# journalctl -t kernel | grep swapfile
	kernel: BTRFS warning (device sda): swapfile must have single data profile
