1 /*
2 * Copyright (c) 2013 Fujitsu Ltd.
3 * Author: DAN LI <li.dan@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 /*
19 * Test Name: quotactl02
20 *
21 * Description:
22 * This testcase checks basic flags of quotactl(2) for an XFS file system:
23 * 1) quotactl(2) succeeds to turn off xfs quota and get xfs quota off status.
24 * 2) quotactl(2) succeeds to turn on xfs quota and get xfs quota on status.
25 * 3) quotactl(2) succeeds to set and use Q_XGETQUOTA to get xfs disk quota
26 * limits.
27 * 4) quotactl(2) succeeds to set and use Q_XGETNEXTQUOTA to get xfs disk
28 * quota limits.
29 */
30 #define _GNU_SOURCE
31 #include <errno.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <sys/quota.h>
35 #include "config.h"
36
37 #if defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1)
38 # include <sys/quota.h>
39 #endif
40
41 #if defined(HAVE_XFS_QUOTA)
42 # include <xfs/xqm.h>
43 #endif
44
45 #include "tst_test.h"
46 #include "lapi/quotactl.h"
47
48 #if defined(HAVE_XFS_QUOTA) && (defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1))
49 static void check_qoff(int, char *);
50 static void check_qon(int, char *);
51 static void check_qlim(int, char *);
52
53 static uint32_t test_id;
54 static struct fs_disk_quota set_dquota = {
55 .d_rtb_softlimit = 1000,
56 .d_fieldmask = FS_DQ_RTBSOFT
57 };
58 static uint32_t qflag = XFS_QUOTA_UDQ_ENFD;
59 static const char mntpoint[] = "mnt_point";
60
61 static struct t_case {
62 int cmd;
63 void *addr;
64 void (*func_check)();
65 int check_subcmd;
66 char *des;
67 } tcases[] = {
68 {QCMD(Q_XQUOTAOFF, USRQUOTA), &qflag, check_qoff, Q_XGETQSTAT,
69 "turn off xfs quota and get xfs quota off status"},
70 {QCMD(Q_XQUOTAON, USRQUOTA), &qflag, check_qon, Q_XGETQSTAT,
71 "turn on xfs quota and get xfs quota on status"},
72 {QCMD(Q_XSETQLIM, USRQUOTA), &set_dquota, check_qlim, Q_XGETQUOTA,
73 "Q_XGETQUOTA"},
74 {QCMD(Q_XSETQLIM, USRQUOTA), &set_dquota, check_qlim, Q_XGETNEXTQUOTA,
75 "Q_XGETNEXTQUOTA"},
76 };
77
check_qoff(int subcmd,char * desp)78 static void check_qoff(int subcmd, char *desp)
79 {
80 int res;
81 struct fs_quota_stat res_qstat;
82
83 res = quotactl(QCMD(subcmd, USRQUOTA), tst_device->dev,
84 test_id, (void*) &res_qstat);
85 if (res == -1) {
86 tst_res(TFAIL | TERRNO,
87 "quotactl() failed to get xfs quota off status");
88 return;
89 }
90
91 if (res_qstat.qs_flags & XFS_QUOTA_UDQ_ENFD) {
92 tst_res(TFAIL, "xfs quota enforcement was on unexpectedly");
93 return;
94 }
95
96 tst_res(TPASS, "quoactl() succeeded to %s", desp);
97 }
98
check_qon(int subcmd,char * desp)99 static void check_qon(int subcmd, char *desp)
100 {
101 int res;
102 struct fs_quota_stat res_qstat;
103
104 res = quotactl(QCMD(subcmd, USRQUOTA), tst_device->dev,
105 test_id, (void*) &res_qstat);
106 if (res == -1) {
107 tst_res(TFAIL | TERRNO,
108 "quotactl() failed to get xfs quota on status");
109 return;
110 }
111
112 if (!(res_qstat.qs_flags & XFS_QUOTA_UDQ_ENFD)) {
113 tst_res(TFAIL, "xfs quota enforcement was off unexpectedly");
114 return;
115 }
116
117 tst_res(TPASS, "quoactl() succeeded to %s", desp);
118 }
119
check_qlim(int subcmd,char * desp)120 static void check_qlim(int subcmd, char *desp)
121 {
122 int res;
123 static struct fs_disk_quota res_dquota;
124
125 res_dquota.d_rtb_softlimit = 0;
126
127 res = quotactl(QCMD(subcmd, USRQUOTA), tst_device->dev,
128 test_id, (void*) &res_dquota);
129 if (res == -1) {
130 if (errno == EINVAL) {
131 tst_brk(TCONF | TERRNO,
132 "%s wasn't supported in quotactl()", desp);
133 }
134 tst_res(TFAIL | TERRNO,
135 "quotactl() failed to get xfs disk quota limits");
136 return;
137 }
138
139 if (res_dquota.d_id != test_id) {
140 tst_res(TFAIL, "quotactl() got unexpected user id %u,"
141 " expected %u", res_dquota.d_id, test_id);
142 return;
143 }
144
145 if (res_dquota.d_rtb_hardlimit != set_dquota.d_rtb_hardlimit) {
146 tst_res(TFAIL, "quotactl() got unexpected rtb soft limit %llu,"
147 " expected %llu", res_dquota.d_rtb_hardlimit,
148 set_dquota.d_rtb_hardlimit);
149 return;
150 }
151
152 tst_res(TPASS, "quoactl() succeeded to set and use %s to get xfs disk "
153 "quota limits", desp);
154 }
155
setup(void)156 static void setup(void)
157 {
158 test_id = geteuid();
159 }
160
verify_quota(unsigned int n)161 static void verify_quota(unsigned int n)
162 {
163 struct t_case *tc = &tcases[n];
164
165 TEST(quotactl(tc->cmd, tst_device->dev, test_id, tc->addr));
166 if (TST_RET == -1) {
167 tst_res(TFAIL | TTERRNO, "quotactl() failed to %s", tc->des);
168 return;
169 }
170
171 tc->func_check(tc->check_subcmd, tc->des);
172 }
173
174 static struct tst_test test = {
175 .needs_tmpdir = 1,
176 .needs_root = 1,
177 .test = verify_quota,
178 .tcnt = ARRAY_SIZE(tcases),
179 .mount_device = 1,
180 .dev_fs_type = "xfs",
181 .mntpoint = mntpoint,
182 .mnt_data = "usrquota",
183 .setup = setup,
184 };
185 #else
186 TST_TEST_TCONF("This system didn't support quota or xfs quota");
187 #endif
188