[LTP] [PATCH v2 3/5] swapon03: Try to swapon() as many files until it fails

Petr Vorel
2025-11-06T16:36:14Z

Previously tst_max_swapfiles() had fine tuning for a specific kernel
version which was fragile due various backports in enterprise kernels.

Let's try to create and use as many swap files until swapon() fails.
Then check for expected EPERM.

Also test swapon() 2x, first in the setup() when first failure happen,
then in the test function (easier than propagate errno from fork to the
main function).

Suggested-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
Changes v1->v2:
* Test first swapon() call (Avinesh). For simplicity and -i working
properly is swapon() tested twice.
* Use correct variable in TCONF message (Avinesh)
* Improve doc (Li)

testcases/kernel/syscalls/swapon/swapon03.c | 68 ++++++++++++++-------
1 file changed, 46 insertions(+), 22 deletions(-)

diff --git a/testcases/kernel/syscalls/swapon/swapon03.c b/testcases/kernel/syscalls/swapon/swapon03.c
index d9822c01ef..a8e0cbcdc6 100644
--- a/testcases/kernel/syscalls/swapon/swapon03.c
+++ b/testcases/kernel/syscalls/swapon/swapon03.c
@@ -1,14 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
+ * Copyright (c) Linux Test Project, 2009-2025
* Copyright (c) International Business Machines Corp., 2007
* Created by <rsalveti@linux.vnet.ibm.com>
- *
*/

/*\
- * This test case checks whether swapon(2) system call returns:
+ * Test checks whether :man2:`swapon` system call returns EPERM when the maximum
+ * number of swap files are already in use.
*
- * - EPERM when there are more than MAX_SWAPFILES already in use.
+ * NOTE: test does not try to calculate MAX_SWAPFILES from the internal
+ * kernel implementation, instead make sure few swaps were created before
+ * maximum was reached.
*/

#include <stdio.h>
@@ -20,48 +23,61 @@
#include "lapi/syscalls.h"
#include "libswap.h"

+/*
+ * MAX_SWAPFILES from the internal kernel implementation is currently <23, 29>,
+ * depending on kernel configuration (see man swapon(2). Chose small enough
+ * value for future changes.
+ */
+#define NUM_SWAP_FILES 15
+
#define MNTPOINT "mntpoint"
#define TEST_FILE MNTPOINT"/testswap"

-static int swapfiles;
+static int *swapfiles;

static void setup_swap(void)
{
pid_t pid;
- int status;
- int j, max_swapfiles, used_swapfiles;
+ int status, used_swapfiles, expected_swapfiles;
char filename[FILENAME_MAX];

SAFE_SETEUID(0);

- /* Determine how many more files are to be created */
- max_swapfiles = tst_max_swapfiles();
used_swapfiles = tst_count_swaps();
- swapfiles = max_swapfiles - used_swapfiles;
- if (swapfiles > max_swapfiles)
- swapfiles = max_swapfiles;
+ expected_swapfiles = NUM_SWAP_FILES - used_swapfiles;
+
+ if (expected_swapfiles < 0)
+ tst_brk(TCONF, "too many used swap files (%d)", used_swapfiles);

pid = SAFE_FORK();
if (pid == 0) {
- /*create and turn on remaining swapfiles */
- for (j = 0; j < swapfiles; j++) {
-
+ while (true) {
/* Create the swapfile */
- snprintf(filename, sizeof(filename), "%s%02d", TEST_FILE, j + 2);
+ snprintf(filename, sizeof(filename), "%s%02d", TEST_FILE, *swapfiles);
MAKE_SMALL_SWAPFILE(filename);

- /* turn on the swap file */
- TST_EXP_PASS_SILENT(swapon(filename, 0));
+ /* Quit on a first swap file over max, check for EPERM */
+ if (swapon(filename, 0) == -1) {
+ if (errno != EPERM)
+ tst_res(TFAIL | TERRNO, "swapon(%s, 0)", filename);
+ break;
+ }
+ (*swapfiles)++;
}
exit(0);
} else {
waitpid(pid, &status, 0);
}

- if (WEXITSTATUS(status))
+ if (WEXITSTATUS(status) || *swapfiles == 0)
tst_brk(TBROK, "Failed to setup swap files");

- tst_res(TINFO, "Successfully created %d swap files", swapfiles);
+ if (*swapfiles < expected_swapfiles) {
+ tst_res(TWARN, "Successfully created only %d swap files (>= %d expected)",
+ *swapfiles, expected_swapfiles);
+ } else {
+ tst_res(TINFO, "Successfully created %d swap files", *swapfiles);
+ }
}

/*
@@ -85,8 +101,8 @@ static void clean_swap(void)
int j;
char filename[FILENAME_MAX];

- for (j = 0; j < swapfiles; j++) {
- snprintf(filename, sizeof(filename), "%s%02d", TEST_FILE, j + 2);
+ for (j = 0; j < *swapfiles; j++) {
+ snprintf(filename, sizeof(filename), "%s%02d", TEST_FILE, j);
check_and_swapoff(filename);
}

@@ -104,12 +120,20 @@ static void setup(void)
tst_brk(TCONF, "swap not supported by kernel");

is_swap_supported(TEST_FILE);
+
+ swapfiles = SAFE_MMAP(NULL, sizeof(*swapfiles), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ *swapfiles = 0;
+
setup_swap();
}

static void cleanup(void)
{
- clean_swap();
+ if (swapfiles) {
+ clean_swap();
+ SAFE_MUNMAP(swapfiles, sizeof(*swapfiles));
+ }
}

static struct tst_test test = {
--
2.51.0