From patchwork Mon Jan 28 13:46:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyril Hrubis X-Patchwork-Id: 10783703 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 19830184E for ; Mon, 28 Jan 2019 13:50:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 072A72AC06 for ; Mon, 28 Jan 2019 13:50:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 04CD32AC61; Mon, 28 Jan 2019 13:50:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A745D2AC06 for ; Mon, 28 Jan 2019 13:50:07 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 95BF28E0007; Mon, 28 Jan 2019 08:50:06 -0500 (EST) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 8E53F8E0001; Mon, 28 Jan 2019 08:50:06 -0500 (EST) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7865B8E0007; Mon, 28 Jan 2019 08:50:06 -0500 (EST) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) by kanga.kvack.org (Postfix) with ESMTP id 14AA58E0001 for ; Mon, 28 Jan 2019 08:50:06 -0500 (EST) Received: by mail-ed1-f70.google.com with SMTP id c34so6493797edb.8 for ; Mon, 28 Jan 2019 05:50:06 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-original-authentication-results:x-gm-message-state:from:to:cc :subject:date:message-id:mime-version:content-transfer-encoding; bh=Vakv3OTUghxnZMPagsTlDiD7LEklNX9zLIFkQ4RBn7s=; b=cVw17/+/cmx5OI3RJkoUwEQKZ7y/j4xaRttmInNjxVNMzAA7g3hj9Gxuq+WkxXPUbL /fL2VJG0qy/z5PlE44yipXN02LfTuD2vd+a0BSvvoLqsxn7TdqIavOGhf0845mpuj+Kj yNO25DNvYrL6NnNUoZ2ozdC5l/AMSF1QVh5EVgpsumB/qSfG4avI9KuKMKzuh/6xaMr+ JnOcYagCCh9+6oOHaOFj1f01yA2gdNr64xmYVu7V0vFY/LbqeNjaGBupwmKZ/SmYgctZ Dzv1TF9TK/DJNua3Twu2ZBXhQSmJZk/K1ZSLTqUKn0aXLHZS1jRz56JMH9HYhhj/NAtY GCpw== X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of metan@suse.de designates 195.135.220.15 as permitted sender) smtp.mailfrom=metan@suse.de X-Gm-Message-State: AJcUukcD0b8nAb2wCiSc4ENAwGb5YeY/XTwaf7ovjljiSNd1p7opimqX dEW4gpWaEK9vlPUHf+kK4hKIHHjLH6+jGgB5B1GYTVMHn1CyTZ2yd620wjZ6/MYFAgDgGbfAnuD cv8n0Dn9fgz3SWIVG9RXgaJtSVJfmBbBE1QPHhTGDg2zBBrIXiLhGteajQya6yqo= X-Received: by 2002:a50:c299:: with SMTP id o25mr22140656edf.281.1548683405469; Mon, 28 Jan 2019 05:50:05 -0800 (PST) X-Google-Smtp-Source: ALg8bN4hwh05QQ9/CQd5MFixNBww87Zx9SrM365U8PVgZVWCm7pxQ2DzGbQcyyh//zN7clV4AXE/ X-Received: by 2002:a50:c299:: with SMTP id o25mr22140566edf.281.1548683403996; Mon, 28 Jan 2019 05:50:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1548683403; cv=none; d=google.com; s=arc-20160816; b=iGvkSR5xzn3b7OW4rfUl1FAIFVl/srDFzNs38VZxoghOculfSIhqBxZTO5uLJ31GVb b5CkYAy0a33MDBFigG0WEfq9CeY6G2cEM2OZvF0L4SCaypqx/34Vw1C+dQEwRMEHxoMR NwSSLkN9vbyeIbsouE4ZpkjEXStSjavaoocTXM6bf13dCf68EBizOyAC+8cmGMAU9Jb8 0byx1X7mOSd5d6r7AVv78KJFUGAacHu3CEsPbOxjhmYJdGALax/K2HJYHt0gQjSE3/tu onMnBPtqOAiXRz1yyCBiNq5mzIsYbontQB/7zjRnWQSCINfqW8e29IIGiht1aH+YMzuf lBEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from; bh=Vakv3OTUghxnZMPagsTlDiD7LEklNX9zLIFkQ4RBn7s=; b=jfwSCTgV26V4nAXqL3HWCIudhC3Rdba61Kqgw+TmcgqiBvYWPLL7/2841NKqqAKSCz JHHOb9oxGNltxqQFZCsOpcxtD3g+PCQw6sN1IM6tITYfon50IJWnsMP692PlNAjaGC3M VmaOo+mTwCjZGTzNcxh9HAcHlbAWk7mLWan7vwVj31fUS8OweYs6ingqQ/unu1D2Zw++ vVwoO9e/7KEtIkNWIJqcfLI4qqeWNl9ygoJmHPDsJJeEgkiPMt1pE8XGd2rr8Zo7Rz86 +h8KxFfXIzFwVS4D7BCwcUxz8fpqxqe5Fbc8K09i2fQnLsSjjgTuytcxq1xmnLUbnQGY VSfw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of metan@suse.de designates 195.135.220.15 as permitted sender) smtp.mailfrom=metan@suse.de Received: from mx1.suse.de (mx2.suse.de. [195.135.220.15]) by mx.google.com with ESMTPS id o4-v6si298364eje.73.2019.01.28.05.50.03 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 28 Jan 2019 05:50:03 -0800 (PST) Received-SPF: pass (google.com: domain of metan@suse.de designates 195.135.220.15 as permitted sender) client-ip=195.135.220.15; Authentication-Results: mx.google.com; spf=pass (google.com: domain of metan@suse.de designates 195.135.220.15 as permitted sender) smtp.mailfrom=metan@suse.de X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 851EDACBF; Mon, 28 Jan 2019 13:50:03 +0000 (UTC) From: Cyril Hrubis To: ltp@lists.linux.it Cc: Cyril Hrubis , Jiri Kosina , Linux-MM , kernel list , Linux API Subject: [PATCH] syscalls/preadv203: Add basic RWF_NOWAIT test Date: Mon, 28 Jan 2019 14:46:56 +0100 Message-Id: <20190128134656.27979-1-metan@ucw.cz> X-Mailer: git-send-email 2.19.2 MIME-Version: 1.0 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Cyril Hrubis We are attempting to trigger the EAGAIN path for the RWF_NOWAIT flag. In order to do so the test runs three threads: * nowait_reader: reads from a random offset from a random file with RWF_NOWAIT flag and expects to get EAGAIN and short read sooner or later * writer_thread: rewrites random file in order to keep the underlying device bussy so that pages evicted from cache cannot be faulted immediatelly * cache_dropper: attempts to evict pages from a cache in order for reader to hit evicted page sooner or later Signed-off-by: Cyril Hrubis CC: Jiri Kosina CC: Linux-MM CC: kernel list CC: Linux API --- I was wondering if we can do a better job at flushing the caches. Is there an interface for flusing caches just for the device we are using for the test? Also the RWF_NOWAIT should probably be benchmarked as well but that is completely out of scope for LTP. runtest/syscalls | 2 + testcases/kernel/syscalls/preadv2/.gitignore | 2 + testcases/kernel/syscalls/preadv2/Makefile | 4 + testcases/kernel/syscalls/preadv2/preadv203.c | 266 ++++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 testcases/kernel/syscalls/preadv2/preadv203.c diff --git a/runtest/syscalls b/runtest/syscalls index 34b47f36b..a69c431f1 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -853,6 +853,8 @@ preadv201 preadv201 preadv201_64 preadv201_64 preadv202 preadv202 preadv202_64 preadv202_64 +preadv203 preadv203 +preadv203_64 preadv203_64 profil01 profil01 diff --git a/testcases/kernel/syscalls/preadv2/.gitignore b/testcases/kernel/syscalls/preadv2/.gitignore index 759d9ef5b..98b81abea 100644 --- a/testcases/kernel/syscalls/preadv2/.gitignore +++ b/testcases/kernel/syscalls/preadv2/.gitignore @@ -2,3 +2,5 @@ /preadv201_64 /preadv202 /preadv202_64 +/preadv203 +/preadv203_64 diff --git a/testcases/kernel/syscalls/preadv2/Makefile b/testcases/kernel/syscalls/preadv2/Makefile index fc1fbf3c7..fbedd0287 100644 --- a/testcases/kernel/syscalls/preadv2/Makefile +++ b/testcases/kernel/syscalls/preadv2/Makefile @@ -11,4 +11,8 @@ include $(abs_srcdir)/../utils/newer_64.mk %_64: CPPFLAGS += -D_FILE_OFFSET_BITS=64 +preadv203: CFLAGS += -pthread +preadv203_64: CFLAGS += -pthread +preadv203_64: LDFLAGS += -pthread + include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/preadv2/preadv203.c b/testcases/kernel/syscalls/preadv2/preadv203.c new file mode 100644 index 000000000..a6d5300f9 --- /dev/null +++ b/testcases/kernel/syscalls/preadv2/preadv203.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Cyril Hrubis + */ + +/* + * This is a basic functional test for RWF_NOWAIT flag, we are attempting to + * force preadv2() either to return a short read or EAGAIN with three + * concurelntly running threads: + * + * nowait_reader: reads from a random offset from a random file with + * RWF_NOWAIT flag and expects to get EAGAIN and short + * read sooner or later + * + * writer_thread: rewrites random file in order to keep the underlying device + * bussy so that pages evicted from cache cannot be faulted + * immediatelly + * + * cache_dropper: attempts to evict pages from a cache in order for reader to + * hit evicted page sooner or later + */ + +/* + * If test fails with EOPNOTSUPP you have likely hit a glibc bug: + * + * https://sourceware.org/bugzilla/show_bug.cgi?id=23579 + * + * Which can be worked around by calling preadv2() directly by syscall() such as: + * + * static ssize_t sys_preadv2(int fd, const struct iovec *iov, int iovcnt, + * off_t offset, int flags) + * { + * return syscall(SYS_preadv2, fd, iov, iovcnt, offset, offset>>32, flags); + * } + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "lapi/preadv2.h" + +#define CHUNK_SZ 4123 +#define CHUNKS 60 +#define MNTPOINT "mntpoint" +#define FILES 1000 + +static int fds[FILES]; + +static volatile int stop; + +static void drop_caches(void) +{ + SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); +} + +/* + * All files are divided in chunks each filled with the same bytes starting with + * '0' at offset 0 and with increasing value on each next chunk. + * + * 000....000111....111.......AAA......AAA... + * | chunk0 || chunk1 | ... | chunk17 | + */ +static int verify_short_read(struct iovec *iov, size_t iov_cnt, + off_t off, size_t size) +{ + unsigned int i; + size_t j, checked = 0; + + for (i = 0; i < iov_cnt; i++) { + char *buf = iov[i].iov_base; + for (j = 0; j < iov[i].iov_len; j++) { + char exp_val = '0' + (off + checked)/CHUNK_SZ; + + if (exp_val != buf[j]) { + tst_res(TFAIL, + "Wrong value read pos %zu size %zu %c (%i) %c (%i)!", + checked, size, exp_val, exp_val, + isprint(buf[j]) ? buf[j] : ' ', buf[j]); + return 1; + } + + if (++checked >= size) + return 0; + } + } + + return 0; +} + +static void *nowait_reader(void *unused LTP_ATTRIBUTE_UNUSED) +{ + char buf1[CHUNK_SZ/2]; + char buf2[CHUNK_SZ]; + unsigned int full_read_cnt = 0, eagain_cnt = 0; + unsigned int short_read_cnt = 0, zero_read_cnt = 0; + + struct iovec rd_iovec[] = { + {buf1, sizeof(buf1)}, + {buf2, sizeof(buf2)}, + }; + + while (!stop) { + if (eagain_cnt >= 100 && short_read_cnt >= 10) + stop = 1; + + /* Ensure short reads doesn't happen because of tripping on EOF */ + off_t off = random() % ((CHUNKS - 2) * CHUNK_SZ); + int fd = fds[random() % FILES]; + + TEST(preadv2(fd, rd_iovec, 2, off, RWF_NOWAIT)); + + if (TST_RET < 0) { + if (TST_ERR != EAGAIN) + tst_brk(TBROK | TTERRNO, "preadv2() failed"); + + eagain_cnt++; + continue; + } + + + if (TST_RET == 0) { + zero_read_cnt++; + continue; + } + + if (TST_RET != CHUNK_SZ + CHUNK_SZ/2) { + verify_short_read(rd_iovec, 2, off, TST_RET); + short_read_cnt++; + continue; + } + + full_read_cnt++; + } + + tst_res(TINFO, + "Number of full_reads %u, short reads %u, zero len reads %u, EAGAIN(s) %u", + full_read_cnt, short_read_cnt, zero_read_cnt, eagain_cnt); + + return (void*)(long)eagain_cnt; +} + +static void *writer_thread(void *unused) +{ + char buf[CHUNK_SZ]; + unsigned int j, write_cnt = 0; + + struct iovec wr_iovec[] = { + {buf, sizeof(buf)}, + }; + + while (!stop) { + int fd = fds[random() % FILES]; + + for (j = 0; j < CHUNKS; j++) { + memset(buf, '0' + j, sizeof(buf)); + + off_t off = CHUNK_SZ * j; + + if (pwritev(fd, wr_iovec, 1, off) < 0) { + if (errno == EBADF) { + tst_res(TBROK | TERRNO, "FDs closed?"); + return unused; + } + + tst_brk(TBROK | TERRNO, "pwritev()"); + } + + write_cnt++; + } + } + + tst_res(TINFO, "Number of writes %u", write_cnt); + + return unused; +} + +static void *cache_dropper(void *unused) +{ + unsigned int drop_cnt = 0; + + while (!stop) { + drop_caches(); + drop_cnt++; + } + + tst_res(TINFO, "Cache dropped %u times", drop_cnt); + + return unused; +} + +static void verify_preadv2(void) +{ + pthread_t reader, dropper, writer; + unsigned int max_runtime = 600; + void *eagains; + + stop = 0; + + drop_caches(); + + SAFE_PTHREAD_CREATE(&dropper, NULL, cache_dropper, NULL); + SAFE_PTHREAD_CREATE(&reader, NULL, nowait_reader, NULL); + SAFE_PTHREAD_CREATE(&writer, NULL, writer_thread, NULL); + + while (!stop && max_runtime-- > 0) + usleep(100000); + + stop = 1; + + SAFE_PTHREAD_JOIN(reader, &eagains); + SAFE_PTHREAD_JOIN(dropper, NULL); + SAFE_PTHREAD_JOIN(writer, NULL); + + if (eagains) + tst_res(TPASS, "Got some EAGAIN"); + else + tst_res(TFAIL, "Haven't got EAGAIN"); +} + +static void setup(void) +{ + char path[1024]; + char buf[CHUNK_SZ]; + unsigned int i; + char j; + + for (i = 0; i < FILES; i++) { + snprintf(path, sizeof(path), MNTPOINT"/file_%i", i); + + fds[i] = SAFE_OPEN(path, O_RDWR | O_CREAT, 0644); + + for (j = 0; j < CHUNKS; j++) { + memset(buf, '0' + j, sizeof(buf)); + SAFE_WRITE(1, fds[i], buf, sizeof(buf)); + } + } +} + +static void do_cleanup(void) +{ + unsigned int i; + + for (i = 0; i < FILES; i++) { + if (fds[i] > 0) + SAFE_CLOSE(fds[i]); + } +} + +TST_DECLARE_ONCE_FN(cleanup, do_cleanup); + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = verify_preadv2, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .needs_tmpdir = 1, +};