Message ID | 1641973691-22981-1-git-send-email-xuyang2018.jy@fujitsu.com |
---|---|
State | Accepted |
Headers | show |
Series | [v6,1/3] syscalls/quotactl09: Test error when quota info hidden in filesystem | expand |
Hi Cyril As your suggestion, I modify this patch as below diff --git a/testcases/kernel/syscalls/quotactl/quotactl09.c b/testcases/kernel/syscalls/quotactl/quotactl09.c index 79f506bdc..4dbfcc7ea 100644 --- a/testcases/kernel/syscalls/quotactl/quotactl09.c +++ b/testcases/kernel/syscalls/quotactl/quotactl09.c @@ -17,14 +17,14 @@ * allowed by the quota format * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for the * specified operation - * - EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't - * under this moutpoint) + * - ENOSYS when cmd is Q_QUOTAON, but the fd refers to a socket * * Minimum e2fsprogs version required is 1.43. */ #include <errno.h> #include <sys/quota.h> +#include <sys/socket.h> #include "tst_test.h" #include "tst_capability.h" #include "quotactl_syscall_var.h" @@ -33,7 +33,7 @@ static int32_t fmt_id = QFMT_VFS_V1; static int test_id, mount_flag; -static int getnextquota_nsup, external_fd = -1; +static int getnextquota_nsup, socket_fd = -1; static struct if_nextdqblk res_ndq; @@ -60,27 +60,25 @@ static struct tcase { void *addr; int exp_err; int on_flag; - int use_external_fd; char *des; } tcases[] = { - {QCMD(Q_SETQUOTA, USRQUOTA), &fmt_id, NULL, EFAULT, 1, 0, + {QCMD(Q_SETQUOTA, USRQUOTA), &fmt_id, NULL, EFAULT, 1, "EFAULT when addr or special is invalid"}, - {QCMD(OPTION_INVALID, USRQUOTA), &fmt_id, NULL, EINVAL, 0, 0, + {QCMD(OPTION_INVALID, USRQUOTA), &fmt_id, NULL, EINVAL, 0, "EINVAL when cmd or type is invalid"}, - {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, ENOTBLK, 0, 0, + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, ENOTBLK, 0, "ENOTBLK when special is not a block device"}, - {QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dqmax, ERANGE, 1, 0, + {QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dqmax, ERANGE, 1, "ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range"}, - {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EPERM, 0, 0, + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EPERM, 0, "EPERM when the caller lacked the required privilege for specified operations"}, - {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EINVAL, 0, 1, - "EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't under" - "this mountpoint)"} + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, ENOSYS, 0, + "ENOSYS when cmd is Q_QUOTAON, but the fd refers to a socket"} }; static void verify_quotactl(unsigned int n) @@ -113,8 +111,12 @@ static void verify_quotactl(unsigned int n) tst_res(TCONF, "quotactl_fd() doesn't have this error, skip"); return; } + if (tc->exp_err == ENOSYS) { + TST_EXP_FAIL(syscall(__NR_quotactl_fd, socket_fd, tc->cmd, *tc->id, tc->addr), tc->exp_err, "syscall(quotactl_fd)"); + return; + } } else { - if (tc->use_external_fd) { + if (tc->exp_err == ENOSYS) { tst_res(TCONF, "quotactl() doesn't use fd, skip"); return; } @@ -123,8 +125,8 @@ static void verify_quotactl(unsigned int n) TST_EXP_FAIL(do_quotactl(fd, tc->cmd, "/dev/null", *tc->id, tc->addr), ENOTBLK, "do_quotactl()"); else - TST_EXP_FAIL(do_quotactl(tc->use_external_fd ? external_fd : fd, tc->cmd, - tst_device->dev, *tc->id, tc->addr), tc->exp_err, "do_quotactl()"); + TST_EXP_FAIL(do_quotactl(fd, tc->cmd, tst_device->dev, *tc->id, tc->addr), + tc->exp_err, "do_quotactl()"); if (quota_on) { TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev, @@ -146,12 +148,11 @@ static void setup(void) const char *const fs_opts[] = { "-O quota", NULL}; quotactl_info(); - external_fd = SAFE_CREAT("testfile", O_RDONLY); SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); mount_flag = 1; - + socket_fd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); fd = SAFE_OPEN(MNTPOINT, O_RDONLY); TEST(do_quotactl(fd, QCMD(Q_GETNEXTQUOTA, USRQUOTA), tst_device->dev, test_id, (void *) &res_ndq)); @@ -168,8 +169,8 @@ static void cleanup(void) { if (fd > -1) SAFE_CLOSE(fd); - if (external_fd > -1) - SAFE_CLOSE(external_fd); + if (socket_fd > -1) + SAFE_CLOSE(socket_fd); if (mount_flag && tst_umount(MNTPOINT)) tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); How about this patch after this change? Best Regards Yang Xu > This case is similar to quotactl06 but only some differences > 1) use quotactl and quotactl_fd syscalls without visible quota file > 2) remove some error for addr argument > 3) test external_fd for quotactl_fd for EINVAL error when using Q_QUOTAON > 4) add error case description when running > > Signed-off-by: Yang Xu<xuyang2018.jy@fujitsu.com> > --- > runtest/syscalls | 1 + > testcases/kernel/syscalls/quotactl/.gitignore | 1 + > .../kernel/syscalls/quotactl/quotactl09.c | 195 ++++++++++++++++++ > 3 files changed, 197 insertions(+) > create mode 100644 testcases/kernel/syscalls/quotactl/quotactl09.c > > diff --git a/runtest/syscalls b/runtest/syscalls > index a0ca84b36..3b2deb64e 100644 > --- a/runtest/syscalls > +++ b/runtest/syscalls > @@ -1073,6 +1073,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..79f506bdc > --- /dev/null > +++ b/testcases/kernel/syscalls/quotactl/quotactl09.c > @@ -0,0 +1,195 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. > + * Author: Yang Xu<xuyang2018.jy@fujitsu.com> > + */ > + > +/*\ > + * [Description] > + * > + * Tests basic error handling of the quotactl syscall without visible quota files > + * (use quotactl and quotactl_fd syscall): > + * > + * - EFAULT when addr or special is invalid > + * - EINVAL when cmd or type is invalid > + * - ENOTBLK when special is not a block device > + * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range > + * allowed by the quota format > + * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for the > + * specified operation > + * - EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't > + * under this moutpoint) > + * > + * Minimum e2fsprogs version required is 1.43. > + */ > + > +#include<errno.h> > +#include<sys/quota.h> > +#include "tst_test.h" > +#include "tst_capability.h" > +#include "quotactl_syscall_var.h" > + > +#define OPTION_INVALID 999 > + > +static int32_t fmt_id = QFMT_VFS_V1; > +static int test_id, mount_flag; > +static int getnextquota_nsup, external_fd = -1; > + > +static struct if_nextdqblk res_ndq; > + > +static struct dqblk set_dqmax = { > + .dqb_bsoftlimit = 0x7fffffffffffffffLL, /* 2^63-1 */ > + .dqb_valid = QIF_BLIMITS > +}; > + > +static struct tst_cap dropadmin = { > + .action = TST_CAP_DROP, > + .id = CAP_SYS_ADMIN, > + .name = "CAP_SYS_ADMIN", > +}; > + > +static 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; > + int use_external_fd; > + char *des; > +} tcases[] = { > + {QCMD(Q_SETQUOTA, USRQUOTA),&fmt_id, NULL, EFAULT, 1, 0, > + "EFAULT when addr or special is invalid"}, > + > + {QCMD(OPTION_INVALID, USRQUOTA),&fmt_id, NULL, EINVAL, 0, 0, > + "EINVAL when cmd or type is invalid"}, > + > + {QCMD(Q_QUOTAON, USRQUOTA),&fmt_id, NULL, ENOTBLK, 0, 0, > + "ENOTBLK when special is not a block device"}, > + > + {QCMD(Q_SETQUOTA, USRQUOTA),&test_id,&set_dqmax, ERANGE, 1, 0, > + "ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range"}, > + > + {QCMD(Q_QUOTAON, USRQUOTA),&fmt_id, NULL, EPERM, 0, 0, > + "EPERM when the caller lacked the required privilege for specified operations"}, > + > + {QCMD(Q_QUOTAON, USRQUOTA),&fmt_id, NULL, EINVAL, 0, 1, > + "EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't under " > + "this mountpoint)"} > +}; > + > +static void verify_quotactl(unsigned int n) > +{ > + struct tcase *tc =&tcases[n]; > + int quota_on = 0; > + int drop_flag = 0; > + > + tst_res(TINFO, "Testing %s", tc->des); > + if (tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA)&& getnextquota_nsup) { > + tst_res(TCONF, "current system doesn't support Q_GETNEXTQUOTA"); > + return; > + } > + > + if (tc->on_flag) { > + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAON, USRQUOTA), tst_device->dev, > + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAON, USRQUOTA))"); > + if (!TST_PASS) > + return; > + 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; > + } > + } else { > + if (tc->use_external_fd) { > + tst_res(TCONF, "quotactl() doesn't use fd, skip"); > + return; > + } > + } > + if (tc->exp_err == ENOTBLK) > + TST_EXP_FAIL(do_quotactl(fd, tc->cmd, "/dev/null", *tc->id, tc->addr), > + ENOTBLK, "do_quotactl()"); > + else > + TST_EXP_FAIL(do_quotactl(tc->use_external_fd ? external_fd : fd, tc->cmd, > + tst_device->dev, *tc->id, tc->addr), tc->exp_err, "do_quotactl()"); > + > + if (quota_on) { > + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev, > + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAOFF, USRQUOTA)"); > + if (!TST_PASS) > + return; > + quota_on = 0; > + } > + > + if (drop_flag) { > + tst_cap_action(&needadmin); > + drop_flag = 0; > + } > +} > + > +static void setup(void) > +{ > + unsigned int i; > + const char *const fs_opts[] = { "-O quota", NULL}; > + > + quotactl_info(); > + external_fd = SAFE_CREAT("testfile", O_RDONLY); > + > + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); > + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); > + mount_flag = 1; > + > + fd = SAFE_OPEN(MNTPOINT, O_RDONLY); > + 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); > + if (external_fd> -1) > + SAFE_CLOSE(external_fd); > + if (mount_flag&& tst_umount(MNTPOINT)) > + tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); > +} > + > +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, > + .needs_device = 1, > + .needs_root = 1, > + .test_variants = QUOTACTL_SYSCALL_VARIANTS, > + .needs_cmds = (const char *[]) { > + "mkfs.ext4>= 1.43.0", > + NULL > + } > +};
Hi!
> How about this patch after this change?
Looks reasonable.
Hi Cyril > Hi! >> How about this patch after this change? > > Looks reasonable. So do you have some comments for other two quotactl patches? or add RVB tag? ps: I want to make them merged in ltp before this release. Best Regargds Yang Xu >
Hi! > >> How about this patch after this change? > > > > Looks reasonable. > So do you have some comments for other two quotactl patches? or add RVB tag? > > ps: I want to make them merged in ltp before this release. I will have a look today, I had half day off yesterday and haven't managed to get to them.
Hi! > +/*\ > + * [Description] > + * > + * Tests basic error handling of the quotactl syscall without visible quota files > + * (use quotactl and quotactl_fd syscall): > + * > + * - EFAULT when addr or special is invalid > + * - EINVAL when cmd or type is invalid > + * - ENOTBLK when special is not a block device > + * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range > + * allowed by the quota format > + * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for the > + * specified operation > + * - EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't > + * under this moutpoint) > + * > + * Minimum e2fsprogs version required is 1.43. > + */ > + > +#include <errno.h> > +#include <sys/quota.h> > +#include "tst_test.h" > +#include "tst_capability.h" > +#include "quotactl_syscall_var.h" > + > +#define OPTION_INVALID 999 > + > +static int32_t fmt_id = QFMT_VFS_V1; > +static int test_id, mount_flag; > +static int getnextquota_nsup, external_fd = -1; > + > +static struct if_nextdqblk res_ndq; > + > +static struct dqblk set_dqmax = { > + .dqb_bsoftlimit = 0x7fffffffffffffffLL, /* 2^63-1 */ > + .dqb_valid = QIF_BLIMITS > +}; > + > +static struct tst_cap dropadmin = { > + .action = TST_CAP_DROP, > + .id = CAP_SYS_ADMIN, > + .name = "CAP_SYS_ADMIN", > +}; > + > +static 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; > + int use_external_fd; > + char *des; > +} tcases[] = { > + {QCMD(Q_SETQUOTA, USRQUOTA), &fmt_id, NULL, EFAULT, 1, 0, > + "EFAULT when addr or special is invalid"}, > + > + {QCMD(OPTION_INVALID, USRQUOTA), &fmt_id, NULL, EINVAL, 0, 0, > + "EINVAL when cmd or type is invalid"}, > + > + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, ENOTBLK, 0, 0, > + "ENOTBLK when special is not a block device"}, > + > + {QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dqmax, ERANGE, 1, 0, > + "ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range"}, > + > + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EPERM, 0, 0, > + "EPERM when the caller lacked the required privilege for specified operations"}, > + > + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EINVAL, 0, 1, > + "EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't under " > + "this mountpoint)"} > +}; > + > +static void verify_quotactl(unsigned int n) > +{ > + struct tcase *tc = &tcases[n]; > + int quota_on = 0; > + int drop_flag = 0; > + > + tst_res(TINFO, "Testing %s", tc->des); > + if (tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA) && getnextquota_nsup) { > + tst_res(TCONF, "current system doesn't support Q_GETNEXTQUOTA"); > + return; > + } > + > + if (tc->on_flag) { > + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAON, USRQUOTA), tst_device->dev, > + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAON, USRQUOTA))"); > + if (!TST_PASS) > + return; > + 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; > + } > + } else { > + if (tc->use_external_fd) { > + tst_res(TCONF, "quotactl() doesn't use fd, skip"); > + return; > + } > + } > + if (tc->exp_err == ENOTBLK) > + TST_EXP_FAIL(do_quotactl(fd, tc->cmd, "/dev/null", *tc->id, tc->addr), > + ENOTBLK, "do_quotactl()"); > + else > + TST_EXP_FAIL(do_quotactl(tc->use_external_fd ? external_fd : fd, tc->cmd, > + tst_device->dev, *tc->id, tc->addr), tc->exp_err, "do_quotactl()"); > + > + if (quota_on) { > + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev, > + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAOFF, USRQUOTA)"); > + if (!TST_PASS) > + return; > + quota_on = 0; There is no need to clear this flag. > + } > + > + if (drop_flag) { > + tst_cap_action(&needadmin); > + drop_flag = 0; And this flag. > + } > +} > + > +static void setup(void) > +{ > + unsigned int i; > + const char *const fs_opts[] = { "-O quota", NULL}; > + > + quotactl_info(); > + external_fd = SAFE_CREAT("testfile", O_RDONLY); > + > + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); > + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); Why don't we pass the fs_opts in tst_test instead and use .mount_device = 1? Should be as easy as: static struct tst_test test = { ... .dev_fs_opts = (const char *const []){"-O quota", NULL}, .mount_device = 1, ... }; Or is there a reason why this wouldn't work? With the changes outlined in the other email and the minor issues I've pointed out here fixed: Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
Hi Cyril > Hi! >> +/*\ >> + * [Description] >> + * >> + * Tests basic error handling of the quotactl syscall without visible quota files >> + * (use quotactl and quotactl_fd syscall): >> + * >> + * - EFAULT when addr or special is invalid >> + * - EINVAL when cmd or type is invalid >> + * - ENOTBLK when special is not a block device >> + * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range >> + * allowed by the quota format >> + * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for the >> + * specified operation >> + * - EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't >> + * under this moutpoint) >> + * >> + * Minimum e2fsprogs version required is 1.43. >> + */ >> + >> +#include<errno.h> >> +#include<sys/quota.h> >> +#include "tst_test.h" >> +#include "tst_capability.h" >> +#include "quotactl_syscall_var.h" >> + >> +#define OPTION_INVALID 999 >> + >> +static int32_t fmt_id = QFMT_VFS_V1; >> +static int test_id, mount_flag; >> +static int getnextquota_nsup, external_fd = -1; >> + >> +static struct if_nextdqblk res_ndq; >> + >> +static struct dqblk set_dqmax = { >> + .dqb_bsoftlimit = 0x7fffffffffffffffLL, /* 2^63-1 */ >> + .dqb_valid = QIF_BLIMITS >> +}; >> + >> +static struct tst_cap dropadmin = { >> + .action = TST_CAP_DROP, >> + .id = CAP_SYS_ADMIN, >> + .name = "CAP_SYS_ADMIN", >> +}; >> + >> +static 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; >> + int use_external_fd; >> + char *des; >> +} tcases[] = { >> + {QCMD(Q_SETQUOTA, USRQUOTA),&fmt_id, NULL, EFAULT, 1, 0, >> + "EFAULT when addr or special is invalid"}, >> + >> + {QCMD(OPTION_INVALID, USRQUOTA),&fmt_id, NULL, EINVAL, 0, 0, >> + "EINVAL when cmd or type is invalid"}, >> + >> + {QCMD(Q_QUOTAON, USRQUOTA),&fmt_id, NULL, ENOTBLK, 0, 0, >> + "ENOTBLK when special is not a block device"}, >> + >> + {QCMD(Q_SETQUOTA, USRQUOTA),&test_id,&set_dqmax, ERANGE, 1, 0, >> + "ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range"}, >> + >> + {QCMD(Q_QUOTAON, USRQUOTA),&fmt_id, NULL, EPERM, 0, 0, >> + "EPERM when the caller lacked the required privilege for specified operations"}, >> + >> + {QCMD(Q_QUOTAON, USRQUOTA),&fmt_id, NULL, EINVAL, 0, 1, >> + "EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't under " >> + "this mountpoint)"} >> +}; >> + >> +static void verify_quotactl(unsigned int n) >> +{ >> + struct tcase *tc =&tcases[n]; >> + int quota_on = 0; >> + int drop_flag = 0; >> + >> + tst_res(TINFO, "Testing %s", tc->des); >> + if (tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA)&& getnextquota_nsup) { >> + tst_res(TCONF, "current system doesn't support Q_GETNEXTQUOTA"); >> + return; >> + } >> + >> + if (tc->on_flag) { >> + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAON, USRQUOTA), tst_device->dev, >> + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAON, USRQUOTA))"); >> + if (!TST_PASS) >> + return; >> + 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; >> + } >> + } else { >> + if (tc->use_external_fd) { >> + tst_res(TCONF, "quotactl() doesn't use fd, skip"); >> + return; >> + } >> + } >> + if (tc->exp_err == ENOTBLK) >> + TST_EXP_FAIL(do_quotactl(fd, tc->cmd, "/dev/null", *tc->id, tc->addr), >> + ENOTBLK, "do_quotactl()"); >> + else >> + TST_EXP_FAIL(do_quotactl(tc->use_external_fd ? external_fd : fd, tc->cmd, >> + tst_device->dev, *tc->id, tc->addr), tc->exp_err, "do_quotactl()"); >> + >> + if (quota_on) { >> + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev, >> + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAOFF, USRQUOTA)"); >> + if (!TST_PASS) >> + return; >> + quota_on = 0; > > There is no need to clear this flag. Yes, good catch, will also remove this in quotactl06.c. > >> + } >> + >> + if (drop_flag) { >> + tst_cap_action(&needadmin); >> + drop_flag = 0; > > And this flag. > >> + } >> +} >> + >> +static void setup(void) >> +{ >> + unsigned int i; >> + const char *const fs_opts[] = { "-O quota", NULL}; >> + >> + quotactl_info(); >> + external_fd = SAFE_CREAT("testfile", O_RDONLY); >> + >> + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); >> + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); > > Why don't we pass the fs_opts in tst_test instead and use .mount_device = 1? The code is pasted from quotactl06.c there use tst_require_quota_support. Here we don't use it, so we can use .mount_device directly. Best Regards Yang Xu > > Should be as easy as: > > static struct tst_test test = { > ... > .dev_fs_opts = (const char *const []){"-O quota", NULL}, > .mount_device = 1, > ... > }; > > Or is there a reason why this wouldn't work? > > > With the changes outlined in the other email and the minor issues I've > pointed out here fixed: > > Reviewed-by: Cyril Hrubis<chrubis@suse.cz> > >
diff --git a/runtest/syscalls b/runtest/syscalls index a0ca84b36..3b2deb64e 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -1073,6 +1073,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..79f506bdc --- /dev/null +++ b/testcases/kernel/syscalls/quotactl/quotactl09.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * Tests basic error handling of the quotactl syscall without visible quota files + * (use quotactl and quotactl_fd syscall): + * + * - EFAULT when addr or special is invalid + * - EINVAL when cmd or type is invalid + * - ENOTBLK when special is not a block device + * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range + * allowed by the quota format + * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for the + * specified operation + * - EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't + * under this moutpoint) + * + * Minimum e2fsprogs version required is 1.43. + */ + +#include <errno.h> +#include <sys/quota.h> +#include "tst_test.h" +#include "tst_capability.h" +#include "quotactl_syscall_var.h" + +#define OPTION_INVALID 999 + +static int32_t fmt_id = QFMT_VFS_V1; +static int test_id, mount_flag; +static int getnextquota_nsup, external_fd = -1; + +static struct if_nextdqblk res_ndq; + +static struct dqblk set_dqmax = { + .dqb_bsoftlimit = 0x7fffffffffffffffLL, /* 2^63-1 */ + .dqb_valid = QIF_BLIMITS +}; + +static struct tst_cap dropadmin = { + .action = TST_CAP_DROP, + .id = CAP_SYS_ADMIN, + .name = "CAP_SYS_ADMIN", +}; + +static 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; + int use_external_fd; + char *des; +} tcases[] = { + {QCMD(Q_SETQUOTA, USRQUOTA), &fmt_id, NULL, EFAULT, 1, 0, + "EFAULT when addr or special is invalid"}, + + {QCMD(OPTION_INVALID, USRQUOTA), &fmt_id, NULL, EINVAL, 0, 0, + "EINVAL when cmd or type is invalid"}, + + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, ENOTBLK, 0, 0, + "ENOTBLK when special is not a block device"}, + + {QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dqmax, ERANGE, 1, 0, + "ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range"}, + + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EPERM, 0, 0, + "EPERM when the caller lacked the required privilege for specified operations"}, + + {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, NULL, EINVAL, 0, 1, + "EINVAL when cmd is Q_QUOTAON, but the fd refers to a regular file(doesn't under " + "this mountpoint)"} +}; + +static void verify_quotactl(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int quota_on = 0; + int drop_flag = 0; + + tst_res(TINFO, "Testing %s", tc->des); + if (tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA) && getnextquota_nsup) { + tst_res(TCONF, "current system doesn't support Q_GETNEXTQUOTA"); + return; + } + + if (tc->on_flag) { + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAON, USRQUOTA), tst_device->dev, + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAON, USRQUOTA))"); + if (!TST_PASS) + return; + 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; + } + } else { + if (tc->use_external_fd) { + tst_res(TCONF, "quotactl() doesn't use fd, skip"); + return; + } + } + if (tc->exp_err == ENOTBLK) + TST_EXP_FAIL(do_quotactl(fd, tc->cmd, "/dev/null", *tc->id, tc->addr), + ENOTBLK, "do_quotactl()"); + else + TST_EXP_FAIL(do_quotactl(tc->use_external_fd ? external_fd : fd, tc->cmd, + tst_device->dev, *tc->id, tc->addr), tc->exp_err, "do_quotactl()"); + + if (quota_on) { + TST_EXP_PASS_SILENT(do_quotactl(fd, QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev, + fmt_id, NULL), "do_quotactl(QCMD(Q_QUOTAOFF, USRQUOTA)"); + if (!TST_PASS) + return; + quota_on = 0; + } + + if (drop_flag) { + tst_cap_action(&needadmin); + drop_flag = 0; + } +} + +static void setup(void) +{ + unsigned int i; + const char *const fs_opts[] = { "-O quota", NULL}; + + quotactl_info(); + external_fd = SAFE_CREAT("testfile", O_RDONLY); + + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); + mount_flag = 1; + + fd = SAFE_OPEN(MNTPOINT, O_RDONLY); + 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); + if (external_fd > -1) + SAFE_CLOSE(external_fd); + if (mount_flag && tst_umount(MNTPOINT)) + tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); +} + +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, + .needs_device = 1, + .needs_root = 1, + .test_variants = QUOTACTL_SYSCALL_VARIANTS, + .needs_cmds = (const char *[]) { + "mkfs.ext4 >= 1.43.0", + NULL + } +};
This case is similar to quotactl06 but only some differences 1) use quotactl and quotactl_fd syscalls without visible quota file 2) remove some error for addr argument 3) test external_fd for quotactl_fd for EINVAL error when using Q_QUOTAON 4) add error case description when running Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com> --- runtest/syscalls | 1 + testcases/kernel/syscalls/quotactl/.gitignore | 1 + .../kernel/syscalls/quotactl/quotactl09.c | 195 ++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 testcases/kernel/syscalls/quotactl/quotactl09.c