From patchwork Wed Jun 28 00:21:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ahelenia_Ziemia=C5=84ska?= X-Patchwork-Id: 113642 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8572127vqr; Tue, 27 Jun 2023 17:58:33 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7nOBjnCHooBqglZMDl+nRl5koGspXaQL9ee10kLhMo4SW1bC3qgfS1/3nEnMJfaUG4Q8vz X-Received: by 2002:a17:90b:3583:b0:263:2312:60c2 with SMTP id mm3-20020a17090b358300b00263231260c2mr2702508pjb.3.1687913912906; Tue, 27 Jun 2023 17:58:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687913912; cv=none; d=google.com; s=arc-20160816; b=t7ddmTKhV/bJoTzdyhRVoAjnWgSOjglzx8n4HAvTUx+ETCBynWbHN6MTPy+08aTvJ+ HZp/iWX75pdi7K2MkWM9+8QyeJPDUWVY/kfnOY/IKj9vpUCaXqMZqpKBk1Urm0fPlPtZ jZDD78430N9Omt6xc9Hh3WiTYV4k9g/ioJ5xDcDDywWTRHlohRPzs2+6Et5JOvSaikoo XsejiCsXozOIOQ+tczgKujWQ6OGKNwGlkGxzyBG8Quz3h4C4AcBjKO4sDFS0sZAgJc3/ DrjfOZQdZRXp3WzpAPRrazTSF7KBICOv7tDahHB/MxmnL2eICaqbr6rB77i5j7uyJ0Um 04sQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:user-agent:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date :dkim-signature; bh=oLITRZoBPOvjkSKmasdQT051beP35SUjK4PvyK/Xx4Q=; fh=FDpqvUt4hYipJnuC2z3aiKuVqd2Xbc49PrXDVCfNyOQ=; b=qph7O2wPAcjUz3VSiO/KuCt0OqUiR0SlTuWL+GSEmq3nUxK1k3paTC5p0fpDBtwsmK fic/OxpkYjs8eoMBwxeuPHiUWKG2/m/+WV7slsWgl9FQCh9J56swcUdI0MuHDv8tGbrn GNbM5Vfh7TdHm06I8+4FKP60PQOL1hr408hKGfk4bcse8SEMsYrG6GH9BTNrlSzbWN33 2mkIARv4U1tOSU50ZrJ9sYVr+4vMU3pnPXZmdWShwdmj8cJCEQh5icHQwKjndMxTkwMg BNPYX1Zm4aHQMV9FVOkfrWr/qhzjK4lQmAqJC+E+5VYR9oipRtc+JFXdzA3YAXJsMnyN u0IA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nabijaczleweli.xyz header.s=202305 header.b=EzOa8B88; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=nabijaczleweli.xyz Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id rj6-20020a17090b3e8600b0025c0b9f8200si10487849pjb.190.2023.06.27.17.58.20; Tue, 27 Jun 2023 17:58:32 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@nabijaczleweli.xyz header.s=202305 header.b=EzOa8B88; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=nabijaczleweli.xyz Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230281AbjF1AVU (ORCPT + 99 others); Tue, 27 Jun 2023 20:21:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58922 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230265AbjF1AVT (ORCPT ); Tue, 27 Jun 2023 20:21:19 -0400 Received: from tarta.nabijaczleweli.xyz (unknown [139.28.40.42]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9D7E326BC; Tue, 27 Jun 2023 17:21:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=nabijaczleweli.xyz; s=202305; t=1687911671; bh=zbEjemLyLvTSZ4W5PZWCZaQHZZO9JNKKBQ883UZYecc=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=EzOa8B886eKyTbVBLAzAqFOHlzv7WCztEP4YKIdGw0lXrXIN2rPix/Hl362temFMU 0ps/KAw9/793UHKUENYr3sB/Gfs39l9lmlKyQiusmtEMhBQmyFP9L/LCrVSXkl0+uo P0gstB6tGf34/DVOudrp/CaMrt8dgiX5w1zCMSJK/BcxQUAPFv/dCTGTFkA6uSUqA5 wTrdOhKhzAuj0xyFEVK4TVWm1+ZMspwlpJ1iRSlg9YIF0f0Tz9RWcUHaYZ59b4CSrY LTCjp+vW6V56SvsX/00rkIjFWMckg+EfIAdn0LKmTVbQg5BvkT5DCroic7CmmNRxcC hRSnpESDQji+w== Received: from tarta.nabijaczleweli.xyz (unknown [192.168.1.250]) by tarta.nabijaczleweli.xyz (Postfix) with ESMTPSA id A893DEF8; Wed, 28 Jun 2023 02:21:11 +0200 (CEST) Date: Wed, 28 Jun 2023 02:21:10 +0200 From: Ahelenia =?utf-8?q?Ziemia=C5=84ska?= To: Amir Goldstein Cc: Alexander Viro , Christian Brauner , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Jan Kara , Chung-Chiang Cheng , ltp@lists.linux.it, Petr Vorel Subject: [LTP RFC PATCH v3] inotify13: new test for fs/splice.c functions vs pipes vs inotify Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: NeoMutt/20230517 X-Spam-Status: No, score=-1.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,PDS_RDNS_DYNAMIC_FP, RDNS_DYNAMIC,SPF_HELO_PASS,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769878591954812363?= X-GMAIL-MSGID: =?utf-8?q?1769906019335607127?= The only one that passes on 6.1.27-1 is sendfile_file_to_pipe. Link: https://lore.kernel.org/linux-fsdevel/jbyihkyk5dtaohdwjyivambb2gffyjs3dodpofafnkkunxq7bu@jngkdxx65pux/t/#u Signed-off-by: Ahelenia Ziemiańska --- Sorry, I missed second part of Amir's comments somehow. cleanup is only run at the end by default: run it manually to not leak fds between tests. I've parameterised the tests from the driver, instead of with macros, and removed the tst_tag data. Added the * [Description] tag and full commit subject to the header comment; leaving the lore.k.o link for now, to be turned into a SHA when the kernel behaviour this tests starts having a SHA. Error checking has been lifted out as well. Formatted in kernel style accd'g to clang-format and check-inotify13. I used the wrong address for ltp@ the first time; I've since bounced the patchset, and am sending this, to the correct address. They were all held for moderation for now. testcases/kernel/syscalls/inotify/.gitignore | 1 + testcases/kernel/syscalls/inotify/inotify13.c | 282 ++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 testcases/kernel/syscalls/inotify/inotify13.c diff --git a/testcases/kernel/syscalls/inotify/.gitignore b/testcases/kernel/syscalls/inotify/.gitignore index f6e5c546a..b597ea63f 100644 --- a/testcases/kernel/syscalls/inotify/.gitignore +++ b/testcases/kernel/syscalls/inotify/.gitignore @@ -10,3 +10,4 @@ /inotify10 /inotify11 /inotify12 +/inotify13 diff --git a/testcases/kernel/syscalls/inotify/inotify13.c b/testcases/kernel/syscalls/inotify/inotify13.c new file mode 100644 index 000000000..97f88053e --- /dev/null +++ b/testcases/kernel/syscalls/inotify/inotify13.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*\ + * [Description] + * Verify splice-family functions (and sendfile) generate IN_ACCESS + * for what they read and IN_MODIFY for what they write. + * + * Regression test for 983652c69199 ("splice: report related fsnotify events") and + * https://lore.kernel.org/linux-fsdevel/jbyihkyk5dtaohdwjyivambb2gffyjs3dodpofafnkkunxq7bu@jngkdxx65pux/t/#u + */ + +#define _GNU_SOURCE +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "inotify.h" + +#if defined(HAVE_SYS_INOTIFY_H) +#include + +static int pipes[2] = { -1, -1 }; +static int inotify = -1; +static int memfd = -1; +static int data_pipes[2] = { -1, -1 }; + +static void watch_rw(int fd) +{ + char buf[64]; + + sprintf(buf, "/proc/self/fd/%d", fd); + SAFE_MYINOTIFY_ADD_WATCH(inotify, buf, IN_ACCESS | IN_MODIFY); +} + +static int compar(const void *l, const void *r) +{ + const struct inotify_event *lie = l; + const struct inotify_event *rie = r; + + return lie->wd - rie->wd; +} + +static void get_events(size_t evcnt, struct inotify_event evs[static evcnt]) +{ + struct inotify_event tail, *itr = evs; + + for (size_t left = evcnt; left; --left) + SAFE_READ(true, inotify, itr++, sizeof(struct inotify_event)); + + TEST(read(inotify, &tail, sizeof(struct inotify_event))); + if (TST_RET != -1) + tst_brk(TFAIL, ">%zu events", evcnt); + if (TST_ERR != EAGAIN) + tst_brk(TFAIL | TTERRNO, "expected EAGAIN"); + + qsort(evs, evcnt, sizeof(struct inotify_event), compar); +} + +static void expect_transfer(const char *name, size_t size) +{ + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "%s", name); + if ((size_t)TST_RET != size) + tst_brk(TBROK, "%s: %ld != %zu", name, TST_RET, size); +} + +static void expect_event(struct inotify_event *ev, int wd, uint32_t mask) +{ + if (ev->wd != wd) + tst_brk(TFAIL, "expect event for wd %d got %d", wd, ev->wd); + if (ev->mask != mask) + tst_brk(TFAIL, + "expect event with mask %" PRIu32 " got %" PRIu32 "", + mask, ev->mask); +} + +// write to file, rewind, transfer accd'g to f2p, read from pipe +// expecting: IN_ACCESS memfd, IN_MODIFY pipes[0] +static void file_to_pipe(const char *name, ssize_t (*f2p)(void)) +{ + struct inotify_event events[2]; + char buf[strlen(name)]; + + SAFE_WRITE(SAFE_WRITE_RETRY, memfd, name, strlen(name)); + SAFE_LSEEK(memfd, 0, SEEK_SET); + watch_rw(memfd); + watch_rw(pipes[0]); + TEST(f2p()); + expect_transfer(name, strlen(name)); + + get_events(ARRAY_SIZE(events), events); + expect_event(events + 0, 1, IN_ACCESS); + expect_event(events + 1, 2, IN_MODIFY); + + SAFE_READ(true, pipes[0], buf, strlen(name)); + if (memcmp(buf, name, strlen(name))) + tst_brk(TFAIL, "buf contents bad"); +} +static ssize_t splice_file_to_pipe(void) +{ + return splice(memfd, NULL, pipes[1], NULL, 128 * 1024 * 1024, 0); +} +static ssize_t sendfile_file_to_pipe(void) +{ + return sendfile(pipes[1], memfd, NULL, 128 * 1024 * 1024); +} + +// write to pipe, transfer with splice, rewind file, read from file +// expecting: IN_ACCESS pipes[0], IN_MODIFY memfd +static void splice_pipe_to_file(const char *name, ssize_t (*param)(void)) +{ + (void)name; + (void)param; + struct inotify_event events[2]; + char buf[sizeof(__func__)]; + + SAFE_WRITE(SAFE_WRITE_RETRY, pipes[1], __func__, sizeof(__func__)); + watch_rw(pipes[0]); + watch_rw(memfd); + TEST(splice(pipes[0], NULL, memfd, NULL, 128 * 1024 * 1024, 0)); + expect_transfer(__func__, sizeof(__func__)); + + get_events(ARRAY_SIZE(events), events); + expect_event(events + 0, 1, IN_ACCESS); + expect_event(events + 1, 2, IN_MODIFY); + + SAFE_LSEEK(memfd, 0, SEEK_SET); + SAFE_READ(true, memfd, buf, sizeof(__func__)); + if (memcmp(buf, __func__, sizeof(__func__))) + tst_brk(TFAIL, "buf contents bad"); +} + +// write to data_pipe, transfer accd'g to p2p, read from pipe +// expecting: IN_ACCESS data_pipes[0], IN_MODIFY pipes[1] +static void pipe_to_pipe(const char *name, ssize_t (*p2p)(void)) +{ + struct inotify_event events[2]; + char buf[strlen(name)]; + + SAFE_WRITE(SAFE_WRITE_RETRY, data_pipes[1], name, strlen(name)); + watch_rw(data_pipes[0]); + watch_rw(pipes[1]); + TEST(p2p()); + expect_transfer(name, strlen(name)); + + get_events(ARRAY_SIZE(events), events); + expect_event(events + 0, 1, IN_ACCESS); + expect_event(events + 1, 2, IN_MODIFY); + + SAFE_READ(true, pipes[0], buf, strlen(name)); + if (memcmp(buf, name, strlen(name))) + tst_brk(TFAIL, "buf contents bad"); +} +static ssize_t splice_pipe_to_pipe(void) +{ + return splice(data_pipes[0], NULL, pipes[1], NULL, 128 * 1024 * 1024, + 0); +} +static ssize_t tee_pipe_to_pipe(void) +{ + return tee(data_pipes[0], pipes[1], 128 * 1024 * 1024, 0); +} + +// vmsplice to pipe, read from pipe +// expecting: IN_MODIFY pipes[0] +static char vmsplice_pipe_to_mem_dt[32 * 1024]; +static void vmsplice_pipe_to_mem(const char *name, ssize_t (*param)(void)) +{ + (void)name; + (void)param; + struct inotify_event event; + char buf[sizeof(__func__)]; + + memcpy(vmsplice_pipe_to_mem_dt, __func__, sizeof(__func__)); + watch_rw(pipes[0]); + TEST(vmsplice( + pipes[1], + &(struct iovec){ .iov_base = vmsplice_pipe_to_mem_dt, + .iov_len = sizeof(vmsplice_pipe_to_mem_dt) }, + 1, SPLICE_F_GIFT)); + expect_transfer(__func__, sizeof(vmsplice_pipe_to_mem_dt)); + + get_events(1, &event); + expect_event(&event, 1, IN_MODIFY); + + SAFE_READ(true, pipes[0], buf, sizeof(__func__)); + if (memcmp(buf, __func__, sizeof(__func__))) + tst_brk(TFAIL, "buf contents bad"); +} + +// write to pipe, vmsplice from pipe +// expecting: IN_ACCESS pipes[1] +static void vmsplice_mem_to_pipe(const char *name, ssize_t (*param)(void)) +{ + (void)name; + (void)param; + char buf[sizeof(__func__)]; + struct inotify_event event; + + SAFE_WRITE(SAFE_WRITE_RETRY, pipes[1], __func__, sizeof(__func__)); + watch_rw(pipes[1]); + TEST(vmsplice(pipes[0], + &(struct iovec){ .iov_base = buf, + .iov_len = sizeof(buf) }, + 1, 0)); + expect_transfer(__func__, sizeof(buf)); + + get_events(1, &event); + expect_event(&event, 1, IN_ACCESS); + + if (memcmp(buf, __func__, sizeof(__func__))) + tst_brk(TFAIL, "buf contents bad"); +} + +#define TEST_F(f, param) \ + { \ + #f, f, param, \ + } +static const struct { + const char *n; + void (*f)(const char *name, ssize_t (*param)(void)); + ssize_t (*param)(void); +} tests[] = { + TEST_F(file_to_pipe, splice_file_to_pipe), + TEST_F(file_to_pipe, sendfile_file_to_pipe), + TEST_F(splice_pipe_to_file, NULL), + TEST_F(pipe_to_pipe, splice_pipe_to_pipe), + TEST_F(pipe_to_pipe, tee_pipe_to_pipe), + TEST_F(vmsplice_pipe_to_mem, NULL), + TEST_F(vmsplice_mem_to_pipe, NULL), +}; + +static void cleanup(void) +{ + if (memfd != -1) + SAFE_CLOSE(memfd); + if (inotify != -1) + SAFE_CLOSE(inotify); + if (pipes[0] != -1) + SAFE_CLOSE(pipes[0]); + if (pipes[1] != -1) + SAFE_CLOSE(pipes[1]); + if (data_pipes[0] != -1) + SAFE_CLOSE(data_pipes[0]); + if (data_pipes[1] != -1) + SAFE_CLOSE(data_pipes[1]); +} + +static void run_test(unsigned int n) +{ + tst_res(TINFO, "%s", tests[n].n); + + SAFE_PIPE2(pipes, O_CLOEXEC); + SAFE_PIPE2(data_pipes, O_CLOEXEC); + inotify = SAFE_MYINOTIFY_INIT1(IN_NONBLOCK | IN_CLOEXEC); + memfd = memfd_create(__func__, MFD_CLOEXEC); + if (memfd == -1) + tst_brk(TCONF | TERRNO, "memfd"); + tests[n].f(tests[n].n, tests[n].param); + tst_res(TPASS, "ок"); + cleanup(); +} + +static struct tst_test test = { + .cleanup = cleanup, + .test = run_test, + .tcnt = ARRAY_SIZE(tests), + .tags = (const struct tst_tag[]){ {} }, +}; + +#else +TST_TEST_TCONF("system doesn't have required inotify support"); +#endif