Fix io_uring tests (#12134)

* io_uring: fix the timeout_remove test

The test does a IORING_OP_TIMEOUT followed with a IORING_OP_TIMEOUT_REMOVE
and assumed we would get the CQEs in the same order.

Linux v5.18 changed how this works and we now get them in the reverse order.

The documentation doesn't explicitly say which CQE we should get first
so just make the test work with both cases.

* io_uring: fix the remove_buffers test

The original test was buggy but accidentally worked with kernels < 5.18

The test assumed that IORING_OP_REMOVE_BUFFERS removed from the start of
but in fact the documentation doesn't specify which buffer is removed,
only that a certain number of buffers are removed.

Starting with the kernel 5.18 the check for the `used_buffer_id` fails.
Turns out that previous kernels removed buffers in such a way that the
remaining buffer for this read would always be 0, however this isn't
true anymore.

Instead of checking a specific value just check that the `used_buffer_id`
corresponds to a valid ID.
This commit is contained in:
Vincent Rischmann 2022-07-16 17:05:11 +02:00 committed by GitHub
parent 9c66fdadc7
commit 47c58cba59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2181,29 +2181,41 @@ test "timeout_remove" {
try testing.expectEqual(@as(u32, 2), try ring.submit());
const cqe_timeout = try ring.copy_cqe();
// IORING_OP_TIMEOUT_REMOVE is not supported by this kernel version:
// Timeout remove operations set the fd to -1, which results in EBADF before EINVAL.
// We use IORING_FEAT_RW_CUR_POS as a safety check here to make sure we are at least pre-5.6.
// We don't want to skip this test for newer kernels.
if (cqe_timeout.user_data == 0x99999999 and
cqe_timeout.err() == .BADF and
(ring.features & linux.IORING_FEAT_RW_CUR_POS) == 0)
{
return error.SkipZigTest;
}
try testing.expectEqual(linux.io_uring_cqe{
.user_data = 0x88888888,
.res = -@as(i32, @enumToInt(linux.E.CANCELED)),
.flags = 0,
}, cqe_timeout);
// The order in which the CQE arrive is not clearly documented and it changed with kernel 5.18:
// * kernel 5.10 gives user data 0x88888888 first, 0x99999999 second
// * kernel 5.18 gives user data 0x99999999 first, 0x88888888 second
const cqe_timeout_remove = try ring.copy_cqe();
try testing.expectEqual(linux.io_uring_cqe{
.user_data = 0x99999999,
.res = 0,
.flags = 0,
}, cqe_timeout_remove);
var cqes: [2]os.linux.io_uring_cqe = undefined;
try testing.expectEqual(@as(u32, 2), try ring.copy_cqes(cqes[0..], 2));
for (cqes) |cqe| {
// IORING_OP_TIMEOUT_REMOVE is not supported by this kernel version:
// Timeout remove operations set the fd to -1, which results in EBADF before EINVAL.
// We use IORING_FEAT_RW_CUR_POS as a safety check here to make sure we are at least pre-5.6.
// We don't want to skip this test for newer kernels.
if (cqe.user_data == 0x99999999 and
cqe.err() == .BADF and
(ring.features & linux.IORING_FEAT_RW_CUR_POS) == 0)
{
return error.SkipZigTest;
}
try testing.expect(cqe.user_data == 0x88888888 or cqe.user_data == 0x99999999);
if (cqe.user_data == 0x88888888) {
try testing.expectEqual(linux.io_uring_cqe{
.user_data = 0x88888888,
.res = -@as(i32, @enumToInt(linux.E.CANCELED)),
.flags = 0,
}, cqe);
} else if (cqe.user_data == 0x99999999) {
try testing.expectEqual(linux.io_uring_cqe{
.user_data = 0x99999999,
.res = 0,
.flags = 0,
}, cqe);
}
}
}
test "accept/connect/recv/link_timeout" {
@ -2989,7 +3001,7 @@ test "remove_buffers" {
try testing.expectEqual(@as(u64, 0xcccccccc), cqe.user_data);
}
// Remove the first 3 buffers
// Remove 3 buffers
{
var sqe = try ring.remove_buffers(0xbababababa, 3, group_id);
@ -3021,7 +3033,7 @@ test "remove_buffers" {
try testing.expect(cqe.flags & linux.IORING_CQE_F_BUFFER == linux.IORING_CQE_F_BUFFER);
const used_buffer_id = cqe.flags >> 16;
try testing.expectEqual(used_buffer_id, 0);
try testing.expect(used_buffer_id >= 0 and used_buffer_id < 4);
try testing.expectEqual(@as(i32, buffer_len), cqe.res);
try testing.expectEqual(@as(u64, 0xdfdfdfdf), cqe.user_data);
try testing.expectEqualSlices(u8, &([_]u8{0} ** buffer_len), buffers[used_buffer_id][0..@intCast(usize, cqe.res)]);