xfs: fix sign handling problem in xfs_bmbt_diff_two_keys
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 27 Aug 2019 00:06:02 +0000 (17:06 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 28 Aug 2019 15:31:01 +0000 (08:31 -0700)
In xfs_bmbt_diff_two_keys, we perform a signed int64_t subtraction with
two unsigned 64-bit quantities.  If the second quantity is actually the
"maximum" key (all ones) as used in _query_all, the subtraction
effectively becomes addition of two positive numbers and the function
returns incorrect results.  Fix this with explicit comparisons of the
unsigned values.  Nobody needs this now, but the online repair patches
will need this to work properly.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/libxfs/xfs_bmap_btree.c

index fbb18ba5d90538af2a34361981248e0a16278d7c..ffe608d2a2d9cae5143c6c7cc4bde2a4e5f2b1f9 100644 (file)
@@ -400,8 +400,20 @@ xfs_bmbt_diff_two_keys(
        union xfs_btree_key     *k1,
        union xfs_btree_key     *k2)
 {
-       return (int64_t)be64_to_cpu(k1->bmbt.br_startoff) -
-                         be64_to_cpu(k2->bmbt.br_startoff);
+       uint64_t                a = be64_to_cpu(k1->bmbt.br_startoff);
+       uint64_t                b = be64_to_cpu(k2->bmbt.br_startoff);
+
+       /*
+        * Note: This routine previously casted a and b to int64 and subtracted
+        * them to generate a result.  This lead to problems if b was the
+        * "maximum" key value (all ones) being signed incorrectly, hence this
+        * somewhat less efficient version.
+        */
+       if (a > b)
+               return 1;
+       if (b > a)
+               return -1;
+       return 0;
 }
 
 static xfs_failaddr_t