| /* |
| * Copyright (c) 2013 Fujitsu Ltd. |
| * Author: DAN LI <li.dan@cn.fujitsu.com> |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| /* |
| * Test Name: quotactl02 |
| * |
| * Description: |
| * This testcase checks basic flags of quotactl(2) for an XFS file system: |
| * 1) quotactl(2) succeeds to turn off xfs quota and get xfs quota off status. |
| * 2) quotactl(2) succeeds to turn on xfs quota and get xfs quota on status. |
| * 3) quotactl(2) succeeds to set and use Q_XGETQUOTA to get xfs disk quota |
| * limits. |
| * 4) quotactl(2) succeeds to set and use Q_XGETNEXTQUOTA to get xfs disk |
| * quota limits. |
| */ |
| #define _GNU_SOURCE |
| #include <errno.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <sys/quota.h> |
| #include "config.h" |
| |
| #if defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1) |
| # include <sys/quota.h> |
| #endif |
| |
| #if defined(HAVE_XFS_QUOTA) |
| # include <xfs/xqm.h> |
| #endif |
| |
| #include "tst_test.h" |
| #include "lapi/quotactl.h" |
| |
| #if defined(HAVE_XFS_QUOTA) && (defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1)) |
| static void check_qoff(int, char *); |
| static void check_qon(int, char *); |
| static void check_qlim(int, char *); |
| |
| static uint32_t test_id; |
| static struct fs_disk_quota set_dquota = { |
| .d_rtb_softlimit = 1000, |
| .d_fieldmask = FS_DQ_RTBSOFT |
| }; |
| static uint32_t qflag = XFS_QUOTA_UDQ_ENFD; |
| static const char mntpoint[] = "mnt_point"; |
| |
| static struct t_case { |
| int cmd; |
| void *addr; |
| void (*func_check)(); |
| int check_subcmd; |
| char *des; |
| } tcases[] = { |
| {QCMD(Q_XQUOTAOFF, USRQUOTA), &qflag, check_qoff, Q_XGETQSTAT, |
| "turn off xfs quota and get xfs quota off status"}, |
| {QCMD(Q_XQUOTAON, USRQUOTA), &qflag, check_qon, Q_XGETQSTAT, |
| "turn on xfs quota and get xfs quota on status"}, |
| {QCMD(Q_XSETQLIM, USRQUOTA), &set_dquota, check_qlim, Q_XGETQUOTA, |
| "Q_XGETQUOTA"}, |
| {QCMD(Q_XSETQLIM, USRQUOTA), &set_dquota, check_qlim, Q_XGETNEXTQUOTA, |
| "Q_XGETNEXTQUOTA"}, |
| }; |
| |
| static void check_qoff(int subcmd, char *desp) |
| { |
| int res; |
| struct fs_quota_stat res_qstat; |
| |
| res = quotactl(QCMD(subcmd, USRQUOTA), tst_device->dev, |
| test_id, (void*) &res_qstat); |
| if (res == -1) { |
| tst_res(TFAIL | TERRNO, |
| "quotactl() failed to get xfs quota off status"); |
| return; |
| } |
| |
| if (res_qstat.qs_flags & XFS_QUOTA_UDQ_ENFD) { |
| tst_res(TFAIL, "xfs quota enforcement was on unexpectedly"); |
| return; |
| } |
| |
| tst_res(TPASS, "quoactl() succeeded to %s", desp); |
| } |
| |
| static void check_qon(int subcmd, char *desp) |
| { |
| int res; |
| struct fs_quota_stat res_qstat; |
| |
| res = quotactl(QCMD(subcmd, USRQUOTA), tst_device->dev, |
| test_id, (void*) &res_qstat); |
| if (res == -1) { |
| tst_res(TFAIL | TERRNO, |
| "quotactl() failed to get xfs quota on status"); |
| return; |
| } |
| |
| if (!(res_qstat.qs_flags & XFS_QUOTA_UDQ_ENFD)) { |
| tst_res(TFAIL, "xfs quota enforcement was off unexpectedly"); |
| return; |
| } |
| |
| tst_res(TPASS, "quoactl() succeeded to %s", desp); |
| } |
| |
| static void check_qlim(int subcmd, char *desp) |
| { |
| int res; |
| static struct fs_disk_quota res_dquota; |
| |
| res_dquota.d_rtb_softlimit = 0; |
| |
| res = quotactl(QCMD(subcmd, USRQUOTA), tst_device->dev, |
| test_id, (void*) &res_dquota); |
| if (res == -1) { |
| if (errno == EINVAL) { |
| tst_brk(TCONF | TERRNO, |
| "%s wasn't supported in quotactl()", desp); |
| } |
| tst_res(TFAIL | TERRNO, |
| "quotactl() failed to get xfs disk quota limits"); |
| return; |
| } |
| |
| if (res_dquota.d_id != test_id) { |
| tst_res(TFAIL, "quotactl() got unexpected user id %u," |
| " expected %u", res_dquota.d_id, test_id); |
| return; |
| } |
| |
| if (res_dquota.d_rtb_hardlimit != set_dquota.d_rtb_hardlimit) { |
| tst_res(TFAIL, "quotactl() got unexpected rtb soft limit %llu," |
| " expected %llu", res_dquota.d_rtb_hardlimit, |
| set_dquota.d_rtb_hardlimit); |
| return; |
| } |
| |
| tst_res(TPASS, "quoactl() succeeded to set and use %s to get xfs disk " |
| "quota limits", desp); |
| } |
| |
| static void setup(void) |
| { |
| test_id = geteuid(); |
| } |
| |
| static void verify_quota(unsigned int n) |
| { |
| struct t_case *tc = &tcases[n]; |
| |
| TEST(quotactl(tc->cmd, tst_device->dev, test_id, tc->addr)); |
| if (TEST_RETURN == -1) { |
| tst_res(TFAIL | TTERRNO, "quotactl() failed to %s", tc->des); |
| return; |
| } |
| |
| tc->func_check(tc->check_subcmd, tc->des); |
| } |
| |
| static struct tst_test test = { |
| .tid = "quotactl02", |
| .needs_tmpdir = 1, |
| .needs_root = 1, |
| .test = verify_quota, |
| .tcnt = ARRAY_SIZE(tcases), |
| .mount_device = 1, |
| .dev_fs_type = "xfs", |
| .mntpoint = mntpoint, |
| .mnt_data = "usrquota", |
| .setup = setup, |
| }; |
| #else |
| TST_TEST_TCONF("This system didn't support quota or xfs quota"); |
| #endif |