On 03/09/2026 23:00, Thadeu Lima de Souza Cascardo wrote:
From: Thomas Hellström <[email protected]>
Add write_eviction_nonblock to exercise the O_NONBLOCK path of the dmem
cgroup max interface. After filling VRAM to the cgroup limit, each
limit-lowering step writes dmem.max with O_NONBLOCK so that synchronous
eviction is skipped. The test then verifies that usage has not yet
dropped below the new limit, allocates a small BO to trigger eviction
explicitly, and finally confirms that usage falls within bounds.
Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <[email protected]>
Signed-off-by: Thadeu Lima de Souza Cascardo <[email protected]>
---
tests/cgroup_dmem.c | 37 ++++++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/tests/cgroup_dmem.c b/tests/cgroup_dmem.c
index 0d3b415acd54..ee6345c17878 100644
--- a/tests/cgroup_dmem.c
+++ b/tests/cgroup_dmem.c
@@ -41,6 +41,7 @@
#define USAGE_DROP_TIMEOUT_MS 1000
#define TEST_INTERRUPTIBLE (1 << 0)
+#define TEST_NONBLOCK (1 << 1)
/**
* SUBTEST: simple
@@ -90,6 +91,18 @@
* REQUIREMENTS: must run as root; xe device with at least one VRAM region
*/
+/**
+ * SUBTEST: write_eviction_nonblock
+ * DESCRIPTION:
+ * Same fill phase as write_eviction. In the limit-lowering phase dmem.max
+ * is written with O_NONBLOCK, which causes the kernel to skip synchronous
+ * eviction. After each nonblock write the test verifies that usage has not
+ * yet dropped below the new limit, then triggers eviction explicitly by
+ * allocating a small BO. Finally verifies that usage falls within bounds
+ * after the forced eviction.
+ * REQUIREMENTS: must run as root; xe device with at least one VRAM region
+ */
+
static atomic_int signal_count;
static struct sigaction sigcont_oldact;
@@ -277,7 +290,7 @@ static void test_write_eviction(int fd, char *cg_region, unsigned int flags, con
struct igt_cgroup *cg;
void **handles;
int max_bo;
- uint64_t current, capacity, cg_max, limit, after;
+ uint64_t current, capacity, cg_max, limit, after, before;
int err;
igt_cgroup_dmem_get_capacity(cg_region, &capacity);
@@ -322,14 +335,31 @@ static void test_write_eviction(int fd, char *cg_region,
unsigned int flags, con
while (limit >= EVICT_STEP) {
limit -= EVICT_STEP;
- igt_cgroup_dmem_set_max(cg, cg_region, limit, false);
+
+ if (flags & TEST_NONBLOCK)
+ igt_cgroup_dmem_get_current(cg, cg_region, &before);
+
+ igt_cgroup_dmem_set_max(cg, cg_region, limit,
+ !!(flags & TEST_NONBLOCK));
igt_cgroup_dmem_get_current(cg, cg_region, &after);
igt_debug("Lowered max to %"PRIu64" MiB: usage = %"PRIu64"
MiB\n",
limit / SZ_1M, after / SZ_1M);
+ if (flags & TEST_NONBLOCK) {
+ /*
+ * O_NONBLOCK skips eviction: verify usage has not
+ * dropped below the new limit yet.
+ */
Is this userspace ABI contract or happens to be? It feels odd - even if
we ask for non block for the write why would kernel not be allowed to do
stuff behind the covers?
Regards,
Tvrtko
+ igt_assert_f(after == before,
+ "Expected no eviction with O_NONBLOCK, but
"
+ "usage dropped from %"PRIu64" MiB to %"PRIu64"
MiB "
+ "(limit %"PRIu64" MiB)\n",
+ before / SZ_1M, after / SZ_1M, limit /
SZ_1M);
+ }
+
if (limit > EVICT_STEP) {
- if ((flags & TEST_INTERRUPTIBLE) && after > limit) {
+ if ((flags & (TEST_INTERRUPTIBLE | TEST_NONBLOCK)) &&
after > limit) {
/* Let a new bo creation trigger eviction. */
void *handle;
err = drv->allocate_vram(ctx, BO_SIZE / 8,
&handle);
@@ -368,6 +398,7 @@ static const struct {
{ "current", test_current, 0 },
{ "write_eviction", test_write_eviction, 0 },
{ "write_eviction_interruptible", test_write_eviction,
TEST_INTERRUPTIBLE },
+ { "write_eviction_nonblock", test_write_eviction, TEST_NONBLOCK },
{ }
};