From patchwork Sun Mar 28 22:33:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12169167 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-24.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F10BEC433DB for ; Sun, 28 Mar 2021 22:35:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BB2C761935 for ; Sun, 28 Mar 2021 22:35:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229656AbhC1Wed (ORCPT ); Sun, 28 Mar 2021 18:34:33 -0400 Received: from mail.kernel.org ([198.145.29.99]:47932 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230450AbhC1WeP (ORCPT ); Sun, 28 Mar 2021 18:34:15 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7068E6192F; Sun, 28 Mar 2021 22:34:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616970855; bh=A5yWnyAyeKl3YsQU9X413QMefKct4lOg8CWaTFd7s4U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=am+NVB2D56GVzXiU1Udzbyx9z0n4YZVNsAenAvGyx/rh2N2zBbXPj60w35TNKUIiL THjBweUO8uHmNJp8I5nZZxhA2P67lkJFr98NYmiW2TDi9Kkzj0Z1tYsiL4HkXlzY2t 0CfIi7PX/5dNQSLOmwptmwk58WBYFflLio7rYYqbgPpmaZ6UKwT04I6rg5G+Jgd+6W U3A8Fpy/h9IvA+++a6PBkFsLqp0hDQ9dpEu3PSzq1nj3JQIeE1sXGCqw0n4PbtjLNn RIe1rYePTQW4FSd13vABfG8hIw5Ktyzi239+1CbJKCSOvx8E8dEHRxc6u8KmGHlsgn gSlyorX9pZdgA== From: Christian Brauner To: Eryu Guan , fstests@vger.kernel.org, Christoph Hellwig Cc: "Darrick J . Wong" , David Howells , Christian Brauner Subject: [PATCH v12 1/6] generic/631: add test for detached mount propagation Date: Mon, 29 Mar 2021 00:33:55 +0200 Message-Id: <20210328223400.1800301-2-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210328223400.1800301-1-brauner@kernel.org> References: <20210328223400.1800301-1-brauner@kernel.org> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=A6fAS7tAPRPONqYTQ9f9cKH6F5OBvRuYVz2qXgEb3AM=; m=8ZQ6bRW98ma4GpDy8UjCocC3BLQm2BLWPAkVXt35HZ0=; p=CcuTBwGrUvb0IHd+hy4yoisbQMzrkHnF1QIGY+4WNrc=; g=863cf7c9129eb2448e6b7b670c2334083ee66dc0 X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGEEGgAKCRCRxhvAZXjcogkQAQDafqk vJR9W3M5TR9NddH0C3JaAnmESd+jo/JnvbMvQ1gD8CTAORahMcug+go1FgLTi3k5N4ARv3bmkjUUJ HatNcgE= Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Christian Brauner Regression test to verify that creating a series of detached mounts, attaching them to the filesystem, and unmounting them does not trigger an integer overflow in ns->mounts causing the kernel to block any new mounts in count_mounts() and returning ENOSPC because it falsely assumes that the maximum number of mounts in the mount namespace has been reached, i.e. it thinks it can't fit the new mounts into the mount namespace anymore. The test is written in a way that it will leave the host's mount namespace intact so we are sure to never make the host's mount namespace unuseable! Link: https://git.kernel.org/torvalds/c/ee2e3f50629f17b0752b55b2566c15ce8dafb557 Cc: Eryu Guan Cc: David Howells Reviewed-by: Christoph Hellwig Signed-off-by: Christian Brauner --- /* v1 - v8 */ patch not present /* v9 */ - Christian Brauner : - Rebased on current master. /* v10 */ - Eryu Guan : - Add missing checks whether test is supported. - Move status=$? assignment up. /* v11 */ unchanged /* v12 */ unchanged --- .gitignore | 1 + src/Makefile | 3 +- src/detached_mounts_propagation.c | 252 ++++++++++++++++++++++++++++++ tests/generic/631 | 43 +++++ tests/generic/631.out | 2 + tests/generic/group | 1 + 6 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 src/detached_mounts_propagation.c create mode 100644 tests/generic/631 create mode 100644 tests/generic/631.out diff --git a/.gitignore b/.gitignore index f3bc0a4f..72bd40a0 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ /src/cloner /src/dbtest /src/deduperace +/src/detached_mounts_propagation /src/devzero /src/dio-interleaved /src/dio-invalidate-cache diff --git a/src/Makefile b/src/Makefile index 3d729a34..99019e6e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,7 +29,8 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \ attr-list-by-handle-cursor-test listxattr dio-interleaved t_dir_type \ dio-invalidate-cache stat_test t_encrypted_d_revalidate \ attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \ - fscrypt-crypt-util bulkstat_null_ocount splice-test chprojid_fail + fscrypt-crypt-util bulkstat_null_ocount splice-test chprojid_fail \ + detached_mounts_propagation SUBDIRS = log-writes perf diff --git a/src/detached_mounts_propagation.c b/src/detached_mounts_propagation.c new file mode 100644 index 00000000..4a588e46 --- /dev/null +++ b/src/detached_mounts_propagation.c @@ -0,0 +1,252 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/* + * Copyright (c) 2021 Christian Brauner + * All Rights Reserved. + * + * Regression test to verify that creating a series of detached mounts, + * attaching them to the filesystem, and unmounting them does not trigger an + * integer overflow in ns->mounts causing the kernel to block any new mounts in + * count_mounts() and returning ENOSPC because it falsely assumes that the + * maximum number of mounts in the mount namespace has been reached, i.e. it + * thinks it can't fit the new mounts into the mount namespace anymore. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* open_tree() */ +#ifndef OPEN_TREE_CLONE +#define OPEN_TREE_CLONE 1 +#endif + +#ifndef OPEN_TREE_CLOEXEC +#define OPEN_TREE_CLOEXEC O_CLOEXEC +#endif + +#ifndef __NR_open_tree + #if defined __alpha__ + #define __NR_open_tree 538 + #elif defined _MIPS_SIM + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ + #define __NR_open_tree 4428 + #endif + #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ + #define __NR_open_tree 6428 + #endif + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_open_tree 5428 + #endif + #elif defined __ia64__ + #define __NR_open_tree (428 + 1024) + #else + #define __NR_open_tree 428 + #endif +#endif + +/* move_mount() */ +#ifndef MOVE_MOUNT_F_EMPTY_PATH +#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */ +#endif + +#ifndef __NR_move_mount + #if defined __alpha__ + #define __NR_move_mount 539 + #elif defined _MIPS_SIM + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ + #define __NR_move_mount 4429 + #endif + #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ + #define __NR_move_mount 6429 + #endif + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_move_mount 5429 + #endif + #elif defined __ia64__ + #define __NR_move_mount (428 + 1024) + #else + #define __NR_move_mount 429 + #endif +#endif + +static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags) +{ + return syscall(__NR_open_tree, dfd, filename, flags); +} + +static inline int sys_move_mount(int from_dfd, const char *from_pathname, int to_dfd, + const char *to_pathname, unsigned int flags) +{ + return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags); +} + +static bool is_shared_mountpoint(const char *path) +{ + bool shared = false; + FILE *f = NULL; + char *line = NULL; + int i; + size_t len = 0; + + f = fopen("/proc/self/mountinfo", "re"); + if (!f) + return 0; + + while (getline(&line, &len, f) > 0) { + char *slider1, *slider2; + + for (slider1 = line, i = 0; slider1 && i < 4; i++) + slider1 = strchr(slider1 + 1, ' '); + + if (!slider1) + continue; + + slider2 = strchr(slider1 + 1, ' '); + if (!slider2) + continue; + + *slider2 = '\0'; + if (strcmp(slider1 + 1, path) == 0) { + /* This is the path. Is it shared? */ + slider1 = strchr(slider2 + 1, ' '); + if (slider1 && strstr(slider1, "shared:")) { + shared = true; + break; + } + } + } + fclose(f); + free(line); + + return shared; +} + +static void usage(void) +{ + const char *text = "mount-new [--recursive] \n"; + fprintf(stderr, "%s", text); + _exit(EXIT_SUCCESS); +} + +#define exit_usage(format, ...) \ + ({ \ + fprintf(stderr, format "\n", ##__VA_ARGS__); \ + usage(); \ + }) + +#define exit_log(format, ...) \ + ({ \ + fprintf(stderr, format "\n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + }) + +static const struct option longopts[] = { + {"help", no_argument, 0, 'a'}, + { NULL, no_argument, 0, 0 }, +}; + +int main(int argc, char *argv[]) +{ + int exit_code = EXIT_SUCCESS, index = 0; + int dfd, fd_tree, new_argc, ret; + char *base_dir; + char *const *new_argv; + char target[PATH_MAX]; + + while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) { + switch (ret) { + case 'a': + /* fallthrough */ + default: + usage(); + } + } + + new_argv = &argv[optind]; + new_argc = argc - optind; + if (new_argc < 1) + exit_usage("Missing base directory\n"); + base_dir = new_argv[0]; + + if (*base_dir != '/') + exit_log("Please specify an absolute path"); + + /* Ensure that target is a shared mountpoint. */ + if (!is_shared_mountpoint(base_dir)) + exit_log("Please ensure that \"%s\" is a shared mountpoint", base_dir); + + ret = unshare(CLONE_NEWNS); + if (ret < 0) + exit_log("%m - Failed to create new mount namespace"); + + ret = mount(NULL, base_dir, NULL, MS_REC | MS_SHARED, NULL); + if (ret < 0) + exit_log("%m - Failed to make base_dir shared mountpoint"); + + dfd = open(base_dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC); + if (dfd < 0) + exit_log("%m - Failed to open base directory \"%s\"", base_dir); + + ret = mkdirat(dfd, "detached-move-mount", 0755); + if (ret < 0) + exit_log("%m - Failed to create required temporary directories"); + + ret = snprintf(target, sizeof(target), "%s/detached-move-mount", base_dir); + if (ret < 0 || (size_t)ret >= sizeof(target)) + exit_log("%m - Failed to assemble target path"); + + /* + * Having a mount table with 10000 mounts is already quite excessive + * and shoult account even for weird test systems. + */ + for (size_t i = 0; i < 10000; i++) { + fd_tree = sys_open_tree(dfd, "detached-move-mount", + OPEN_TREE_CLONE | + OPEN_TREE_CLOEXEC | + AT_EMPTY_PATH); + if (fd_tree < 0) { + if (errno == ENOSYS) /* New mount API not (fully) supported. */ + break; + + fprintf(stderr, "%m - Failed to open %d(detached-move-mount)", dfd); + exit_code = EXIT_FAILURE; + break; + } + + ret = sys_move_mount(fd_tree, "", dfd, "detached-move-mount", MOVE_MOUNT_F_EMPTY_PATH); + if (ret < 0) { + if (errno == ENOSPC) + fprintf(stderr, "%m - Buggy mount counting"); + else if (errno == ENOSYS) /* New mount API not (fully) supported. */ + break; + else + fprintf(stderr, "%m - Failed to attach mount to %d(detached-move-mount)", dfd); + exit_code = EXIT_FAILURE; + break; + } + close(fd_tree); + + ret = umount2(target, MNT_DETACH); + if (ret < 0) { + fprintf(stderr, "%m - Failed to unmount %s", target); + exit_code = EXIT_FAILURE; + break; + } + } + + (void)unlinkat(dfd, "detached-move-mount", AT_REMOVEDIR); + close(dfd); + + exit(exit_code); +} diff --git a/tests/generic/631 b/tests/generic/631 new file mode 100644 index 00000000..0b6cac42 --- /dev/null +++ b/tests/generic/631 @@ -0,0 +1,43 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021 Christian Brauner +# All Rights Reserved. +# +# FS QA Test No. 631 +# +# Regression test to verify that creating a series of detached mounts, +# attaching them to the filesystem, and unmounting them does not trigger an +# integer overflow in ns->mounts causing the kernel to block any new mounts in +# count_mounts() and returning ENOSPC because it falsely assumes that the +# maximum number of mounts in the mount namespace has been reached, i.e. it +# thinks it can't fit the new mounts into the mount namespace anymore. +# +seq=`basename $0` +seqres=$RESULT_DIR/$seq +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + cd / + rm -f $tmp.* +} + +. ./common/rc + +rm -f $seqres.full + +_supported_fs generic +_require_test +_require_test_program "detached_mounts_propagation" + +$here/src/detached_mounts_propagation $TEST_DIR >> $seqres.full +status=$? + +echo silence is golden +exit diff --git a/tests/generic/631.out b/tests/generic/631.out new file mode 100644 index 00000000..ce88f447 --- /dev/null +++ b/tests/generic/631.out @@ -0,0 +1,2 @@ +QA output created by 631 +silence is golden diff --git a/tests/generic/group b/tests/generic/group index 7c7531d1..151f8af2 100644 --- a/tests/generic/group +++ b/tests/generic/group @@ -633,3 +633,4 @@ 628 auto quick rw clone 629 auto quick rw copy_range 630 auto quick rw dedupe clone +631 auto quick mount From patchwork Sun Mar 28 22:33:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12169177 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT, WEIRD_QUOTING autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03313C433E4 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CDB3361974 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231176AbhC1Wed (ORCPT ); Sun, 28 Mar 2021 18:34:33 -0400 Received: from mail.kernel.org ([198.145.29.99]:47960 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231521AbhC1WeW (ORCPT ); Sun, 28 Mar 2021 18:34:22 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7FAEC6044F; Sun, 28 Mar 2021 22:34:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616970862; bh=iXZsxd8Y//Pw5x1akELrcWY93zH2FPtW2FGbhG2wjzg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TqmXkH2+zVboV1OWpOP3VKppra71EgRZWcUztR2SEgH0puZioyXAWvARfOWX1jI63 O4CgzQP8ezC+pnmLVAfb486KAAjRQ1tDNKGmgOeY9BipwORedpFQHiyYGrPQeJT0vY 56IQ9MID18w0/AKqNyFzX8vfQZo3hry8uwSti/GQd06VL7dTPZ1m1bAFam7CJGNMrW COqHM57JiUNOYqoQ3dY7a/kcB2euVbbYXZ1UEUCRhsJ1mBQMIBI6qxz9p5fq+fALEC pvT2njH3uMgoOlevsb+iM+joBthzPGCEtoltrHh9OjgR+tWkIudwzHHLga1ipJQrVq UOdxBZ6auP5PQ== From: Christian Brauner To: Eryu Guan , fstests@vger.kernel.org, Christoph Hellwig Cc: "Darrick J . Wong" , David Howells , Christian Brauner Subject: [PATCH v12 3/6] common/rc: add _scratch_{u}mount_idmapped() helpers Date: Mon, 29 Mar 2021 00:33:57 +0200 Message-Id: <20210328223400.1800301-4-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210328223400.1800301-1-brauner@kernel.org> References: <20210328223400.1800301-1-brauner@kernel.org> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=0tBoWLwhZNa+tipA2iRvU4W45a+5ynswiuHs0HRDIhQ=; m=6Vb20E8gcJEA5o4NwNERTGWL1KgKXo25uFGgA6DLiA4=; p=wFchO1ZkvaARbRmPsdNbh8K2R1PGG7o1N9BGTz+Q77Y=; g=9c892fd1eb0dd15af2123a1c358e9d021f1dddd6 X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGEEGwAKCRCRxhvAZXjconloAP0Wgwx ZDlHP4IXrJLKz/LpJ8vMS5J4fQSL43Av6qnoQRwD8DxkHCvsh1r1+3BXEu/0ZVNvJeAdSB0d3BwUo WFwqQgw= Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Christian Brauner They will be used in follow-up patches for xfs quota tests but might be useful for other tests in the future. Cc: Eryu Guan Cc: Christoph Hellwig Cc: David Howells Cc: fstests@vger.kernel.org Signed-off-by: Christian Brauner --- /* v1 - v9 */ patch not present /* v10 */ patch introduced /* v11 */ - Amir Goldstein : - Minor Makefile style nit. - Add missing "/" when calculating maxium path length. - Handle the case where user gives us a path to userns. /* v12 */ - Eryu Guan : - Fix helper installation. --- .gitignore | 1 + common/rc | 35 +++ src/idmapped-mounts/Makefile | 13 +- src/idmapped-mounts/mount-idmapped.c | 431 +++++++++++++++++++++++++++ src/idmapped-mounts/utils.c | 2 +- src/idmapped-mounts/utils.h | 1 + 6 files changed, 478 insertions(+), 5 deletions(-) create mode 100644 src/idmapped-mounts/mount-idmapped.c diff --git a/.gitignore b/.gitignore index 3229bb26..4cc9c807 100644 --- a/.gitignore +++ b/.gitignore @@ -179,6 +179,7 @@ /src/aio-dio-regress/aiocp /src/aio-dio-regress/aiodio_sparse2 /src/idmapped-mounts/idmapped-mounts +/src/idmapped-mounts/mount-idmapped /src/log-writes/replay-log /src/perf/*.pyc diff --git a/common/rc b/common/rc index a8b375a2..351996fc 100644 --- a/common/rc +++ b/common/rc @@ -342,6 +342,36 @@ _scratch_mount() _try_scratch_mount $* || _fail "mount failed" } +_scratch_mount_idmapped() +{ + local type="$1" + local id="$2" + + if [ "$type" = "u" ]; then + # This means root will be able to create files as uid %id in + # the underlying filesystem by going through the idmapped mount. + $here/src/idmapped-mounts/mount-idmapped --map-mount u:0:$id:1 \ + --map-mount u:$id:0:1 \ + --map-mount g:0:0:1 \ + "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" + elif [ "$type" = "g" ]; then + # This means root will be able to create files as gid %id in + # the underlying filesystem by going through the idmapped mount. + $here/src/idmapped-mounts/mount-idmapped --map-mount g:0:$id:1 \ + --map-mount g:$id:0:1 \ + --map-mount u:0:0:1 \ + "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" + elif [ "$type" = "b" ]; then + # This means root will be able to create files as uid and gid + # %id in the underlying filesystem by going through the idmapped mount. + $here/src/idmapped-mounts/mount-idmapped --map-mount b:0:$id:1 \ + --map-mount b:$id:0:1 \ + "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" + else + _fail "usage: either \"u\" (uid), \"g\" (gid), or \"b\" (uid and gid) must be specified " + fi +} + _scratch_unmount() { case "$FSTYP" in @@ -357,6 +387,11 @@ _scratch_unmount() esac } +_scratch_umount_idmapped() +{ + $UMOUNT_PROG $SCRATCH_MNT +} + _scratch_remount() { local opts="$1" diff --git a/src/idmapped-mounts/Makefile b/src/idmapped-mounts/Makefile index 6a934146..ad4ddc99 100644 --- a/src/idmapped-mounts/Makefile +++ b/src/idmapped-mounts/Makefile @@ -3,9 +3,10 @@ TOPDIR = ../.. include $(TOPDIR)/include/builddefs -TARGETS = idmapped-mounts +TARGETS = idmapped-mounts mount-idmapped +CFILES_IDMAPPED_MOUNTS = idmapped-mounts.c utils.c +CFILES_MOUNT_IDMAPPED = mount-idmapped.c utils.c -CFILES = idmapped-mounts.c utils.c HFILES = missing.h utils.h LLDLIBS += -pthread LDIRT = $(TARGETS) @@ -24,9 +25,13 @@ depend: .dep include $(BUILDRULES) -$(TARGETS): $(CFILES) +idmapped-mounts: $(CFILES_IDMAPPED_MOUNTS) @echo " [CC] $@" - $(Q)$(LTLINK) $(CFILES) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS) + $(Q)$(LTLINK) $(CFILES_IDMAPPED_MOUNTS) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS) + +mount-idmapped: $(CFILES_MOUNT_IDMAPPED) + @echo " [CC] $@" + $(Q)$(LTLINK) $(CFILES_MOUNT_IDMAPPED) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS) install: $(INSTALL) -m 755 -d $(PKG_LIB_DIR)/src/idmapped-mounts diff --git a/src/idmapped-mounts/mount-idmapped.c b/src/idmapped-mounts/mount-idmapped.c new file mode 100644 index 00000000..5f5ba5d2 --- /dev/null +++ b/src/idmapped-mounts/mount-idmapped.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "../global.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "missing.h" +#include "utils.h" + +/* A few helpful macros. */ +#define STRLITERALLEN(x) (sizeof(""x"") - 1) + +#define INTTYPE_TO_STRLEN(type) \ + (2 + (sizeof(type) <= 1 \ + ? 3 \ + : sizeof(type) <= 2 \ + ? 5 \ + : sizeof(type) <= 4 \ + ? 10 \ + : sizeof(type) <= 8 ? 20 : sizeof(int[-2 * (sizeof(type) > 8)]))) + +#define syserror(format, ...) \ + ({ \ + fprintf(stderr, format, ##__VA_ARGS__); \ + (-errno); \ + }) + +#define syserror_set(__ret__, format, ...) \ + ({ \ + typeof(__ret__) __internal_ret__ = (__ret__); \ + errno = labs(__ret__); \ + fprintf(stderr, format, ##__VA_ARGS__); \ + __internal_ret__; \ + }) + +struct list { + void *elem; + struct list *next; + struct list *prev; +}; + +#define list_for_each(__iterator, __list) \ + for (__iterator = (__list)->next; __iterator != __list; __iterator = __iterator->next) + +static inline void list_init(struct list *list) +{ + list->elem = NULL; + list->next = list->prev = list; +} + +static inline int list_empty(const struct list *list) +{ + return list == list->next; +} + +static inline void __list_add(struct list *new, struct list *prev, struct list *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add_tail(struct list *head, struct list *list) +{ + __list_add(list, head->prev, head); +} + +typedef enum idmap_type_t { + ID_TYPE_UID, + ID_TYPE_GID +} idmap_type_t; + +struct id_map { + idmap_type_t map_type; + __u32 nsid; + __u32 hostid; + __u32 range; +}; + +static struct list active_map; + +static int add_map_entry(__u32 id_host, + __u32 id_ns, + __u32 range, + idmap_type_t map_type) +{ + struct list *new_list = NULL; + struct id_map *newmap = NULL; + + newmap = malloc(sizeof(*newmap)); + if (!newmap) + return -ENOMEM; + + new_list = malloc(sizeof(struct list)); + if (!new_list) { + free(newmap); + return -ENOMEM; + } + + *newmap = (struct id_map){ + .hostid = id_host, + .nsid = id_ns, + .range = range, + .map_type = map_type, + }; + + new_list->elem = newmap; + list_add_tail(&active_map, new_list); + return 0; +} + +static int parse_map(char *map) +{ + char types[2] = {'u', 'g'}; + int ret; + __u32 id_host, id_ns, range; + char which; + + if (!map) + return -1; + + ret = sscanf(map, "%c:%u:%u:%u", &which, &id_ns, &id_host, &range); + if (ret != 4) + return -1; + + if (which != 'b' && which != 'u' && which != 'g') + return -1; + + for (int i = 0; i < 2; i++) { + idmap_type_t map_type; + + if (which != types[i] && which != 'b') + continue; + + if (types[i] == 'u') + map_type = ID_TYPE_UID; + else + map_type = ID_TYPE_GID; + + ret = add_map_entry(id_host, id_ns, range, map_type); + if (ret < 0) + return ret; + } + + return 0; +} + +static int write_id_mapping(idmap_type_t map_type, pid_t pid, const char *buf, size_t buf_size) +{ + int fd = -EBADF, setgroups_fd = -EBADF; + int fret = -1; + int ret; + char path[STRLITERALLEN("/proc/") + INTTYPE_TO_STRLEN(pid_t) + + STRLITERALLEN("/setgroups") + 1]; + + if (geteuid() != 0 && map_type == ID_TYPE_GID) { + ret = snprintf(path, sizeof(path), "/proc/%d/setgroups", pid); + if (ret < 0 || ret >= sizeof(path)) + goto out; + + setgroups_fd = open(path, O_WRONLY | O_CLOEXEC); + if (setgroups_fd < 0 && errno != ENOENT) { + syserror("Failed to open \"%s\"", path); + goto out; + } + + if (setgroups_fd >= 0) { + ret = write_nointr(setgroups_fd, "deny\n", STRLITERALLEN("deny\n")); + if (ret != STRLITERALLEN("deny\n")) { + syserror("Failed to write \"deny\" to \"/proc/%d/setgroups\"", pid); + goto out; + } + } + } + + ret = snprintf(path, sizeof(path), "/proc/%d/%cid_map", pid, map_type == ID_TYPE_UID ? 'u' : 'g'); + if (ret < 0 || ret >= sizeof(path)) + goto out; + + fd = open(path, O_WRONLY | O_CLOEXEC); + if (fd < 0) { + syserror("Failed to open \"%s\"", path); + goto out; + } + + ret = write_nointr(fd, buf, buf_size); + if (ret != buf_size) { + syserror("Failed to write %cid mapping to \"%s\"", + map_type == ID_TYPE_UID ? 'u' : 'g', path); + goto out; + } + + fret = 0; +out: + if (fd >= 0) + close(fd); + if (setgroups_fd >= 0) + close(setgroups_fd); + + return fret; +} + +static int map_ids_from_idmap(struct list *idmap, pid_t pid) +{ + int fill, left; + char mapbuf[4096] = {}; + bool had_entry = false; + + for (idmap_type_t map_type = ID_TYPE_UID, u_or_g = 'u'; + map_type <= ID_TYPE_GID; map_type++, u_or_g = 'g') { + char *pos = mapbuf; + int ret; + struct list *iterator; + + + list_for_each(iterator, idmap) { + struct id_map *map = iterator->elem; + if (map->map_type != map_type) + continue; + + had_entry = true; + + left = 4096 - (pos - mapbuf); + fill = snprintf(pos, left, "%u %u %u\n", map->nsid, map->hostid, map->range); + /* + * The kernel only takes <= 4k for writes to + * /proc//{g,u}id_map + */ + if (fill <= 0 || fill >= left) + return syserror_set(-E2BIG, "Too many %cid mappings defined", u_or_g); + + pos += fill; + } + if (!had_entry) + continue; + + ret = write_id_mapping(map_type, pid, mapbuf, pos - mapbuf); + if (ret < 0) + return syserror("Failed to write mapping: %s", mapbuf); + + memset(mapbuf, 0, sizeof(mapbuf)); + } + + return 0; +} + +static int get_userns_fd_from_idmap(struct list *idmap) +{ + int ret; + pid_t pid; + char path_ns[STRLITERALLEN("/proc/") + INTTYPE_TO_STRLEN(pid_t) + + STRLITERALLEN("/ns/user") + 1]; + + pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER | CLONE_NEWNS); + if (pid < 0) + return -errno; + + ret = map_ids_from_idmap(idmap, pid); + if (ret < 0) + return ret; + + ret = snprintf(path_ns, sizeof(path_ns), "/proc/%d/ns/user", pid); + if (ret < 0 || (size_t)ret >= sizeof(path_ns)) + ret = -EIO; + else + ret = open(path_ns, O_RDONLY | O_CLOEXEC | O_NOCTTY); + + (void)kill(pid, SIGKILL); + (void)wait_for_pid(pid); + return ret; +} + +static inline bool strnequal(const char *str, const char *eq, size_t len) +{ + return strncmp(str, eq, len) == 0; +} + +static void usage(void) +{ + const char *text = "\ +mount-idmapped --map-mount= \n\ +\n\ +Create an idmapped mount of at \n\ +Options:\n\ + --map-mount=\n\ + Specify an idmap for the mount in the format\n\ + :::\n\ + The can be:\n\ + \"b\" or \"both\" -> map both uids and gids\n\ + \"u\" or \"uid\" -> map uids\n\ + \"g\" or \"gid\" -> map gids\n\ + For example, specifying:\n\ + both:1000:1001:1 -> map uid and gid 1000 to uid and gid 1001 in and no other ids\n\ + uid:20000:100000:1000 -> map uid 20000 to uid 100000, uid 20001 to uid 100001 [...] in \n\ + Currently up to 340 separate idmappings may be specified.\n\n\ + --map-mount=/proc//ns/user\n\ + Specify a path to a user namespace whose idmap is to be used.\n\n\ + --recursive\n\ + Copy the whole mount tree from and apply the idmap to everyone at .\n\n\ +Examples:\n\ + - Create an idmapped mount of /source on /target with both ('b') uids and gids mapped:\n\ + mount-idmapped --map-mount b:0:10000:10000 /source /target\n\n\ + - Create an idmapped mount of /source on /target with uids ('u') and gids ('g') mapped separately:\n\ + mount-idmapped --map-mount u:0:10000:10000 g:0:20000:20000 /source /target\n\n\ +"; + fprintf(stderr, "%s", text); + _exit(EXIT_SUCCESS); +} + +#define exit_usage(format, ...) \ + ({ \ + fprintf(stderr, format, ##__VA_ARGS__); \ + usage(); \ + }) + +#define exit_log(format, ...) \ + ({ \ + fprintf(stderr, format, ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + }) + +static const struct option longopts[] = { + {"map-mount", required_argument, 0, 'a'}, + {"help", no_argument, 0, 'c'}, + {"recursive", no_argument, 0, 'd'}, + { NULL, 0, 0, 0 }, +}; + +int main(int argc, char *argv[]) +{ + int fd_userns = -EBADF; + int index = 0; + const char *source = NULL, *target = NULL; + bool recursive = false; + int fd_tree, new_argc, ret; + char *const *new_argv; + + list_init(&active_map); + while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) { + switch (ret) { + case 'a': + if (strnequal(optarg, "/proc/", STRLITERALLEN("/proc/"))) { + fd_userns = open(optarg, O_RDONLY | O_CLOEXEC); + if (fd_userns < 0) + exit_log("%m - Failed top open user namespace path %s\n", optarg); + break; + } + + ret = parse_map(optarg); + if (ret < 0) + exit_log("Failed to parse idmaps for mount\n"); + break; + case 'd': + recursive = true; + break; + case 'c': + /* fallthrough */ + default: + usage(); + } + } + + new_argv = &argv[optind]; + new_argc = argc - optind; + if (new_argc < 2) + exit_usage("Missing source or target mountpoint\n\n"); + source = new_argv[0]; + target = new_argv[1]; + + fd_tree = sys_open_tree(-EBADF, source, + OPEN_TREE_CLONE | + OPEN_TREE_CLOEXEC | + AT_EMPTY_PATH | + (recursive ? AT_RECURSIVE : 0)); + if (fd_tree < 0) { + exit_log("%m - Failed to open %s\n", source); + exit(EXIT_FAILURE); + } + + if (!list_empty(&active_map) || fd_userns >= 0) { + struct mount_attr attr = { + .attr_set = MOUNT_ATTR_IDMAP, + }; + + if (fd_userns >= 0) + attr.userns_fd = fd_userns; + else + attr.userns_fd = get_userns_fd_from_idmap(&active_map); + if (attr.userns_fd < 0) + exit_log("%m - Failed to create user namespace\n"); + + ret = sys_mount_setattr(fd_tree, "", AT_EMPTY_PATH | AT_RECURSIVE, + &attr, sizeof(attr)); + if (ret < 0) + exit_log("%m - Failed to change mount attributes\n"); + close(attr.userns_fd); + } + + ret = sys_move_mount(fd_tree, "", -EBADF, target, + MOVE_MOUNT_F_EMPTY_PATH); + if (ret < 0) + exit_log("%m - Failed to attach mount to %s\n", target); + close(fd_tree); + + exit(EXIT_SUCCESS); +} diff --git a/src/idmapped-mounts/utils.c b/src/idmapped-mounts/utils.c index b27ba445..977443f1 100644 --- a/src/idmapped-mounts/utils.c +++ b/src/idmapped-mounts/utils.c @@ -88,7 +88,7 @@ pid_t do_clone(int (*fn)(void *), void *arg, int flags) #endif } -static int get_userns_fd_cb(void *data) +int get_userns_fd_cb(void *data) { return kill(getpid(), SIGSTOP); } diff --git a/src/idmapped-mounts/utils.h b/src/idmapped-mounts/utils.h index 93425731..efbf3bc3 100644 --- a/src/idmapped-mounts/utils.h +++ b/src/idmapped-mounts/utils.h @@ -20,6 +20,7 @@ #include "missing.h" extern pid_t do_clone(int (*fn)(void *), void *arg, int flags); +extern int get_userns_fd_cb(void *data); extern int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range); extern ssize_t read_nointr(int fd, void *buf, size_t count); From patchwork Sun Mar 28 22:33:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12169169 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F0F7EC433E2 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AC89C61969 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231521AbhC1Wee (ORCPT ); Sun, 28 Mar 2021 18:34:34 -0400 Received: from mail.kernel.org ([198.145.29.99]:47974 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231213AbhC1WeY (ORCPT ); Sun, 28 Mar 2021 18:34:24 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 8D5496193E; Sun, 28 Mar 2021 22:34:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616970864; bh=XR3CeT7KZxaGNHWMYXCfmVknrqSFmNPEBWRzrOmCaMM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k9O/Ue95wUDkngDJ/rPD3jbRquqWnMlH2kQoHbmIcVKQ1IOY3n0dkuy00QAusYkJi Yd8yZl6p9TInreSlBtq9J75OtvCpyMm6Oue/PKQs3wY5c5wdWzQGmsPHmkxIBugz2B YsvDRlkmvwzABOtwT1v8CpNBXnYlH773Qp5imAmpWb4zqSJWMGOD8ikjsDLxyPY3CW R32V3uU1X5zGM6SlwNVsn48ZYqTfhZ1wv4ZxTybgEcceSBNOBRtnmkcbBpS3rtRts6 ME6NSMDiSoMF75MJ8FGvVq/RjWDkC1wePwYLLfAsYLKH+b4F5bjOpXcbrBHyiI4BnR vY6Z/RfkToOcQ== From: Christian Brauner To: Eryu Guan , fstests@vger.kernel.org, Christoph Hellwig Cc: "Darrick J . Wong" , David Howells , Christian Brauner Subject: [PATCH v12 4/6] common/quota: move _qsetup() helper to common code Date: Mon, 29 Mar 2021 00:33:58 +0200 Message-Id: <20210328223400.1800301-5-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210328223400.1800301-1-brauner@kernel.org> References: <20210328223400.1800301-1-brauner@kernel.org> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=wM9Q2AdFuvVYmj1+BgTxu13NVAXYIAuRDfZKkOg26xw=; m=G9up2oLwo++96UH6tgmgi4o4ese0pNaEOzVzPn2cm5o=; p=WU5/GGIh2yNDrbksNUPmm2Bl9QB12TJxW4HV+CzVmqw=; g=03a67e8d3f5d58609a3b5e24479cc8492106b35a X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGEEGwAKCRCRxhvAZXjcoseGAQCQKA+ +kqLYbwkPT6W4FHogU85RN4TWSiZnShkbMSioxwEAs/Jb7hXjg7FHKrELMgXqi6o67z74in+xqBJk BL3BzgE= Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Christian Brauner It's already used in two tests and will be used in a third. Cc: Eryu Guan Cc: Christoph Hellwig Cc: Darrick J. Wong Cc: fstests@vger.kernel.org Suggested-by: Eryu Guan Signed-off-by: Christian Brauner --- /* v1 - v9 */ patch not present /* v10 */ patch introduced /* v11 */ unchanged /* v12 */ unchanged --- common/quota | 20 ++++++++++++++++++++ tests/xfs/050 | 19 ------------------- tests/xfs/299 | 19 ------------------- 3 files changed, 20 insertions(+), 38 deletions(-) diff --git a/common/quota b/common/quota index 1437d5f7..32a9a555 100644 --- a/common/quota +++ b/common/quota @@ -329,5 +329,25 @@ _report_quota_inodes() { repquota $1 | egrep "^($qa_user|root|nobody)" | awk '{print $1, $6, $7, $8}' | sort -r } +# Determine which type of quota we're using +_qsetup() +{ + opt=$1 + enforce=0 + if [ $opt = "u" -o $opt = "uno" ]; then + type=u + eval `_choose_uid` + elif [ $opt = "g" -o $opt = "gno" ]; then + type=g + eval `_choose_gid` + elif [ $opt = "p" -o $opt = "pno" ]; then + type=p + eval `_choose_prid` + fi + [ $opt = "u" -o $opt = "g" -o $opt = "p" ] && enforce=1 + + echo "Using type=$type id=$id" >> $seqres.full +} + # make sure this script returns success /bin/true diff --git a/tests/xfs/050 b/tests/xfs/050 index 1df97537..e7c81d0a 100755 --- a/tests/xfs/050 +++ b/tests/xfs/050 @@ -69,25 +69,6 @@ _filter_and_check_blks() ' | _filter_quota_report } -_qsetup() -{ - opt=$1 - enforce=0 - if [ $opt = "u" -o $opt = "uno" ]; then - type=u - eval `_choose_uid` - elif [ $opt = "g" -o $opt = "gno" ]; then - type=g - eval `_choose_gid` - elif [ $opt = "p" -o $opt = "pno" ]; then - type=p - eval `_choose_prid` - fi - [ $opt = "u" -o $opt = "g" -o $opt = "p" ] && enforce=1 - - echo "Using type=$type id=$id" >> $seqres.full -} - _exercise() { _scratch_mkfs_xfs | _filter_mkfs 2>$tmp.mkfs diff --git a/tests/xfs/299 b/tests/xfs/299 index b862e67e..26b7fcfd 100755 --- a/tests/xfs/299 +++ b/tests/xfs/299 @@ -62,25 +62,6 @@ _filter_and_check_blks() ' | _filter_quota_report } -_qsetup() -{ - opt=$1 - enforce=0 - if [ $opt = "u" -o $opt = "uno" ]; then - type=u - eval `_choose_uid` - elif [ $opt = "g" -o $opt = "gno" ]; then - type=g - eval `_choose_gid` - elif [ $opt = "p" -o $opt = "pno" ]; then - type=p - eval `_choose_prid` - fi - [ $opt = "u" -o $opt = "g" -o $opt = "p" ] && enforce=1 - - echo "Using type=$type id=$id" >> $seqres.full -} - _exercise() { From patchwork Sun Mar 28 22:33:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12169175 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BD3BBC433E1 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 94FB961968 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231213AbhC1Wee (ORCPT ); Sun, 28 Mar 2021 18:34:34 -0400 Received: from mail.kernel.org ([198.145.29.99]:47988 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231546AbhC1We0 (ORCPT ); Sun, 28 Mar 2021 18:34:26 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id CA1B66192F; Sun, 28 Mar 2021 22:34:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616970866; bh=iL6BZt9DTITpwkBXoIIqjyh7Jr82PLwXAyrOYZwVG9g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kOUs8foy3NCMmb8aOYfheXywhcCNN2J2UFR4qYTy8q/eV+bv3WUdmlPW+078wC9ws obAFPQJ8AODqqpgCQh75uvTDQW8EDRyf3npk+I19iMmmTlbEQm7AU4kiDTS4XsvHqD LYOaOSYSWpRglWgaLnlBzk9KIwwOVki5PJPu0+c9s4pHpOXEf2eVCddXBsHI+OBpRY cnPNC157UWJiyepLBJLgN4JrQq7pZUpU9HilRzv7Uaee3JFG7oDOVF9iqXK2CX1iAr kFVGIFOFP6kA3027L4bDpLKhoGGdBCbnvXk2LEgBZ4e1IfcXBiPRL4FMHzihmbLRD6 xY5SZCubZGuAg== From: Christian Brauner To: Eryu Guan , fstests@vger.kernel.org, Christoph Hellwig Cc: "Darrick J . Wong" , David Howells , Christian Brauner Subject: [PATCH v12 5/6] xfs/529: quotas and idmapped mounts Date: Mon, 29 Mar 2021 00:33:59 +0200 Message-Id: <20210328223400.1800301-6-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210328223400.1800301-1-brauner@kernel.org> References: <20210328223400.1800301-1-brauner@kernel.org> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=EgB5KdoeorNO/mLrePkENS7nda1o1bZbOZAU19/Z4ok=; m=XH3eKrC4HukflTh6hqXAj6plSWpF+gIbFNy9Ku7qbs0=; p=0DbHWI0bI12ahBBnHufFPDNomQ6z1XWPz98GTG9gjjQ=; g=280b6bb4a231df9e1fd9447129d23aa7979062ee X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGEEGwAKCRCRxhvAZXjcohqcAQDSl9Y +1efhFgt97o/O4+0z5gnrLF8pTbTXfPFPPpRIigD/eVD6ZH+02OqzNXa+fECQjy318CW3dMb6mwgn q4JDqAc= Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Christian Brauner Test that xfs quota behave correctly on idmapped mounts. Mount a scratch device with user and group quota support enabled. Create directories "unmapped" and "idmapped". Create files in the unampped mount and verify quota behavior. Create files through the idmapped mount and verify identical behavior. Cc: Eryu Guan Cc: Darrick J. Wong Cc: fstests@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Christian Brauner --- /* v1 - v8 */ patch not present /* v9 */ - Christian Brauner : - Rebased on current master. /* v10 */ - Eryu Guan : - Remove leading "_" from local helpers. - Remove redundant "-q" option from umount -l calls. - Use wipe_mount() in a few more places. /* v11 */ - Amir Goldstein : - Add a dedicated "idmapped" tag for idmapped mounts tests. /* v12 */ - Eryu Guan : - Don't use lazy umount if not required. --- tests/xfs/529 | 377 ++++++++++++++++++++++++++ tests/xfs/529.out | 657 ++++++++++++++++++++++++++++++++++++++++++++++ tests/xfs/group | 1 + 3 files changed, 1035 insertions(+) create mode 100644 tests/xfs/529 create mode 100644 tests/xfs/529.out diff --git a/tests/xfs/529 b/tests/xfs/529 new file mode 100644 index 00000000..a5d92314 --- /dev/null +++ b/tests/xfs/529 @@ -0,0 +1,377 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021 Christian Brauner +# All Rights Reserved. +# +# FS QA Test No. 529 +# +# Exercise basic xfs_quota functionality (user/group/project quota) +# Use of "sync" mount option here is an attempt to get deterministic +# allocator behaviour. +# +seq=`basename $0` +seqres=$RESULT_DIR/$seq +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +wipe_mounts() +{ + umount "${SCRATCH_MNT}/idmapped" >/dev/null 2>&1 + _scratch_unmount >/dev/null 2>&1 +} + +_cleanup() +{ + cd / + wipe_mounts + rm -f $tmp.* +} + +# get standard environment, filters and checks +. ./common/rc +. ./common/filter +. ./common/quota + +# remove previous $seqres.full before test +rm -f $seqres.full + +# real QA test starts here +_supported_fs xfs +_require_idmapped_mounts +_require_test_program "idmapped-mounts/mount-idmapped" +_require_scratch +_require_xfs_quota +_require_user fsgqa +_require_user fsgqa2 +_require_group fsgqa +_require_group fsgqa2 + +_scratch_mkfs_xfs >>$seqres.full 2>&1 + +uqid=`id -u fsgqa` +gqid=`id -g fsgqa` + +uqid2=`id -u fsgqa2` +gqid2=`id -g fsgqa2` + +pqid=10 +cat >$tmp.projects <$tmp.projid <> $seqres.full + + for ((i=0; i<$((inum-1)); i++)); do + _file_as_id $SCRATCH_MNT/unmapped/inode$i $id $type 1024 0 + done + + _file_as_id $SCRATCH_MNT/unmapped/block $id $type $bs 1 +} + +create_files_idmapped() +{ + local bs=$1 + local inum=$2 + + echo "Using type=$type id=$id2" >> $seqres.full + + for ((i=0; i<$((inum-1)); i++)); do + _file_as_id $SCRATCH_MNT/idmapped/inode$i $id2 $type 1024 0 + done + + _file_as_id $SCRATCH_MNT/idmapped/block $id2 $type $bs 1 +} + +clean_files() +{ + rm -rf $SCRATCH_MNT/unmapped 2>/dev/null + rm -rf $SCRATCH_MNT/idmapped 2>/dev/null + rm -rf $tmp.quot 2>/dev/null + rm -rf $tmp.quota 2>/dev/null +} + +filter_quot() +{ + _filter_quota | grep -v "root \|\#0 " \ + | sed -e '/#[0-9]*/s/#[0-9]*/#ID/g' +} + +filter_report() +{ + _filter_quota | grep -v "^root \|^\#0 " \ + | sed -e '/^#[0-9]*/s/^#[0-9]*/#ID/g' +} + +filter_quota() +{ + _filter_quota | sed -e "/Disk quotas for/s/([0-9]*)/(ID)/g" \ + -e "/Disk quotas for/s/#[0-9]*/#ID/g" +} + +filter_state() +{ + _filter_quota | sed -e "s/Inode: #[0-9]* (0 blocks, 0 extents)/Inode: #[INO] (0 blocks, 0 extents)/g" \ + -e "s/Inode: #[0-9]* ([0-9]* blocks, [0-9]* extents)/Inode: #[INO] (X blocks, Y extents)/g" \ + -e "/[0-9][0-9]:[0-9][0-9]:[0-9][0-9]/s/ [0-9][0-9]:[0-9][0-9]:[0-9][0-9]//g" \ + -e '/max warnings:/d' +} + +test_quot() +{ + local opt="$*" + + echo "checking quot command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "quot -$type $opt -bi" $SCRATCH_MNT | filter_quot +} + +test_report() +{ + local opt="$*" + + echo "checking report command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "report -$type $opt -bi" \ + $SCRATCH_MNT | filter_report +} + +test_quota() +{ + local opt="$*" + + echo "checking quota command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "quota -$type $opt -bi $id" \ + $SCRATCH_MNT | filter_quota +} + +test_limit() +{ + local bs=$1 + local bh=$2 + local is=$3 + local ih=$4 + + echo "checking limit command (type=$type, bsoft=$bs, bhard=$bh, isoft=$is, ihard=$ih)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "limit -$type bsoft=$bs bhard=$bh fsgqa" \ + -c "limit -$type isoft=$is ihard=$ih fsgqa" \ + $SCRATCH_MNT + + # let the timer day transition happen + sleep 2 +} + +test_timer() +{ + echo "checking timer command (type=$type)" + # set 3days+1h for time won't become 2days soon + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "timer -$type -bi 73h" \ + $SCRATCH_MNT | _filter_scratch +} + +test_disable() +{ + echo "checking disable command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "disable -$type -v" \ + $SCRATCH_MNT | filter_state +} + +test_enable() +{ + echo "checking enable command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "enable -$type -v" $SCRATCH_MNT | filter_state +} + +test_off() +{ + echo "checking off command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "off -$type -v" $SCRATCH_MNT | _filter_scratch +} + +test_remove() +{ + echo "checking remove command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "remove -$type -v" \ + $SCRATCH_MNT | _filter_scratch +} + +test_state() +{ + echo "checking state command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "state -$type" $SCRATCH_MNT | filter_state +} + +test_dump() +{ + echo "checking dump command (type=$type)" + rm -f $tmp.backup 2>>/dev/null + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "dump -$type -f $tmp.backup" \ + $SCRATCH_MNT | _filter_scratch +} + +test_restore() +{ + echo "checking restore command (type=$type)" + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "restore -$type -f $tmp.backup" \ + $SCRATCH_MNT | _filter_scratch +} + +wipe_scratch() +{ + wipe_mounts + _scratch_mkfs_xfs >>$seqres.full 2>&1 +} + +qmount_idmapped() +{ + wipe_mounts + _try_scratch_mount || _fail "qmount failed" + + mkdir -p "${SCRATCH_MNT}/unmapped" + mkdir -p "${SCRATCH_MNT}/idmapped" + + $here/src/idmapped-mounts/mount-idmapped \ + --map-mount b:$id:$id2:1 \ + --map-mount b:0:0:1 \ + "$SCRATCH_MNT/unmapped" "$SCRATCH_MNT/idmapped" || _fail "mount-idmapped failed" + + chmod ugo+rwx $SCRATCH_MNT + chmod ugo+rwx $SCRATCH_MNT/unmapped + chmod ugo+rwx $SCRATCH_MNT/idmapped +} + +test_xfs_quota() +{ + # init quota + echo "init quota limit and timer, and dump it" + if [ "$idmapped" -eq 1 ]; then + echo "create_files_idmapped 1024k 15"; create_files_idmapped 1024k 15 + else + echo "create_files_unmapped 1024k 15"; create_files_unmapped 1024k 15 + fi + echo "quota remount"; qmount_idmapped + echo ; test_quot + echo ; test_timer + echo ; test_limit 512k 2048k 10 20 + echo ; test_dump + + # report options test + echo "report options test" + echo ; test_report + echo "-N option"; test_report -N + echo "-L -U options"; test_report -L $id -U $id + echo "-t option"; test_report -t + echo "-n option"; test_report -n + echo "-h option"; test_report -h + + # quot options test + echo "quot options test" + echo ; test_quot + echo "-f option"; test_quot -f $tmp.quot + cat $tmp.quot | filter_quot + echo "-n option"; test_quot -n + + # quota options test + echo ; test_quota + echo "-f option"; test_quota -f $tmp.quota + cat $tmp.quota | filter_quota + echo "-N option"; test_quota -N + echo "-n option"; test_quota -n + echo "-h option"; test_quota -h + + # disable/enable test + echo "disable quota" + echo ; test_disable + echo ; test_report -N + echo "expect a remove error at here"; test_remove + echo ; test_enable + echo ; test_report -N + + # off and remove test + echo "off and remove test" + echo ; test_limit 100m 100m 100 100 + echo ; test_quota -N + echo ; test_off + echo ; test_state + echo ; test_remove + echo ; test_report -N + echo "quota remount"; qmount_idmapped + echo ; test_report -N + + # restore test + echo "restore quota" + echo ; test_restore + echo ; test_report -N + echo ; test_state + echo "cleanup files"; clean_files +} + +echo "----------------------- uquota,sync,unmapped ---------------------------" +wipe_scratch +_qmount_option "uquota,sync" +type=u +id=$uqid +id2=$uqid2 +idmapped=0 +qmount_idmapped +test_xfs_quota + +echo "----------------------- uquota,sync,idmapped ---------------------------" +wipe_scratch +_qmount_option "uquota,sync" +type=u +id=$uqid +id2=$uqid2 +idmapped=1 +qmount_idmapped +test_xfs_quota + +echo "----------------------- gquota,sync,unmapped ---------------------------" +wipe_scratch +_qmount_option "gquota,sync" +type=g +id=$gqid +id2=$gqid2 +idmapped=0 +qmount_idmapped +test_xfs_quota + +echo "----------------------- gquota,sync,idmapped ---------------------------" +wipe_scratch +_qmount_option "gquota,sync" +type=g +id=$gqid +id2=$gqid2 +idmapped=1 +qmount_idmapped +test_xfs_quota + +wipe_mounts + +# success, all done +status=0 +exit diff --git a/tests/xfs/529.out b/tests/xfs/529.out new file mode 100644 index 00000000..7d2cd96d --- /dev/null +++ b/tests/xfs/529.out @@ -0,0 +1,657 @@ +QA output created by 529 +----------------------- uquota,sync,unmapped --------------------------- +init quota limit and timer, and dump it +create_files_unmapped 1024k 15 +quota remount + +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 fsgqa + +checking timer command (type=u) + +checking limit command (type=u, bsoft=512k, bhard=2048k, isoft=10, ihard=20) + +checking dump command (type=u) +report options test + +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-N option +checking report command (type=u) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-L -U options +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-t option +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-n option +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-h option +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/Grace +---------- --------------------------------- --------------------------------- +fsgqa 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] + +quot options test + +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 fsgqa +-f option +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 fsgqa +-n option +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 #ID + +checking quota command (type=u) +Disk quotas for User fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-f option +checking quota command (type=u) +Disk quotas for User fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-N option +checking quota command (type=u) +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-n option +checking quota command (type=u) +Disk quotas for User #ID (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-h option +checking quota command (type=u) +Disk quotas for User fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +disable quota + +checking disable command (type=u) +User quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: OFF + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=u) +fsgqa 1024 512 2048 00 [--------] 15 10 20 00 [--------] + +expect a remove error at here +checking remove command (type=u) +XFS_QUOTARM: Invalid argument + +checking enable command (type=u) +User quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=u) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +off and remove test + +checking limit command (type=u, bsoft=100m, bhard=100m, isoft=100, ihard=100) + +checking quota command (type=u) +SCRATCH_DEV 1024 102400 102400 00 [--------] 15 100 100 00 [--------] SCRATCH_MNT + +checking off command (type=u) +User quota are not enabled on SCRATCH_DEV + +checking state command (type=u) + +checking remove command (type=u) +User quota are not enabled on SCRATCH_DEV + +checking report command (type=u) + +quota remount + +checking report command (type=u) +fsgqa 1024 0 0 00 [--------] 15 0 0 00 [--------] + +restore quota + +checking restore command (type=u) + +checking report command (type=u) +fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days] + + +checking state command (type=u) +User quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [7 days] +Inodes grace time: [7 days] +Realtime Blocks grace time: [7 days] +cleanup files +----------------------- uquota,sync,idmapped --------------------------- +init quota limit and timer, and dump it +create_files_idmapped 1024k 15 +quota remount + +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 fsgqa + +checking timer command (type=u) + +checking limit command (type=u, bsoft=512k, bhard=2048k, isoft=10, ihard=20) + +checking dump command (type=u) +report options test + +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-N option +checking report command (type=u) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-L -U options +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-t option +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-n option +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-h option +checking report command (type=u) +User quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/Grace +---------- --------------------------------- --------------------------------- +fsgqa 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] + +quot options test + +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 fsgqa +-f option +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 fsgqa +-n option +checking quot command (type=u) +SCRATCH_DEV (SCRATCH_MNT) User: + 1024 15 #ID + +checking quota command (type=u) +Disk quotas for User fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-f option +checking quota command (type=u) +Disk quotas for User fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-N option +checking quota command (type=u) +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-n option +checking quota command (type=u) +Disk quotas for User #ID (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-h option +checking quota command (type=u) +Disk quotas for User fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +disable quota + +checking disable command (type=u) +User quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: OFF + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=u) +fsgqa 1024 512 2048 00 [--------] 15 10 20 00 [--------] + +expect a remove error at here +checking remove command (type=u) +XFS_QUOTARM: Invalid argument + +checking enable command (type=u) +User quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=u) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +off and remove test + +checking limit command (type=u, bsoft=100m, bhard=100m, isoft=100, ihard=100) + +checking quota command (type=u) +SCRATCH_DEV 1024 102400 102400 00 [--------] 15 100 100 00 [--------] SCRATCH_MNT + +checking off command (type=u) +User quota are not enabled on SCRATCH_DEV + +checking state command (type=u) + +checking remove command (type=u) +User quota are not enabled on SCRATCH_DEV + +checking report command (type=u) + +quota remount + +checking report command (type=u) +fsgqa 1024 0 0 00 [--------] 15 0 0 00 [--------] + +restore quota + +checking restore command (type=u) + +checking report command (type=u) +fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days] + + +checking state command (type=u) +User quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [7 days] +Inodes grace time: [7 days] +Realtime Blocks grace time: [7 days] +cleanup files +----------------------- gquota,sync,unmapped --------------------------- +init quota limit and timer, and dump it +create_files_unmapped 1024k 15 +quota remount + +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 fsgqa + +checking timer command (type=g) + +checking limit command (type=g, bsoft=512k, bhard=2048k, isoft=10, ihard=20) + +checking dump command (type=g) +report options test + +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-N option +checking report command (type=g) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-L -U options +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-t option +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-n option +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-h option +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/Grace +---------- --------------------------------- --------------------------------- +fsgqa 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] + +quot options test + +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 fsgqa +-f option +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 fsgqa +-n option +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 #ID + +checking quota command (type=g) +Disk quotas for Group fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-f option +checking quota command (type=g) +Disk quotas for Group fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-N option +checking quota command (type=g) +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-n option +checking quota command (type=g) +Disk quotas for Group #ID (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-h option +checking quota command (type=g) +Disk quotas for Group fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +disable quota + +checking disable command (type=g) +Group quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: OFF + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=g) +fsgqa 1024 512 2048 00 [--------] 15 10 20 00 [--------] + +expect a remove error at here +checking remove command (type=g) +XFS_QUOTARM: Invalid argument + +checking enable command (type=g) +Group quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=g) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +off and remove test + +checking limit command (type=g, bsoft=100m, bhard=100m, isoft=100, ihard=100) + +checking quota command (type=g) +SCRATCH_DEV 1024 102400 102400 00 [--------] 15 100 100 00 [--------] SCRATCH_MNT + +checking off command (type=g) +Group quota are not enabled on SCRATCH_DEV + +checking state command (type=g) + +checking remove command (type=g) +Group quota are not enabled on SCRATCH_DEV + +checking report command (type=g) + +quota remount + +checking report command (type=g) +fsgqa 1024 0 0 00 [--------] 15 0 0 00 [--------] + +restore quota + +checking restore command (type=g) + +checking report command (type=g) +fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days] + + +checking state command (type=g) +Group quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [7 days] +Inodes grace time: [7 days] +Realtime Blocks grace time: [7 days] +cleanup files +----------------------- gquota,sync,idmapped --------------------------- +init quota limit and timer, and dump it +create_files_idmapped 1024k 15 +quota remount + +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 fsgqa + +checking timer command (type=g) + +checking limit command (type=g, bsoft=512k, bhard=2048k, isoft=10, ihard=20) + +checking dump command (type=g) +report options test + +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-N option +checking report command (type=g) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-L -U options +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-t option +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-n option +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/ Grace +---------- -------------------------------------------------- -------------------------------------------------- +#ID 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +-h option +checking report command (type=g) +Group quota on SCRATCH_MNT (SCRATCH_DEV) + Blocks Inodes +Group ID Used Soft Hard Warn/Grace Used Soft Hard Warn/Grace +---------- --------------------------------- --------------------------------- +fsgqa 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] + +quot options test + +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 fsgqa +-f option +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 fsgqa +-n option +checking quot command (type=g) +SCRATCH_DEV (SCRATCH_MNT) Group: + 1024 15 #ID + +checking quota command (type=g) +Disk quotas for Group fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-f option +checking quota command (type=g) +Disk quotas for Group fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-N option +checking quota command (type=g) +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-n option +checking quota command (type=g) +Disk quotas for Group #ID (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +-h option +checking quota command (type=g) +Disk quotas for Group fsgqa (ID) +Filesystem Blocks Quota Limit Warn/Time Files Quota Limit Warn/Time Mounted on +SCRATCH_DEV 1M 512K 2M 00 [3 days] 15 10 20 00 [3 days] SCRATCH_MNT +disable quota + +checking disable command (type=g) +Group quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: OFF + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=g) +fsgqa 1024 512 2048 00 [--------] 15 10 20 00 [--------] + +expect a remove error at here +checking remove command (type=g) +XFS_QUOTARM: Invalid argument + +checking enable command (type=g) +Group quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [3 days] +Inodes grace time: [3 days] +Realtime Blocks grace time: [7 days] + +checking report command (type=g) +fsgqa 1024 512 2048 00 [3 days] 15 10 20 00 [3 days] + +off and remove test + +checking limit command (type=g, bsoft=100m, bhard=100m, isoft=100, ihard=100) + +checking quota command (type=g) +SCRATCH_DEV 1024 102400 102400 00 [--------] 15 100 100 00 [--------] SCRATCH_MNT + +checking off command (type=g) +Group quota are not enabled on SCRATCH_DEV + +checking state command (type=g) + +checking remove command (type=g) +Group quota are not enabled on SCRATCH_DEV + +checking report command (type=g) + +quota remount + +checking report command (type=g) +fsgqa 1024 0 0 00 [--------] 15 0 0 00 [--------] + +restore quota + +checking restore command (type=g) + +checking report command (type=g) +fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days] + + +checking state command (type=g) +Group quota state on SCRATCH_MNT (SCRATCH_DEV) + Accounting: ON + Enforcement: ON + Inode: #[INO] (X blocks, Y extents) +Blocks grace time: [7 days] +Inodes grace time: [7 days] +Realtime Blocks grace time: [7 days] +cleanup files diff --git a/tests/xfs/group b/tests/xfs/group index 288b916d..03b447c7 100644 --- a/tests/xfs/group +++ b/tests/xfs/group @@ -505,3 +505,4 @@ 526 auto quick mkfs 527 auto quick quota 528 auto quick rw realtime +529 auto quick quota idmapped From patchwork Sun Mar 28 22:34:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12169171 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A9C6EC433E0 for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 803EE6195F for ; Sun, 28 Mar 2021 22:35:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231546AbhC1Wee (ORCPT ); Sun, 28 Mar 2021 18:34:34 -0400 Received: from mail.kernel.org ([198.145.29.99]:48002 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231552AbhC1We2 (ORCPT ); Sun, 28 Mar 2021 18:34:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id EDF2A6193F; Sun, 28 Mar 2021 22:34:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616970868; bh=oGGfyrcEDtSdqexqRiJO/kTJUTjMXJdqjxw9hMufUG8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MmbkMW6x/jUqn6M5aNvo7ipxHqCyz1vjsnQS7PO+XAzttbUcz2TU0ZtPuMVLVPAVe IXzNwwCl7SR2/UiQLBJzUv9Ck43REIYIJ2yBkwT4ceptfbsqamBJHYqg5+V5Xfc43Q d3SsIVDo/yCcFurKVHVBZTkbnAm8cXn7RaGxDZ50yYbcoH2osNcrvgMqBmjiyma8z3 oIBGaECXIrI5p2lTVXxMQLefV7o6GDgJDKrDnHdv4oyY57PNNbHeSGh+z4R6WmRmG0 f+mo7IVcMDYMi9zM26bBRr47Hx+WCo69xfNgrqdscvpStkHix8rcZaz1c/cC9zvOVK nVmcj7gPqp67w== From: Christian Brauner To: Eryu Guan , fstests@vger.kernel.org, Christoph Hellwig Cc: "Darrick J . Wong" , David Howells , Christian Brauner Subject: [PATCH v12 6/6] xfs/530: quotas on idmapped mounts Date: Mon, 29 Mar 2021 00:34:00 +0200 Message-Id: <20210328223400.1800301-7-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210328223400.1800301-1-brauner@kernel.org> References: <20210328223400.1800301-1-brauner@kernel.org> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=cOLF8OTvRYXC3y485VSv6ujk3GSawMtRMrE2w7da8uQ=; m=NSojVSEcGmHs17du71gAqBeEPUmyNa+aTP10K3+zNDY=; p=5IPG7PkJ8lEg0tHazaSCM9UAg1xyfOOU5cJiD2lywb0=; g=76f367105ab177f69a9d0c5c4fa3a37a7167f47b X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGEEHAAKCRCRxhvAZXjcoiZDAQD3smI ZxCixlj3oOlYk2xNc4+9q8ZcHX2YEEX21e+Rs3wD+LWMUdEPMHhKEmU1DqKGVYUVUkrUF1PUviaOP lR17VgI= Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Christian Brauner This is basically a re-implementation of xfs/050 but each file creation call is done through an idmapped mount which verifies that the semantics are identical even when the mount is idmapped. Cc: Eryu Guan Cc: Darrick J. Wong Cc: fstests@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Christian Brauner --- /* v1 - v8 */ patch not present /* v9 */ - Christian Brauner : - Rebased onto current master. /* v10 */ - Eryu Guan : - Remove leading "_" from local helpers. - Use newly introduced _scratch_{u}mount_idmapped() helpers /* v11 */ - Amir Goldstein : - Add a dedicated "idmapped" tag for idmapped mounts tests. /* v12 */ unchanged --- tests/xfs/530 | 212 ++++++++++++++++++++++++++++++++++++++++++++++ tests/xfs/530.out | 129 ++++++++++++++++++++++++++++ tests/xfs/group | 1 + 3 files changed, 342 insertions(+) create mode 100644 tests/xfs/530 create mode 100644 tests/xfs/530.out diff --git a/tests/xfs/530 b/tests/xfs/530 new file mode 100644 index 00000000..7d2e8771 --- /dev/null +++ b/tests/xfs/530 @@ -0,0 +1,212 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021 Christian Brauner +# All Rights Reserved. +# +# FS QA Test No. 530 +# +# Exercises basic XFS quota functionality +# uquota, gquota, uqnoenforce, gqnoenforce +# +seq=`basename $0` +seqres=$RESULT_DIR/$seq +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common/rc +. ./common/filter +. ./common/quota + +_cleanup() +{ + cd / + _scratch_unmount 2>/dev/null + rm -f $tmp.* +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# real QA test starts here +_supported_fs xfs + +cp /dev/null $seqres.full +chmod a+rwx $seqres.full # arbitrary users will write here + +_require_scratch +_require_xfs_quota +_require_user fsgqa +_require_test_program "idmapped-mounts/mount-idmapped" + +_scratch_mkfs >/dev/null 2>&1 +_scratch_mount +bsize=$(_get_file_block_size $SCRATCH_MNT) +_scratch_unmount + +bsoft=$(( 200 * $bsize )) +bhard=$(( 1000 * $bsize )) +isoft=4 +ihard=10 + +# The actual point at which limit enforcement takes place for the +# hard block limit is variable depending on filesystem blocksize, +# and iosize. What we want to test is that the limit is enforced +# (ie. blksize less than limit but not unduly less - ~85% is kind) +# nowadays we actually get much closer to the limit before EDQUOT. +# +_filter_and_check_blks() +{ + perl -npe ' + if (/^\#'$id'\s+(\d+)/ && '$enforce') { + $maximum = '$bhard'; + $minimum = '$bhard' * 85/100; + $used = $1 * 1024; + if (($used < $minimum || $used > $maximum) && '$noextsz') { + printf(" URK %d: %d is out of range! [%d,%d]\n", + '$id', $used, $minimum, $maximum); + } + s/^(\#'$id'\s+)(\d+)/\1 =OK=/g; + } + ' | _filter_quota_report +} + +run_tests() +{ + _scratch_mkfs_xfs | _filter_mkfs 2>$tmp.mkfs + cat $tmp.mkfs >>$seqres.full + + # keep the blocksize and data size for dd later + . $tmp.mkfs + + _qmount + + # Figure out whether we're doing large allocations + # (bail out if they're so large they stuff the test up) + _test_inode_flag extsz-inherit $SCRATCH_MNT + noextsz=$? + extsize=`_test_inode_extsz $SCRATCH_MNT` + [ $extsize -ge 512000 ] && \ + _notrun "Extent size hint is too large ($extsize bytes)" + + _qsetup $1 + + echo "Using type=$type id=$id" >>$seqres.full + + $XFS_QUOTA_PROG -x -c "warn -$type 65535 -d" $SCRATCH_DEV + + echo + echo "*** report no quota settings" | tee -a $seqres.full + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "repquota -birnN -$type" $SCRATCH_DEV | + _filter_quota_report | LC_COLLATE=POSIX sort -ru + + echo + echo "*** report initial settings" | tee -a $seqres.full + _scratch_mount_idmapped $type $id + _file_as_id $SCRATCH_MNT/initme 0 $type 1024 0 + _scratch_umount_idmapped + echo "ls -l $SCRATCH_MNT" >>$seqres.full + ls -l $SCRATCH_MNT >>$seqres.full + $XFS_QUOTA_PROG -D $tmp.projects -P $temp.projid -x \ + -c "limit -$type bsoft=${bsoft} bhard=${bhard} $id" \ + -c "limit -$type isoft=$isoft ihard=$ihard $id" \ + $SCRATCH_DEV + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "repquota -birnN -$type" $SCRATCH_DEV | + _filter_quota_report | LC_COLLATE=POSIX sort -ru + + echo + echo "*** push past the soft inode limit" | tee -a $seqres.full + _scratch_mount_idmapped $type $id + _file_as_id $SCRATCH_MNT/softie1 0 $type 1024 0 + _file_as_id $SCRATCH_MNT/softie2 0 $type 1024 0 + _file_as_id $SCRATCH_MNT/softie3 0 $type 1024 0 + _file_as_id $SCRATCH_MNT/softie4 0 $type 1024 0 + _scratch_umount_idmapped + _qmount + $XFS_QUOTA_PROG -x -c "warn -i -$type 0 $id" $SCRATCH_DEV + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "repquota -birnN -$type" $SCRATCH_DEV | + _filter_quota_report | LC_COLLATE=POSIX sort -ru + + echo + echo "*** push past the soft block limit" | tee -a $seqres.full + _scratch_mount_idmapped $type $id + _file_as_id $SCRATCH_MNT/softie 0 $type $bsize 300 + _scratch_umount_idmapped + _qmount + $XFS_QUOTA_PROG -x -c "warn -i -$type 0 $id" \ + -c "warn -b -$type 0 $id" $SCRATCH_DEV + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "repquota -birnN -$type" $SCRATCH_DEV | + _filter_quota_report | LC_COLLATE=POSIX sort -ru + + echo + # Note: for quota accounting (not enforcement), EDQUOT is not expected + echo "*** push past the hard inode limit (expect EDQUOT)" | tee -a $seqres.full + for i in 1 2 3 4 5 6 7 8 9 10 11 12 + do + _scratch_mount_idmapped $type $id + _file_as_id $SCRATCH_MNT/hard$i 0 $type 1024 0 + _scratch_umount_idmapped + done + _qmount + $XFS_QUOTA_PROG -x -c "warn -b -$type 0 $id" \ + -c "warn -i -$type 0 $id" $SCRATCH_DEV + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "repquota -birnN -$type" $SCRATCH_DEV | + _filter_quota_report | LC_COLLATE=POSIX sort -ru + + echo + # Note: for quota accounting (not enforcement), EDQUOT is not expected + echo "*** push past the hard block limit (expect EDQUOT)" | tee -a $seqres.full + _scratch_mount_idmapped $type $id + _file_as_id $SCRATCH_MNT/softie 0 $type $bsize 1200 + _scratch_umount_idmapped + echo "ls -l $SCRATCH_MNT" >>$seqres.full + ls -l $SCRATCH_MNT >>$seqres.full + _qmount + $XFS_QUOTA_PROG -x -c "warn -b -$type 0 $id" $SCRATCH_DEV + $XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \ + -c "repquota -birnN -$type" $SCRATCH_DEV | + _filter_and_check_blks | LC_COLLATE=POSIX sort -ru + + echo + echo "*** unmount" + _scratch_unmount + +} + +cat >$tmp.projects <$tmp.projid <