[LTP] [PATCH] Increase pipe2() coverage.

laniel_francis@privacyrequired.com laniel_francis@privacyrequired.com
Sat Apr 4 19:50:55 CEST 2020


From: Francis Laniel <laniel_francis@privacyrequired.com>

A new test was added (pipe2_03.c), this test checks the following:
1. Create a pipe with O_NONBLOCK.
2. Check that this flag is set.
3. Check that pipe size is 65536B.
4. Reduce pipe size to 4096B.
5. Write buffer bigger than page size and see that second write fails.
6. Set pipe's flags to default.
7. Check that pipe is still full with select.
---
 testcases/kernel/syscalls/pipe2/.gitignore |   1 +
 testcases/kernel/syscalls/pipe2/pipe2_03.c | 215 +++++++++++++++++++++
 2 files changed, 216 insertions(+)
 create mode 100644 testcases/kernel/syscalls/pipe2/pipe2_03.c

diff --git a/testcases/kernel/syscalls/pipe2/.gitignore b/testcases/kernel/syscalls/pipe2/.gitignore
index cd38bb309..01d980dba 100644
--- a/testcases/kernel/syscalls/pipe2/.gitignore
+++ b/testcases/kernel/syscalls/pipe2/.gitignore
@@ -1,2 +1,3 @@
 /pipe2_01
 /pipe2_02
+/pipe2_03
diff --git a/testcases/kernel/syscalls/pipe2/pipe2_03.c b/testcases/kernel/syscalls/pipe2/pipe2_03.c
new file mode 100644
index 000000000..ea225fddc
--- /dev/null
+++ b/testcases/kernel/syscalls/pipe2/pipe2_03.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Francis Laniel, 2020                                         */
+/******************************************************************************/
+/******************************************************************************/
+/*                                                                            */
+/* File:        pipe2_03.c                                                    */
+/*                                                                            */
+/* Description: This Program tests getting and setting the pipe size.         */
+/*              It also tests what happen when you write to a full pipe       */
+/*              depending on whether O_NONBLOCK is or not.                    */
+/*                                                                            */
+/* Usage:  <for command-line>                                                 */
+/* pipe2_03 [-c n] [-e][-i n] [-I x] [-p x] [-t]                              */
+/*      where,  -c n : Run n copies concurrently.                             */
+/*              -e   : Turn on errno logging.                                 */
+/*              -i n : Execute test n times.                                  */
+/*              -I x : Execute test for x seconds.                            */
+/*              -P x : Pause for x seconds between iterations.                */
+/*              -t   : Turn on syscall timing.                                */
+/*                                                                            */
+/* Total Tests: 1                                                             */
+/*                                                                            */
+/* Test Name:   pipe2_03                                                      */
+/*                                                                            */
+/* Author:      Francis Laniel                                                */
+/*                                                                            */
+/* History:     Created - Mar 28 2020 - Francis Laniel                        */
+/******************************************************************************/
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <features.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/select.h>
+
+#include "tst_test.h"
+
+#define PAGE_NR 16
+#define READ_SIDE 0
+#define WRITE_SIDE 1
+#define SECONDS 3
+#define MICROSECONDS 0
+
+/**
+ * The two file descriptors of the pipe.
+ */
+static int fds[2];
+
+/**
+ * This variable will contain the system page size after setup.
+ */
+static long page_size;
+
+/**
+ * Setup everything.
+ * This function will:
+ * 1. Create the pipe with O_NONBLOCK.
+ * 2. Get system page size with sysconf().
+ */
+static void setup(void)
+{
+	/*
+	 * Check that Linux version is greater than 2.6.35 to be able to use
+	 * F_GETPIPE_SZ and F_SETPIPE_SZ.
+	 */
+	if (tst_kvercmp(2, 6, 35) < 0)
+		tst_brk(TCONF, "This test can only run on kernels that are 2.6.35 and higher");
+
+	/*
+	 * Create the pip with O_NONBLOCK.
+	 */
+	if (pipe2(fds, O_NONBLOCK))
+		tst_brk(TBROK | TERRNO, "pipe2() failed");
+
+	/*
+	 * Get the system page size.
+	 */
+	page_size = SAFE_SYSCONF(_SC_PAGESIZE);
+}
+
+/**
+ * Test everything.
+ */
+static void test_pipe2(void)
+{
+	int ret;
+
+	long flags;
+	long pipe_size;
+
+	char *buf;
+
+	fd_set set;
+	struct timeval timeout;
+
+	/*
+	 * Get the flags of the pipe.
+	 */
+	flags = SAFE_FCNTL(fds[0], F_GETFL);
+
+	if (!(flags & O_NONBLOCK))
+		tst_res(TFAIL, "O_NONBLOCK flag must be set.");
+
+	/*
+	 * Get the size of the pipe.
+	 */
+	pipe_size = SAFE_FCNTL(fds[0], F_GETPIPE_SZ);
+
+	if (pipe_size != page_size * PAGE_NR)
+		tst_res(TFAIL, "Default pipe page is 16 * 4096 = 65536B.");
+
+	/*
+	 * A pipe has two file descriptors.
+	 * But in the kernel these two file descriptors point to the same pipe.
+	 * So setting size from first file handle set size for the pipe.
+	 *
+	 * Moreover, the size of a pipe is exprimed in page.
+	 * So the minimal size of a pipe is a page size, setting its size to 0
+	 * leads to a pipe whom size is 4096B.
+	 */
+	SAFE_FCNTL(fds[0], F_SETPIPE_SZ, 0);
+
+	/*
+	 * So getting size from the second file descriptor return the size of
+	 * the pipe which was changed before with first file descriptor.
+	 */
+	pipe_size = SAFE_FCNTL(fds[1], F_GETPIPE_SZ);
+
+	if (pipe_size != page_size)
+		tst_res(TFAIL, "Pipe size (%ld) must be page size (%ld)",
+			pipe_size, page_size);
+
+	/*
+	 * Create a buffer of page size.
+	 * We create it in stack because we do not care of its lifetime.
+	 */
+	buf = alloca(page_size);
+
+	SAFE_WRITE(1, fds[WRITE_SIDE], buf, page_size);
+
+	/*
+	 * This write should return -1 because pipe is already full.
+	 */
+	if (write(fds[WRITE_SIDE], buf, page_size) != -1)
+		tst_res(TFAIL | TERRNO, "write() succeeded and should not");
+
+	/*
+	 * Remove the O_NONBLOCK parameter for the pipe.
+	 * After this call write to the pipe will be blocking.
+	 */
+	SAFE_FCNTL(fds[0], F_SETFL, flags & ~O_NONBLOCK);
+
+	/*
+	 * Get again the flags of the pipe.
+	 */
+	flags = SAFE_FCNTL(fds[0], F_GETFL);
+
+	if (flags & O_NONBLOCK)
+		tst_res(TFAIL, "O_NONBLOCK flag must not be set.");
+
+	/*
+	 * Empty the set so no garbage value is in it.
+	 */
+	FD_ZERO(&set);
+
+	/*
+	 * Add the write side of the pipe to the set.
+	 */
+	FD_SET(fds[WRITE_SIDE], &set);
+
+	if (!FD_ISSET(fds[WRITE_SIDE], &set))
+		tst_res(TFAIL, "Pipe must be in the set.");
+
+	timeout.tv_sec = SECONDS;
+	timeout.tv_usec = MICROSECONDS;
+
+	/*
+	 * Since writes are now blocking we use select to check if the pipe is
+	 * available to receive write.
+	 * Wait SECONDS seconds and MICROSECONDS microseconds on write side of
+	 * the pipe.
+	 */
+	ret = select(1, NULL, &set, NULL, &timeout);
+
+	if (ret == -1)
+		tst_res(TFAIL | TERRNO, "select() failed");
+
+	/*
+	 * The pipe is still full so select should return after the waiting time
+	 * returning 0 because write side of the pipe is not available because
+	 * it is full.
+	 */
+	if (ret)
+		tst_res(TFAIL, "Pipe is not full.");
+	else
+		tst_res(TPASS, "Pipe is still full.");
+}
+
+/**
+ * Clean everything either if test is finished or if something failed.
+ */
+static void cleanup(void)
+{
+	for (int i = 0; i < 2; i++)
+		if (fds[i])
+			SAFE_CLOSE(fds[i]);
+}
+
+static struct tst_test test = {
+	.test_all = test_pipe2,
+	.setup = setup,
+	.cleanup = cleanup,
+};
\ No newline at end of file
-- 
2.20.1



More information about the ltp mailing list