1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2019-2021 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This testcase checks that quotactl(2) on ext4 filesystem succeeds to: 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * - turn on quota with Q_QUOTAON flag for project 13f08c3bdfSopenharmony_ci * - set disk quota limits with Q_SETQUOTA flag for project 14f08c3bdfSopenharmony_ci * - get disk quota limits with Q_GETQUOTA flag for project 15f08c3bdfSopenharmony_ci * - set information about quotafile with Q_SETINFO flag for project 16f08c3bdfSopenharmony_ci * - get information about quotafile with Q_GETINFO flag for project 17f08c3bdfSopenharmony_ci * - get quota format with Q_GETFMT flag for project 18f08c3bdfSopenharmony_ci * - get disk quota limit greater than or equal to ID with Q_GETNEXTQUOTA flag for project 19f08c3bdfSopenharmony_ci * - turn off quota with Q_QUOTAOFF flag for project 20f08c3bdfSopenharmony_ci * 21f08c3bdfSopenharmony_ci * Minimum e2fsprogs version required is 1.43. 22f08c3bdfSopenharmony_ci */ 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#include <errno.h> 25f08c3bdfSopenharmony_ci#include <string.h> 26f08c3bdfSopenharmony_ci#include <unistd.h> 27f08c3bdfSopenharmony_ci#include <sys/stat.h> 28f08c3bdfSopenharmony_ci#include <sys/mount.h> 29f08c3bdfSopenharmony_ci#include "tst_test.h" 30f08c3bdfSopenharmony_ci#include "quotactl_syscall_var.h" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#define FMTID QFMT_VFS_V1 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_cistatic int32_t fmt_id = FMTID; 35f08c3bdfSopenharmony_cistatic int test_id, mount_flag; 36f08c3bdfSopenharmony_cistatic struct dqblk set_dq = { 37f08c3bdfSopenharmony_ci .dqb_bsoftlimit = 100, 38f08c3bdfSopenharmony_ci .dqb_valid = QIF_BLIMITS 39f08c3bdfSopenharmony_ci}; 40f08c3bdfSopenharmony_cistatic struct dqblk res_dq; 41f08c3bdfSopenharmony_cistatic struct dqinfo set_qf = { 42f08c3bdfSopenharmony_ci .dqi_bgrace = 80, 43f08c3bdfSopenharmony_ci .dqi_valid = IIF_BGRACE 44f08c3bdfSopenharmony_ci}; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic struct dqinfo res_qf; 47f08c3bdfSopenharmony_cistatic int32_t fmt_buf; 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_cistatic struct if_nextdqblk res_ndq; 50f08c3bdfSopenharmony_cistatic int getnextquota_nsup; 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic struct tcase { 53f08c3bdfSopenharmony_ci int cmd; 54f08c3bdfSopenharmony_ci int *id; 55f08c3bdfSopenharmony_ci void *addr; 56f08c3bdfSopenharmony_ci void *set_data; 57f08c3bdfSopenharmony_ci void *res_data; 58f08c3bdfSopenharmony_ci int sz; 59f08c3bdfSopenharmony_ci char *des; 60f08c3bdfSopenharmony_ci char *tname; 61f08c3bdfSopenharmony_ci} tcases[] = { 62f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, PRJQUOTA), &fmt_id, NULL, 63f08c3bdfSopenharmony_ci NULL, NULL, 0, "turn on quota for project", 64f08c3bdfSopenharmony_ci "QCMD(Q_QUOTAON, PRJQUOTA)"}, 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci {QCMD(Q_SETQUOTA, PRJQUOTA), &test_id, &set_dq, 67f08c3bdfSopenharmony_ci NULL, NULL, 0, "set disk quota limit for project", 68f08c3bdfSopenharmony_ci "QCMD(Q_SETQUOTA, PRJQUOTA)"}, 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci {QCMD(Q_GETQUOTA, PRJQUOTA), &test_id, &res_dq, 71f08c3bdfSopenharmony_ci &set_dq.dqb_bsoftlimit, &res_dq.dqb_bsoftlimit, 72f08c3bdfSopenharmony_ci sizeof(res_dq.dqb_bsoftlimit), "get disk quota limit for project", 73f08c3bdfSopenharmony_ci "QCMD(Q_GETQUOTA, PRJQUOTA)"}, 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_ci {QCMD(Q_SETINFO, PRJQUOTA), &test_id, &set_qf, 76f08c3bdfSopenharmony_ci NULL, NULL, 0, "set information about quotafile for project", 77f08c3bdfSopenharmony_ci "QCMD(Q_SETINFO, PRJQUOTA"}, 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci {QCMD(Q_GETINFO, PRJQUOTA), &test_id, &res_qf, 80f08c3bdfSopenharmony_ci &set_qf.dqi_bgrace, &res_qf.dqi_bgrace, sizeof(res_qf.dqi_bgrace), 81f08c3bdfSopenharmony_ci "get information about quotafile for project", 82f08c3bdfSopenharmony_ci "QCMD(Q_GETINFO, PRJQUOTA"}, 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci {QCMD(Q_GETFMT, PRJQUOTA), &test_id, &fmt_buf, 85f08c3bdfSopenharmony_ci &fmt_id, &fmt_buf, sizeof(fmt_buf), 86f08c3bdfSopenharmony_ci "get quota format for project", "QCMD(Q_GETFMT, PRJQUOTA)"}, 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci {QCMD(Q_GETNEXTQUOTA, PRJQUOTA), &test_id, &res_ndq, 89f08c3bdfSopenharmony_ci &test_id, &res_ndq.dqb_id, sizeof(res_ndq.dqb_id), 90f08c3bdfSopenharmony_ci "get next disk quota limit for project", 91f08c3bdfSopenharmony_ci "QCMD(Q_GETNEXTQUOTA, PRJQUOTA)"}, 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAOFF, PRJQUOTA), &test_id, NULL, 94f08c3bdfSopenharmony_ci NULL, NULL, 0, "turn off quota for project", 95f08c3bdfSopenharmony_ci "QCMD(Q_QUOTAOFF, PRJQUOTA)"}, 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci}; 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistatic void setup(void) 100f08c3bdfSopenharmony_ci{ 101f08c3bdfSopenharmony_ci const char *const fs_opts[] = {"-I 256", "-O quota,project", NULL}; 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci quotactl_info(); 104f08c3bdfSopenharmony_ci SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); 105f08c3bdfSopenharmony_ci SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); 106f08c3bdfSopenharmony_ci mount_flag = 1; 107f08c3bdfSopenharmony_ci fd = SAFE_OPEN(MNTPOINT, O_RDONLY); 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci TEST(do_quotactl(fd, QCMD(Q_GETNEXTQUOTA, PRJQUOTA), tst_device->dev, 110f08c3bdfSopenharmony_ci test_id, (void *) &res_ndq)); 111f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL || TST_ERR == ENOSYS) 112f08c3bdfSopenharmony_ci getnextquota_nsup = 1; 113f08c3bdfSopenharmony_ci} 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_cistatic void cleanup(void) 116f08c3bdfSopenharmony_ci{ 117f08c3bdfSopenharmony_ci if (fd > -1) 118f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 119f08c3bdfSopenharmony_ci if (mount_flag && tst_umount(MNTPOINT)) 120f08c3bdfSopenharmony_ci tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); 121f08c3bdfSopenharmony_ci} 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_cistatic void verify_quota(unsigned int n) 124f08c3bdfSopenharmony_ci{ 125f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci res_dq.dqb_bsoftlimit = 0; 128f08c3bdfSopenharmony_ci res_qf.dqi_igrace = 0; 129f08c3bdfSopenharmony_ci fmt_buf = 0; 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", n, tc->tname); 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci if (tc->cmd == QCMD(Q_GETNEXTQUOTA, PRJQUOTA) && getnextquota_nsup) { 134f08c3bdfSopenharmony_ci tst_res(TCONF, "current system doesn't support this cmd"); 135f08c3bdfSopenharmony_ci return; 136f08c3bdfSopenharmony_ci } 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(do_quotactl(fd, tc->cmd, tst_device->dev, *tc->id, tc->addr), 139f08c3bdfSopenharmony_ci "do_quotactl to %s", tc->des); 140f08c3bdfSopenharmony_ci if (!TST_PASS) 141f08c3bdfSopenharmony_ci return; 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci if (memcmp(tc->res_data, tc->set_data, tc->sz)) { 144f08c3bdfSopenharmony_ci tst_res(TFAIL, "quotactl failed to %s", tc->des); 145f08c3bdfSopenharmony_ci tst_res_hexd(TINFO, tc->res_data, tc->sz, "retval: "); 146f08c3bdfSopenharmony_ci tst_res_hexd(TINFO, tc->set_data, tc->sz, "expected: "); 147f08c3bdfSopenharmony_ci return; 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci tst_res(TPASS, "quotactl succeeded to %s", tc->des); 151f08c3bdfSopenharmony_ci} 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_cistatic struct tst_test test = { 154f08c3bdfSopenharmony_ci .needs_root = 1, 155f08c3bdfSopenharmony_ci .needs_drivers = (const char *const []) { 156f08c3bdfSopenharmony_ci "quota_v2", 157f08c3bdfSopenharmony_ci NULL 158f08c3bdfSopenharmony_ci }, 159f08c3bdfSopenharmony_ci .min_kver = "4.5", /* commit 689c958cbe6b (ext4: add project quota support) */ 160f08c3bdfSopenharmony_ci .test = verify_quota, 161f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 162f08c3bdfSopenharmony_ci .setup = setup, 163f08c3bdfSopenharmony_ci .cleanup = cleanup, 164f08c3bdfSopenharmony_ci .needs_device = 1, 165f08c3bdfSopenharmony_ci .dev_fs_type = "ext4", 166f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 167f08c3bdfSopenharmony_ci .test_variants = QUOTACTL_SYSCALL_VARIANTS, 168f08c3bdfSopenharmony_ci .needs_cmds = (const char *[]) { 169f08c3bdfSopenharmony_ci "mkfs.ext4 >= 1.43.0", 170f08c3bdfSopenharmony_ci NULL 171f08c3bdfSopenharmony_ci } 172f08c3bdfSopenharmony_ci}; 173