From patchwork Mon Dec 7 07:51:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 7781371 Return-Path: X-Original-To: patchwork-linux-nvdimm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 6AD75BEEE1 for ; Mon, 7 Dec 2015 07:52:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4E4EE203C4 for ; Mon, 7 Dec 2015 07:52:03 +0000 (UTC) Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D2A9C203B6 for ; Mon, 7 Dec 2015 07:52:01 +0000 (UTC) Received: from ml01.vlan14.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id A1A7C1A1FF9; Sun, 6 Dec 2015 23:52:01 -0800 (PST) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by ml01.01.org (Postfix) with ESMTP id B71A01A1FF9 for ; Sun, 6 Dec 2015 23:52:00 -0800 (PST) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP; 06 Dec 2015 23:52:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,393,1444719600"; d="scan'208";a="8716974" Received: from dwillia2-desk3.jf.intel.com ([10.54.39.136]) by fmsmga004.fm.intel.com with ESMTP; 06 Dec 2015 23:52:00 -0800 Subject: [PATCH] ndctl: general dax mmap test From: Dan Williams To: linux-nvdimm@lists.01.org Date: Sun, 06 Dec 2015 23:51:33 -0800 Message-ID: <20151207075133.32696.92131.stgit@dwillia2-desk3.jf.intel.com> User-Agent: StGit/0.17.1-9-g687f MIME-Version: 1.0 Cc: toshi.kani@hp.com X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Toshi Kani Permute through various parameters to mmap when establishing dax mappings. Ideally we would have fuzz testing for this interface, but for now this just does nominal testing of several options. All the test code is from Toshi, with integration into ndctl by Dan. Not-yet-signed-off-by: Toshi Kani Signed-off-by: Dan Williams Signed-off-by: Toshi Kani --- Makefile.am | 5 + lib/test-mmap.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/test-mmap.sh | 61 +++++++++++++++ 3 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 lib/test-mmap.c create mode 100755 lib/test-mmap.sh diff --git a/Makefile.am b/Makefile.am index 2989e076972d..7fee9c688c84 100644 --- a/Makefile.am +++ b/Makefile.am @@ -123,8 +123,8 @@ if ENABLE_DESTRUCTIVE TESTS += lib/test-blk-ns lib/test-pmem-ns lib/test-pcommit check_PROGRAMS += lib/test-blk-ns lib/test-pmem-ns lib/test-pcommit -TESTS += lib/test-dax-dev lib/test-dax.sh -check_PROGRAMS += lib/test-dax-dev lib/test-dax-pmd +TESTS += lib/test-dax-dev lib/test-dax.sh lib/test-mmap.sh +check_PROGRAMS += lib/test-dax-dev lib/test-dax-pmd lib/test-mmap endif lib_test_libndctl_SOURCES = lib/test-libndctl.c lib/test-core.c @@ -149,3 +149,4 @@ lib_test_dax_dev_SOURCES = lib/test-dax-dev.c lib/test-core.c lib_test_dax_dev_LDADD = lib/libndctl.la lib_test_dax_pmd_SOURCES = lib/test-dax-pmd.c +lib_test_mmap_SOURCES = lib/test-mmap.c diff --git a/lib/test-mmap.c b/lib/test-mmap.c new file mode 100644 index 000000000000..d0134fa44712 --- /dev/null +++ b/lib/test-mmap.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MB(a) ((a) * 1024UL * 1024UL) + +static struct timeval start_tv, stop_tv; + +// Calculate the difference between two time values. +static void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0) +{ + tdiff->tv_sec = t1->tv_sec - t0->tv_sec; + tdiff->tv_usec = t1->tv_usec - t0->tv_usec; + if (tdiff->tv_usec < 0) + tdiff->tv_sec--, tdiff->tv_usec += 1000000; +} + +// Start timing now. +static void start(void) +{ + (void) gettimeofday(&start_tv, (struct timezone *) 0); +} + +// Stop timing and return real time in microseconds. +static unsigned long long stop(void) +{ + struct timeval tdiff; + + (void) gettimeofday(&stop_tv, (struct timezone *) 0); + tvsub(&tdiff, &stop_tv, &start_tv); + return (tdiff.tv_sec * 1000000 + tdiff.tv_usec); +} + +static void test_write(unsigned long *p, size_t size) +{ + size_t i; + unsigned long *wp; + unsigned long long timeval; + + start(); + for (i=0, wp=p; i<(size/sizeof(wp)); i++) + *wp++ = 1; + timeval = stop(); + printf("Write: %10llu usec\n", timeval); +} + +static void test_read(unsigned long *p, size_t size) +{ + size_t i; + volatile unsigned long *wp, tmp; + unsigned long long timeval; + + start(); + for (i=0, wp=p; i<(size/sizeof(wp)); i++) + tmp = *wp++; + tmp = tmp; + timeval = stop(); + printf("Read : %10llu usec\n", timeval); +} + +int main(int argc, char **argv) +{ + int fd, i, opt, ret; + int oflags, mprot, mflags = 0; + int is_read_only = 0, is_mlock = 0, is_mlockall = 0; + int mlock_skip = 0, read_test = 0, write_test = 0; + void *mptr = NULL; + unsigned long *p; + struct stat stat; + size_t size, cpy_size; + const char *file_name = NULL; + + while ((opt = getopt(argc, argv, "RMSApsrw")) != -1) { + switch (opt) { + case 'R': + printf("> mmap: read-only\n"); + is_read_only = 1; + break; + case 'M': + printf("> mlock\n"); + is_mlock = 1; + break; + case 'S': + printf("> mlock - skip first ite\n"); + mlock_skip = 1; + break; + case 'A': + printf("> mlockall\n"); + is_mlockall = 1; + break; + case 'p': + printf("> MAP_POPULATE\n"); + mflags |= MAP_POPULATE; + break; + case 's': + printf("> MAP_SHARED\n"); + mflags |= MAP_SHARED; + break; + case 'r': + printf("> read-test\n"); + read_test = 1; + break; + case 'w': + printf("> write-test\n"); + write_test = 1; + break; + } + } + + if (optind == argc) { + printf("missing file name\n"); + return EXIT_FAILURE; + } + file_name = argv[optind]; + + if (!(mflags & MAP_SHARED)) { + printf("> MAP_PRIVATE\n"); + mflags |= MAP_PRIVATE; + } + + if (is_read_only) { + oflags = O_RDONLY; + mprot = PROT_READ; + } else { + oflags = O_RDWR; + mprot = PROT_READ|PROT_WRITE; + } + + fd = open(file_name, oflags); + if (fd == -1) { + perror("open failed"); + return EXIT_FAILURE; + } + + ret = fstat(fd, &stat); + if (ret < 0) { + perror("fstat failed"); + return EXIT_FAILURE; + } + size = stat.st_size; + + printf("> open %s size %#zx flags %#x\n", file_name, size, oflags); + + ret = posix_memalign(&mptr, MB(2), size); + if (ret ==0) + free(mptr); + + printf("> mmap mprot 0x%x flags 0x%x\n", mprot, mflags); + p = mmap(mptr, size, mprot, mflags, fd, 0x0); + if (!p) { + perror("mmap failed"); + return EXIT_FAILURE; + } + if ((long unsigned)p & (MB(2)-1)) + printf("> mmap: NOT 2MB aligned: 0x%p\n", p); + else + printf("> mmap: 2MB aligned: 0x%p\n", p); + +#if 0 /* SIZE LIMIT */ + if (size >= MB(2)) + cpy_size = MB(32); + else +#endif + cpy_size = size; + + for (i=0; i<3; i++) { + + if (is_mlock && !mlock_skip) { + printf("> mlock 0x%p\n", p); + ret = mlock(p, size); + if (ret < 0) { + perror("mlock failed"); + return EXIT_FAILURE; + } + } else if (is_mlockall) { + printf("> mlockall\n"); + ret = mlockall(MCL_CURRENT|MCL_FUTURE); + if (ret < 0) { + perror("mlockall failed"); + return EXIT_FAILURE; + } + } + + printf("===== %d =====\n", i+1); + if (write_test) + test_write(p, cpy_size); + if (read_test) + test_read(p, cpy_size); + + if (is_mlock && !mlock_skip) { + printf("> munlock 0x%p\n", p); + ret = munlock(p, size); + if (ret < 0) { + perror("munlock failed"); + return EXIT_FAILURE; + } + } else if (is_mlockall) { + printf("> munlockall\n"); + ret = munlockall(); + if (ret < 0) { + perror("munlockall failed"); + return EXIT_FAILURE; + } + } + + /* skip, if requested, only the first iteration */ + mlock_skip = 0; + } + + printf("> munmap 0x%p\n", p); + munmap(p, size); + return EXIT_SUCCESS; +} + diff --git a/lib/test-mmap.sh b/lib/test-mmap.sh new file mode 100755 index 000000000000..8d024e57925d --- /dev/null +++ b/lib/test-mmap.sh @@ -0,0 +1,61 @@ +#!/bin/bash +MNT=test_mmap_mnt +FILE=image +DEV="" +TEST=lib/test-mmap + +err() { + rc=1 + echo "test-mmap: failed at line $1" + if [ -n "$DEV" ]; then + umount $DEV + else + rc=77 + fi + rmdir $MNT + exit $rc +} + +test_mmap() { + trap 'err $LINENO' ERR + + # SHARED + $TEST -Mrwps $MNT/$FILE # mlock, populate, shared (mlock fail) + $TEST -Arwps $MNT/$FILE # mlockall, populate, shared + $TEST -RMrps $MNT/$FILE # read-only, mlock, populate, shared (mlock fail) + $TEST -rwps $MNT/$FILE # popluate, shared (popluate no effect) + $TEST -Rrps $MNT/$FILE # read-only popluate, shared (popluate no effect) + $TEST -Mrws $MNT/$FILE # mlock, shared (mlock fail) + $TEST -RMrs $MNT/$FILE # read-only, mlock, shared (mlock fail) + $TEST -rws $MNT/$FILE # shared (ok) + $TEST -Rrs $MNT/$FILE # read-only, shared (ok) + + # PRIVATE + $TEST -Mrwp $MNT/$FILE # mlock, populate, private (ok) + $TEST -RMrp $MNT/$FILE # read-only, mlock, populate, private (mlock fail) + $TEST -rwp $MNT/$FILE # populate, private (ok) + $TEST -Rrp $MNT/$FILE # read-only, populate, private (populate no effect) + $TEST -Mrw $MNT/$FILE # mlock, private (ok) + $TEST -RMr $MNT/$FILE # read-only, mlock, private (mlock fail) + $TEST -MSr $MNT/$FILE # private, read before mlock (ok) + $TEST -rw $MNT/$FILE # private (ok) + $TEST -Rr $MNT/$FILE # read-only, private (ok) +} + +set -e +mkdir -p $MNT +trap 'err $LINENO' ERR + +DEV=$(lib/test-dax-dev) + +mkfs.ext4 $DEV +mount $DEV $MNT -o dax +fallocate -l 1GiB $MNT/$FILE +test_mmap +umount $MNT + +mkfs.xfs -f $DEV +mount $DEV $MNT -o dax +fallocate -l 1GiB $MNT/$FILE +test_mmap +umount $MNT