diff mbox series

[v1,11/11] syscalls/quotactl09: Test error when quota info hidden in filesystem

Message ID 1634562996-6045-1-git-send-email-xuyang2018.jy@fujitsu.com
State Changes Requested
Headers show
Series [v1,01/11] syscalls/quotactl01: Also test with vfsv1 format | expand

Commit Message

Yang Xu Oct. 18, 2021, 1:16 p.m. UTC
This case is similar to quotactl06 but only two differences
1) use quotactl and quotactl_fd syscalls without visible quota file
2) remove some error for addr argument

Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/quotactl/.gitignore |   1 +
 .../kernel/syscalls/quotactl/quotactl09.c     | 179 ++++++++++++++++++
 3 files changed, 181 insertions(+)
 create mode 100644 testcases/kernel/syscalls/quotactl/quotactl09.c

Comments

Cyril Hrubis Oct. 26, 2021, 2:41 p.m. UTC | #1
Hi!
Generally looks good, same minor comments as for the rest of the
patchset apply here as well:

- for the description comment
- no need to include "lapi/quotactl.h"
- there are some trailing whitespaces (have you run make check before submitting?)
- does geteuid() in setup return anything else than 0?

Also I wonder if we should include the fmtv0 in the variant list, but as
far as I can tell it only matters for the tests that attempt to set the
limits, right?

I guess that we can define the test variants as:

static struct quotactl_variant {
	int use_fd;
	int32_t fmt_id;
	const char *fmt_name;
} variants[] = {
	{.use_fd = 0, .fmt_id = QFMT_VFS_V1, .fmt_name = "fmtv1"},
	{.use_fd = 1, .fmt_id = QFMT_VFS_V1, .fmt_name = "fmtv1"},
	{.use_fd = 0, .fmt_id = QFMT_VFS_V0, .fmt_name = "fmtv0"},
	{.use_fd = 1, .fmt_id = QFMT_VFS_V0, .fmt_name = "fmtv0"},
};

And then set .variants = 2 for all the tests that does not touch the
limits and for these tests that manipulate the limits set .variants = 4
Yang Xu Oct. 27, 2021, 3:26 a.m. UTC | #2
Hi Cyril
> Hi!
> Generally looks good, same minor comments as for the rest of the
> patchset apply here as well:
>
> - for the description comment
> - no need to include "lapi/quotactl.h"
> - there are some trailing whitespaces (have you run make check before submitting?)
Sorry, I forgot to run.
> - does geteuid() in setup return anything else than 0?
>
> Also I wonder if we should include the fmtv0 in the variant list, but as
> far as I can tell it only matters for the tests that attempt to set the
> limits, right?
>
> I guess that we can define the test variants as:
>
> static struct quotactl_variant {
> 	int use_fd;
> 	int32_t fmt_id;
> 	const char *fmt_name;
> } variants[] = {
> 	{.use_fd = 0, .fmt_id = QFMT_VFS_V1, .fmt_name = "fmtv1"},
> 	{.use_fd = 1, .fmt_id = QFMT_VFS_V1, .fmt_name = "fmtv1"},
> 	{.use_fd = 0, .fmt_id = QFMT_VFS_V0, .fmt_name = "fmtv0"},
> 	{.use_fd = 1, .fmt_id = QFMT_VFS_V0, .fmt_name = "fmtv0"},
> };
>
> And then set .variants = 2 for all the tests that does not touch the
> limits and for these tests that manipulate the limits set .variants = 4

At the begining, I also have same idea. But quota info hidden in 
filesystem  doesn't use quotacheck cmd and also doesn't use vfsv0 
foramt. Also quotactl_fd is also hidden in filesystem, so it only use 
QFMT_VFS_V1 format.

I perfer to make this patchset by the following idea

1)if quota info is visable, then test vfsv1 and vfsv0 two variants
2)if quota info is hidden in filesystem, then it only support vfsv1,
so test use_fd and not_use_fd variants.

Best Regards
Yang Xu

>
diff mbox series

Patch

diff --git a/runtest/syscalls b/runtest/syscalls
index cdeb3e142..c8df80fa0 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1074,6 +1074,7 @@  quotactl05 quotactl05
 quotactl06 quotactl06
 quotactl07 quotactl07
 quotactl08 quotactl08
+quotactl09 quotactl09
 
 read01 read01
 read02 read02
diff --git a/testcases/kernel/syscalls/quotactl/.gitignore b/testcases/kernel/syscalls/quotactl/.gitignore
index dab9b3420..94de2c8f2 100644
--- a/testcases/kernel/syscalls/quotactl/.gitignore
+++ b/testcases/kernel/syscalls/quotactl/.gitignore
@@ -6,3 +6,4 @@ 
 /quotactl06
 /quotactl07
 /quotactl08
+/quotactl09
diff --git a/testcases/kernel/syscalls/quotactl/quotactl09.c b/testcases/kernel/syscalls/quotactl/quotactl09.c
new file mode 100644
index 000000000..3276624bc
--- /dev/null
+++ b/testcases/kernel/syscalls/quotactl/quotactl09.c
@@ -0,0 +1,179 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Tests basic error handling of the quotactl syscall without visible quota files
+ * (use quotactl and quotactl_fd syscall):
+ *
+ * 1) quotactl fails with EFAULT when addr or special is invalid.
+ *
+ * 2) quotactl fails with EINVAL when cmd or type is invalid.
+ *
+ * 3) quotactl fails with ENOTBLK when special is not a block device.
+ *
+ * 4) quotactl fails with ERANGE when cmd is Q_SETQUOTA, but the
+ * specified limits are out of the range allowed by the quota format.
+ *
+ * 5) quotactl fails with EPERM when the caller lacked the required
+ * privilege (CAP_SYS_ADMIN) for the specified operation.
+ */
+
+#include <errno.h>
+#include <sys/quota.h>
+#include "tst_test.h"
+#include "lapi/quotactl.h"
+#include "tst_capability.h"
+#include "quotactl_var.h"
+
+#define OPTION_INVALID 999
+#define MNTPOINT "mntpoint"
+#define TESTFILE MNTPOINT "/testfile"
+
+static int32_t fmt_id;
+static int test_id, fd = -1;
+static int getnextquota_nsup;
+
+static struct if_nextdqblk res_ndq;
+
+static struct dqblk set_dqmax = {
+	.dqb_bsoftlimit = 0x7fffffffffffffffLL,  /* 2^63-1 */
+	.dqb_valid = QIF_BLIMITS
+};
+
+struct tst_cap dropadmin = {
+	.action = TST_CAP_DROP,
+	.id = CAP_SYS_ADMIN,
+	.name = "CAP_SYS_ADMIN",
+};
+
+struct tst_cap needadmin = {
+	.action = TST_CAP_REQ,
+	.id = CAP_SYS_ADMIN,
+	.name = "CAP_SYS_ADMIN",
+};
+
+static struct tcase {
+	int cmd;
+	int *id;
+	void *addr;
+	int exp_err;
+	int on_flag;
+} tcases[] = {
+	{QCMD(Q_SETQUOTA, USRQUOTA), &fmt_id, NULL, EFAULT, 1},
+	{QCMD(OPTION_INVALID, USRQUOTA), &fmt_id, NULL, EINVAL, 0},
+	{QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, ENOTBLK, 0},
+	{QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dqmax, ERANGE, 1},
+	{QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EPERM, 0},
+};
+
+static void verify_quotactl(unsigned int n)
+{
+	struct tcase *tc = &tcases[n];
+	int quota_on = 0;
+	int drop_flag = 0;
+
+	if (tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA) && getnextquota_nsup) {
+		tst_res(TCONF, "current system doesn't support Q_GETNEXTQUOTA");
+		return;
+	}
+
+	if (tc->on_flag) {
+		TEST(do_quotactl(fd, QCMD(Q_QUOTAON, USRQUOTA), tst_device->dev,
+			fmt_id, NULL));
+		if (TST_RET == -1)
+			tst_brk(TBROK,
+				"quotactl with Q_QUOTAON returned %ld", TST_RET);
+		quota_on = 1;
+	}
+
+	if (tc->exp_err == EPERM) {
+		tst_cap_action(&dropadmin);
+		drop_flag = 1;
+	}
+	
+	if (tst_variant) {
+		if (tc->exp_err == ENOTBLK) {
+			tst_res(TCONF, "quotactl_fd() doesn't have this error, skip");
+			return;
+		}
+	}
+	if (tc->exp_err == ENOTBLK)
+		TEST(do_quotactl(fd, tc->cmd, "/dev/null", *tc->id, tc->addr));
+	else
+		TEST(do_quotactl(fd, tc->cmd, tst_device->dev, *tc->id, tc->addr));
+
+	if (TST_RET == -1) {
+		if (tc->exp_err == TST_ERR) {
+			tst_res(TPASS | TTERRNO, "quotactl failed as expected");
+		} else {
+			tst_res(TFAIL | TTERRNO,
+				"quotactl failed unexpectedly; expected %s, but got",
+				tst_strerrno(tc->exp_err));
+		}
+	} else {
+		tst_res(TFAIL, "quotactl returned wrong value: %ld", TST_RET);
+	}
+
+	if (quota_on) {
+		TEST(do_quotactl(fd, QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev,
+			fmt_id, NULL));
+		if (TST_RET == -1)
+			tst_brk(TBROK,
+				"quotactl with Q_QUOTAOFF returned %ld", TST_RET);
+		quota_on = 0;
+	}
+
+	if (drop_flag) {
+		tst_cap_action(&needadmin);
+		drop_flag = 0;
+	}
+}
+
+static void setup(void)
+{
+	unsigned int i;
+
+	fmt_id = QFMT_VFS_V1;
+	quotactl_info();
+
+	test_id = geteuid();
+	fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, 0644);
+
+	TEST(do_quotactl(fd, QCMD(Q_GETNEXTQUOTA, USRQUOTA), tst_device->dev,
+		test_id, (void *) &res_ndq));
+	if (TST_ERR == EINVAL || TST_ERR == ENOSYS)
+		getnextquota_nsup = 1;
+
+	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
+		if (!tcases[i].addr)
+			tcases[i].addr = tst_get_bad_addr(NULL);
+	}
+}
+
+static void cleanup(void)
+{
+	if (fd > -1)
+		SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_QFMT_V2",
+		NULL
+	},
+	.tcnt = ARRAY_SIZE(tcases),
+	.test = verify_quotactl,
+	.dev_fs_type = "ext4",
+	.mntpoint = MNTPOINT,
+	.mount_device = 1,
+	.dev_fs_opts = (const char *const []){"-O", "quota", NULL},
+	.needs_root = 1,
+	.test_variants = 2,
+};