1 /*
2 * Copyright (c) 2017 Fujitsu Ltd.
3 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program, if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * Test Name: quotactl03
21 *
22 * Description:
23 * quotactl(2) with XGETNEXTQUOTA looks for the next active quota for an user
24 * equal or higher to a given ID, in this test the ID is specified to a value
25 * close to UINT_MAX(max value of unsigned int). When reaching the upper limit
26 * and finding no active quota, it should return -1 and set errno to ENOENT.
27 * Actually, quotactl(2) overflows and and return 0 as the "next" active id.
28 *
29 * This kernel bug of xfs has been fixed in:
30 *
31 * commit 657bdfb7f5e68ca5e2ed009ab473c429b0d6af85
32 * Author: Eric Sandeen <sandeen@redhat.com>
33 * Date: Tue Jan 17 11:43:38 2017 -0800
34 *
35 * xfs: don't wrap ID in xfs_dq_get_next_id
36 */
37
38 #define _GNU_SOURCE
39 #include <errno.h>
40 #include <unistd.h>
41 #include <stdio.h>
42 #include <sys/quota.h>
43 #include "config.h"
44
45 #if defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1)
46 # include <sys/quota.h>
47 #endif
48
49 #if defined(HAVE_XFS_QUOTA)
50 # include <xfs/xqm.h>
51 #endif
52
53 #include "tst_test.h"
54 #include "lapi/quotactl.h"
55
56 #if defined(HAVE_XFS_QUOTA) && (defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1))
57
58 static const char mntpoint[] = "mnt_point";
59 static uint32_t test_id = 0xfffffffc;
60
verify_quota(void)61 static void verify_quota(void)
62 {
63 struct fs_disk_quota res_dquota;
64
65 res_dquota.d_id = 1;
66
67 TEST(quotactl(QCMD(Q_XGETNEXTQUOTA, USRQUOTA), tst_device->dev,
68 test_id, (void *)&res_dquota));
69 if (TST_RET != -1) {
70 tst_res(TFAIL, "quotactl() found the next active ID:"
71 " %u unexpectedly", res_dquota.d_id);
72 return;
73 }
74
75 if (TST_ERR == EINVAL) {
76 tst_brk(TCONF | TTERRNO,
77 "Q_XGETNEXTQUOTA wasn't supported in quotactl()");
78 }
79
80 if (TST_ERR != ENOENT) {
81 tst_res(TFAIL | TTERRNO, "quotactl() failed unexpectedly with"
82 " %s expected ENOENT", tst_strerrno(TST_ERR));
83 } else {
84 tst_res(TPASS, "quotactl() failed with ENOENT as expected");
85 }
86 }
87
88 static struct tst_test test = {
89 .needs_tmpdir = 1,
90 .needs_root = 1,
91 .test_all = verify_quota,
92 .mount_device = 1,
93 .dev_fs_type = "xfs",
94 .mntpoint = mntpoint,
95 .mnt_data = "usrquota",
96 };
97
98 #else
99 TST_TEST_TCONF("This system didn't support quota or xfs quota");
100 #endif
101