diff mbox

[V2] generic/395: test GETNEXTQUOTA near INT_MAX

Message ID 8c91051e-8a78-cb20-d926-ea86e5b4645a@sandeen.net (mailing list archive)
State New, archived
Headers show

Commit Message

Eric Sandeen Dec. 22, 2016, 1:11 a.m. UTC
XFS kernel code had a bug where GETNEXTQUOTA-type
quotactls requesting an ID near UINT_MAX could overflow
and return 0 as the "next" active ID.

This test checks that by creating an active quota near
UINT_MAX, then asking for the next one after it.

The proper answer is ENOENT, but if we wrap we'll return
ID 0.

This also changes test-nextquota.c so that it checks
both GETNEXTQUOTA and XGETNEXTQUOTA even if one fails;
it stores the failure conditions and returns 1 if either
of them fails.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

V2: cleanups from Eryu's review.

Eryu - I need to send a _require_getnextquota patch, and some
other cleanups to 244, similar to your review of this test
(I copied this test from 244).

I'll do that in reply to this patch, hopfully tonight, yet.


--
To unsubscribe from this list: send the line "unsubscribe fstests" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Eryu Guan Dec. 24, 2016, 10:20 a.m. UTC | #1
On Wed, Dec 21, 2016 at 07:11:21PM -0600, Eric Sandeen wrote:
> XFS kernel code had a bug where GETNEXTQUOTA-type
> quotactls requesting an ID near UINT_MAX could overflow
> and return 0 as the "next" active ID.
> 
> This test checks that by creating an active quota near
> UINT_MAX, then asking for the next one after it.
> 
> The proper answer is ENOENT, but if we wrap we'll return
> ID 0.
> 
> This also changes test-nextquota.c so that it checks
> both GETNEXTQUOTA and XGETNEXTQUOTA even if one fails;
> it stores the failure conditions and returns 1 if either
> of them fails.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
> 
> V2: cleanups from Eryu's review.
> 
> Eryu - I need to send a _require_getnextquota patch, and some
> other cleanups to 244, similar to your review of this test
> (I copied this test from 244).
> 
> I'll do that in reply to this patch, hopfully tonight, yet.

Thanks, Eric!

> +# remount just for kicks, make sure we get it off disk
> +_scratch_unmount
> +_qmount
> +quotaon $SCRATCH_MNT 2>/dev/null

I removed this quotaon too and merged.

Thanks,
Eryu
--
To unsubscribe from this list: send the line "unsubscribe fstests" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/test-nextquota.c b/src/test-nextquota.c
index ba4de27..73c63d8 100644
--- a/src/test-nextquota.c
+++ b/src/test-nextquota.c
@@ -73,6 +73,7 @@  int main(int argc, char *argv[])
 	int cmd;
 	int type = -1, typeflag = 0;
 	int verbose = 0;
+	int retval = 0;
 	uint id = 0, idflag = 0;
 	char *device = NULL;
 	char *tmp;
@@ -140,30 +141,32 @@  int main(int argc, char *argv[])
 	cmd = QCMD(Q_GETNEXTQUOTA, type);
 	if (quotactl(cmd, device, id, (void *)&dqb) < 0) {
 		perror("Q_GETNEXTQUOTA");
-		return 1;
+		retval = 1;
+	} else {
+		/*
+		 * We only print id and inode limits because
+		 * block count varies depending on fs block size, etc;
+		 * this is just a sanity test that we can retrieve the quota,
+		 * and inode limits have the same units across both calls.
+		 */
+		printf("id        %u\n", dqb.dqb_id);
+		printf("ihard     %llu\n",
+				  (unsigned long long)dqb.dqb_ihardlimit);
+		printf("isoft     %llu\n",
+				  (unsigned long long)dqb.dqb_isoftlimit);
 	}
 
-	/*
-	 * We only print id and inode limits because
-	 * block count varies depending on fs block size, etc;
-	 * this is just a sanity test that we can retrieve the quota,
-	 * and inode limits have the same units across both calls.
-	 */
-	printf("id        %u\n", dqb.dqb_id);
-	printf("ihard     %llu\n", (unsigned long long)dqb.dqb_ihardlimit);
-	printf("isoft     %llu\n", (unsigned long long)dqb.dqb_isoftlimit);
-
 	if (verbose)
 		printf("====Q_XGETNEXTQUOTA====\n");
 	cmd = QCMD(Q_XGETNEXTQUOTA, USRQUOTA);
 	if (quotactl(cmd, device, id, (void *)&xqb) < 0) {
 		perror("Q_XGETNEXTQUOTA");
-		return 1;
+		retval = 1;
+	} else {
+		printf("id        %u\n", xqb.d_id);
+		printf("ihard     %llu\n", xqb.d_ino_hardlimit);
+		printf("isoft     %llu\n", xqb.d_ino_softlimit);
 	}
 
-	printf("id        %u\n", xqb.d_id);
-	printf("ihard     %llu\n", xqb.d_ino_hardlimit);
-	printf("isoft     %llu\n", xqb.d_ino_softlimit);
-
-	return 0;
+	return retval;
 }

diff --git a/tests/generic/395 b/tests/generic/395
new file mode 100755
index 0000000..cc4a93e
--- /dev/null
+++ b/tests/generic/395
@@ -0,0 +1,94 @@ 
+#! /bin/bash
+# FS QA Test 394
+#
+# test out high quota ids retrieved by Q_GETNEXTQUOTA
+# Request for next ID near 2^32 should not wrap to 0
+#
+# Designed to use the new Q_GETNEXTQUOTA quotactl
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Red Hat, Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms 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.  See the
+# GNU General Public License for more details.
+#
+# 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/quota
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs generic
+_supported_os Linux
+_require_quota
+_require_scratch
+
+_scratch_mkfs >> $seqres.full 2>&1
+
+MOUNT_OPTIONS="-o usrquota,grpquota"
+
+_qmount
+
+# Ok, do we even have GETNEXTQUOTA?  Querying ID 0 should work.
+$here/src/test-nextquota -i 0 -u -d $SCRATCH_DEV &> $seqres.full || \
+	_notrun "No GETNEXTQUOTA support"
+
+echo "Launch all quotas"
+
+# We want to create a block of quotas for an id very near
+# 2^32, then ask for the next quota after it.  The returned
+# ID should not overflow to 0.
+
+# Populate  with 2^32-4
+ID=4294967292
+setquota -u $ID $ID $ID $ID $ID $SCRATCH_MNT
+touch ${SCRATCH_MNT}/${ID}
+chown ${ID} ${SCRATCH_MNT}/${ID}
+
+# remount just for kicks, make sure we get it off disk
+_scratch_unmount
+_qmount
+quotaon $SCRATCH_MNT 2>/dev/null
+
+# Ask for the next quota after $ID; should get nothing back
+# If kernelspace wraps, we'll get 0 back.
+for TYPE in u g; do
+	let NEXT=ID+1
+	echo "Ask for ID after $NEXT expecting nothing"
+	$here/src/test-nextquota -i $NEXT -${TYPE} -d $SCRATCH_DEV
+done
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/395.out b/tests/generic/395.out
new file mode 100644
index 0000000..bcd87ec
--- /dev/null
+++ b/tests/generic/395.out
@@ -0,0 +1,8 @@ 
+QA output created by 395
+Launch all quotas
+Ask for ID after 4294967293 expecting nothing
+Q_GETNEXTQUOTA: No such file or directory
+Q_XGETNEXTQUOTA: No such file or directory
+Ask for ID after 4294967293 expecting nothing
+Q_GETNEXTQUOTA: No such file or directory
+Q_XGETNEXTQUOTA: No such file or directory
diff --git a/tests/generic/group b/tests/generic/group
index 20b31ef..e9d3e4a 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -397,3 +397,4 @@ 
 392 auto quick metadata
 393 auto quick rw
 394 auto quick
+395 auto quick quota