From patchwork Fri Jul 26 08:19:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Amann X-Patchwork-Id: 1137308 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.linux.it (client-ip=213.254.12.146; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.com Received: from picard.linux.it (picard.linux.it [213.254.12.146]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45w27Q6kLZz9sBF for ; Fri, 26 Jul 2019 18:19:44 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 8E64C3C1CA0 for ; Fri, 26 Jul 2019 10:19:38 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-2.smtp.seeweb.it (in-2.smtp.seeweb.it [IPv6:2001:4b78:1:20::2]) by picard.linux.it (Postfix) with ESMTP id 442343C1C88 for ; Fri, 26 Jul 2019 10:19:36 +0200 (CEST) Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-2.smtp.seeweb.it (Postfix) with ESMTPS id 4252D60102A for ; Fri, 26 Jul 2019 10:19:34 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 5BD2CB62D for ; Fri, 26 Jul 2019 08:19:34 +0000 (UTC) From: Christian Amann To: ltp@lists.linux.it Date: Fri, 26 Jul 2019 10:19:26 +0200 Message-Id: <20190726081926.8250-1-camann@suse.com> X-Mailer: git-send-email 2.16.4 X-Virus-Scanned: clamav-milter 0.99.2 at in-2.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-2.smtp.seeweb.it Subject: [LTP] [PATCH v1] syscalls/ioprio: Add functional test case X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Add ioprio_set03 which tests if the I/O priority set by the ioprio_set(2) syscall is taken into account when writing to files. Signed-off-by: Christian Amann --- Notes: This patch was written to be aplicable after the current test cases from Linus Walleij on the mailing list were corrected and applied. (That means, putting the runtest entires in place, moving the syscall function to the "ioprio.h" file, etc.) Slight adjustment could be necessary, though. runtest/syscalls | 1 + testcases/kernel/syscalls/ioprio/.gitignore | 1 + testcases/kernel/syscalls/ioprio/Makefile | 2 + testcases/kernel/syscalls/ioprio/ioprio_set03.c | 187 ++++++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_set03.c diff --git a/runtest/syscalls b/runtest/syscalls index 20e4ef0f5..2c205ae8e 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -543,6 +543,7 @@ ioprio_get01 ioprio_get01 ioprio_set01 ioprio_set01 ioprio_set02 ioprio_set02 +ioprio_set03 ioprio_set03 iopl01 iopl01 iopl02 iopl02 diff --git a/testcases/kernel/syscalls/ioprio/.gitignore b/testcases/kernel/syscalls/ioprio/.gitignore index 890081d8c..373079bf2 100644 --- a/testcases/kernel/syscalls/ioprio/.gitignore +++ b/testcases/kernel/syscalls/ioprio/.gitignore @@ -1,3 +1,4 @@ ioprio_get01 ioprio_set01 ioprio_set02 +ioprio_set03 diff --git a/testcases/kernel/syscalls/ioprio/Makefile b/testcases/kernel/syscalls/ioprio/Makefile index 5ea7d67db..647d296ca 100644 --- a/testcases/kernel/syscalls/ioprio/Makefile +++ b/testcases/kernel/syscalls/ioprio/Makefile @@ -4,3 +4,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +ioprio_set03: CFLAGS += -pthread diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set03.c b/testcases/kernel/syscalls/ioprio/ioprio_set03.c new file mode 100644 index 000000000..333723b3a --- /dev/null +++ b/testcases/kernel/syscalls/ioprio/ioprio_set03.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 SUSE LLC + * Author: Christian Amann + */ +/* + * Functional test to see if the I/O priority set with ioprio_set(2) + * has an effect when writing to files. + * + * In order to do so, this test mounts a loop device for which the + * I/O scheduler is set to either 'bfq' or 'cfq'. Then two write threads + * are started which both simultaneusly write to a file each. One thread + * is set to IDLE priority while the other is set to BE. + * If the thread with the higher I/O priority writes at least 10% more + * to its file, the test is successful. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include "tst_safe_pthread.h" +#include "tst_test.h" +#include "ioprio.h" + +#define MNTPOINT "MNTPOINT" +#define FILE1 MNTPOINT"/file1" +#define FILE2 MNTPOINT"/file2" +#define CHUNKSIZE (blksize > 8192 ? blksize : 8192) /* Bytes */ +#define IOTIME (2) /* Seconds */ + +#define SCHED_TEMPLATE "/sys/block/%s/queue/scheduler" + +static blksize_t blksize; + +static struct thread_data { + int fd; + pthread_t thread; + long prio; + int writes; + char *out_buf; +} tdata[2]; + +static void set_io_scheduler(const char *device_name) +{ + int fd; + unsigned int i; + const char * const schedulers[] = {"bfq", "cfq"}; + const char *used_scheduler = NULL; + char avail_schedulers[256]; + char sched_path[256]; + + sprintf(sched_path, SCHED_TEMPLATE, device_name); + + fd = SAFE_OPEN(sched_path, O_RDWR); + + SAFE_READ(0, fd, avail_schedulers, 255); + avail_schedulers[255] = '\0'; + + /* Check if right I/O schedulers are available */ + for (i = 0; i < ARRAY_SIZE(schedulers); ++i) { + if (strstr(avail_schedulers, schedulers[i])) + used_scheduler = schedulers[i]; + } + if (!used_scheduler) + tst_brk(TCONF, "Needed I/O schedulers are not available"); + + /* Set I/O scheduler */ + TEST(write(fd, used_scheduler, sizeof(used_scheduler))); + if (TST_RET < 0) + tst_brk(TBROK | TTERRNO, "Could not set I/O scheduler"); + + SAFE_CLOSE(fd); + + tst_res(TINFO, "Set I/O scheduler to '%s'", used_scheduler); + if (TST_RET < 0) + tst_brk(TBROK | TTERRNO, "Could not set I/O scheduler"); +} + +static void *io_thread(void *arg) +{ + long thread_num = (long) arg; + int ret; + + ret = sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, tdata[thread_num].prio); + if (ret == -1) + tst_brk(TBROK || TTERRNO, "ioprio_set() failed"); + + ret = sys_ioprio_get(IOPRIO_WHO_PROCESS, 0); + if (ret != tdata[thread_num].prio) + tst_brk(TBROK, "ioprio_set() set wrong priority"); + + /* align to blocksize for O_DIRECT writes */ + tdata[thread_num].out_buf = SAFE_MEMALIGN(blksize, CHUNKSIZE); + memset(tdata[thread_num].out_buf, 'X', CHUNKSIZE); + + tdata[thread_num].writes = 0; + while (1) { + SAFE_WRITE(1, tdata[thread_num].fd, + tdata[thread_num].out_buf, CHUNKSIZE); + tdata[thread_num].writes++; + if (tdata[thread_num].writes % 1000 == 0) + SAFE_LSEEK(tdata[thread_num].fd, 0, SEEK_SET); + } + + return arg; +} + +static void verify_ioprio(void) +{ + long i; + time_t time_started, time_spent = 0; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + for (i = 0; i < 2; i++) { + SAFE_PTHREAD_CREATE(&tdata[i].thread, NULL, + io_thread, (void *) i); + } + + time_started = time(NULL); + while (time_spent < IOTIME) { + time_spent = time(NULL) - time_started; + usleep(10000); + } + + for (i = 0; i < 2; i++) + pthread_cancel(tdata[i].thread); + + tst_res(TINFO, "Writes done with low priority: %d", tdata[0].writes); + tst_res(TINFO, "Writes done with high priority: %d", tdata[1].writes); + + /* High priority output should be at least 10% more */ + if (tdata[1].writes >= tdata[0].writes + tdata[0].writes/10.0) + tst_res(TPASS, "High priority write was successful"); + else + tst_res(TFAIL, "High priority write did not show any effect"); + + for (i = 0; i < 2; ++i) { + if (tdata[i].out_buf) + free(tdata[i].out_buf); + } +} + +static void setup(void) +{ + const char *device_name; + struct stat statbuf; + + device_name = &tst_device->dev[5]; /* skip '/dev/' prefix */ + + set_io_scheduler(device_name); + + tdata[0].fd = SAFE_OPEN(FILE1, O_RDWR | O_CREAT | O_DIRECT, 0644); + tdata[1].fd = SAFE_OPEN(FILE2, O_RDWR | O_CREAT | O_DIRECT, 0644); + + tdata[0].prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0); + tdata[1].prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0); + + SAFE_FSTAT(tdata[0].fd, &statbuf); + blksize = statbuf.st_blksize; + + tst_res(TINFO, "Blocksize: %ld", blksize); +} + +static void cleanup(void) +{ + if (tdata[1].fd > 0) + SAFE_CLOSE(tdata[1].fd); + if (tdata[0].fd > 0) + SAFE_CLOSE(tdata[0].fd); +} + +static struct tst_test test = { + .test_all = verify_ioprio, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNTPOINT, + .dev_min_size = 64, + .dev_fs_type = "ext4", +};