From 54b90cb6e537a899728c5a9c4fe9e7220003222e Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 9 Jan 2023 18:22:56 +0100 Subject: [PATCH] btrfs-progs: fi mkswapfile: fix page count in header Per user report on https://old.reddit.com/r/btrfs/comments/107fnw1/btrfs_filesystem_mkswapfile_results_in_an/ the swapfile header does not contain the correct number of pages that matches the file size and the activated swapfile is only 1GiB: # btrfs filesystem mkswapfile -s 10g swapfile # swapon swapfile # cat /proc/swaps Filename Type Size Used Priority /swap/swapfile file 1048572 0 -2 A workaround is to run 'mkswap swapfile' before activation. Proper fix is to calculate the number of (fixed size) 4K pages available for the swap. Issue: #568 Signed-off-by: David Sterba --- Documentation/btrfs-filesystem.rst | 6 ++++- cmds/filesystem.c | 40 ++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/Documentation/btrfs-filesystem.rst b/Documentation/btrfs-filesystem.rst index 24d7157d..bd1161ac 100644 --- a/Documentation/btrfs-filesystem.rst +++ b/Documentation/btrfs-filesystem.rst @@ -190,7 +190,7 @@ label [|] [] mkswapfile [-s size] file Create a new file that's suitable and formatted as a swapfile. Default - size is 2GiB, minimum size is 40KiB. + size is 2GiB, fixed page size 4KiB, minimum size is 40KiB. A swapfile must be created in a specific way: NOCOW and preallocated. Subvolume containing a swapfile cannot be snapshotted and blocks of an @@ -200,6 +200,10 @@ mkswapfile [-s size] file needs to be done by command ``swapon(8)``. See also command ``btrfs inspect-internal map-swapfile`` and the :doc:`Swapfile feature` description. + .. note:: + The command is a simplified version of 'mkswap', if you want to set + label, page size, or other parameters please use 'mkswap' proper. + ``Options`` -s|--size SIZE diff --git a/cmds/filesystem.c b/cmds/filesystem.c index 3f86346e..b189d7cb 100644 --- a/cmds/filesystem.c +++ b/cmds/filesystem.c @@ -1449,26 +1449,26 @@ static const char * const cmd_filesystem_mkswapfile_usage[] = { }; /* - * Swap signature in the first 4KiB, v2: + * Swap signature in the first 4KiB, v2, no label: * * 00000400 .. = 01 00 00 00 ff ff 03 00 00 00 00 00 cb 70 8e 60 - * ^^^^^^^^^^^ - * uuid 4B + * ^^^^^^^^^^^ ^^^^^^^^^^^ + * page count 4B uuid 4B * 00000420 .. = 1d fb 4e ca be d4 3f 1f 6a 6b 0c 03 00 00 00 00 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * uuid 8B * 00000ff0 .. = 00 00 00 00 00 00 53 57 41 50 53 50 41 43 45 32 * S W A P S P A C E 2 */ -static int write_swap_signature(int fd) +static int write_swap_signature(int fd, u32 page_count) { int ret; - static unsigned char swap[4096] = { + static unsigned char swap[SZ_4K] = { [0x400] = 0x01, - [0x404] = 0xff, - [0x405] = 0xff, - [0x406] = 0x03, + /* 0x404 .. 0x407 number of pages (little-endian) */ + /* 0x408 .. 0x40b number of bad pages (unused) */ /* 0x40c .. 0x42b UUID */ + /* Last bytes of the page */ [0xff6] = 'S', [0xff7] = 'W', [0xff8] = 'A', @@ -1480,9 +1480,11 @@ static int write_swap_signature(int fd) [0xffe] = 'E', [0xfff] = '2', }; + u32 *pages = (u32 *)&swap[0x404]; + *pages = cpu_to_le32(page_count); uuid_generate(&swap[0x40c]); - ret = pwrite(fd, swap, 4096, 0); + ret = pwrite(fd, swap, SZ_4K, 0); return ret; } @@ -1494,6 +1496,7 @@ static int cmd_filesystem_mkswapfile(const struct cmd_struct *cmd, int argc, cha const char *fname; unsigned long flags; u64 size = SZ_2G; + u64 page_count; optind = 0; while (1) { @@ -1545,7 +1548,22 @@ static int cmd_filesystem_mkswapfile(const struct cmd_struct *cmd, int argc, cha ret = 1; goto out; } - pr_verbose(LOG_INFO, "fallocate to size %llu\n", size); + page_count = size / SZ_4K; + if (page_count <= 10) { + error("file too short"); + ret = 1; + goto out; + } + /* First file page with header */ + page_count--; + if (page_count > (u32)-1) { + error("file too big"); + ret = 1; + goto out; + } + size = round_down(size, SZ_4K); + pr_verbose(LOG_INFO, "fallocate to size %llu, page size %u, %llu pages\n", + size, SZ_4K, page_count); ret = fallocate(fd, 0, 0, size); if (ret < 0) { error("cannot fallocate file: %m"); @@ -1553,7 +1571,7 @@ static int cmd_filesystem_mkswapfile(const struct cmd_struct *cmd, int argc, cha goto out; } pr_verbose(LOG_INFO, "write swap signature\n"); - ret = write_swap_signature(fd); + ret = write_swap_signature(fd, page_count); if (ret < 0) { error("cannot write swap signature: %m"); ret = 1;