From: Maciej Patelczyk <maciej.patelczyk@intel.com>
To: Jan Maslak <jan.maslak@intel.com>, <igt-dev@lists.freedesktop.org>
Subject: Re: [PATCH 1/1] tests/intel/xe_eudebug: Add basic-vm-bind-ufence-no-ack test
Date: Thu, 7 May 2026 10:52:53 +0200 [thread overview]
Message-ID: <24aa9483-a6a9-46e2-b5e6-0a775ab6cc34@intel.com> (raw)
In-Reply-To: <20260227142638.3264013-2-jan.maslak@intel.com>
On 27/02/2026 15:26, Jan Maslak wrote:
> Add a test that verifies the kernel correctly blocks unbind operations
> on VMAs whose VM_BIND ufence has not yet been ACKed by the debugger.
>
> The test performs N vm_bind operations with user fences attached, then
> partially acknowledges them: the first (N-2) ufences are ACKed
> immediately, while the remaining 2 are withheld. It checks that:
> - the ACKed ufences complete successfully,
> - the un-ACKed ufences time out as blocked,
> - unbind attempts on the un-ACKed VMAs are denied with -EBUSY,
> - after the remaining ACKs are delivered, the blocked ufences complete
> and the unbinds succeed.
>
> Signed-off-by: Jan Maslak <jan.maslak@intel.com>
> ---
> tests/intel/xe_eudebug.c | 144 +++++++++++++++++++++++++++++++++------
> 1 file changed, 124 insertions(+), 20 deletions(-)
>
> diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
> index 134f31766..c899316fb 100644
> --- a/tests/intel/xe_eudebug.c
> +++ b/tests/intel/xe_eudebug.c
> @@ -66,6 +66,7 @@ static void test_sysfs_toggle(int fd)
> #define VM_BIND_DELAY_UFENCE_ACK (1 << 8)
> #define VM_BIND_UFENCE_RECONNECT (1 << 9)
> #define VM_BIND_UFENCE_SIGINT_CLIENT (1 << 10)
> +#define VM_BIND_UFENCE_NO_ACK (1 << 11)
> #define TEST_FAULTABLE (1 << 30)
> #define TEST_DISCOVERY (1 << 31)
>
> @@ -1924,6 +1925,7 @@ static void test_metadata_attach(int fd, unsigned int flags, int num_clients)
> }
>
> #define STAGE_CLIENT_WAIT_ON_UFENCE_DONE 1337
> +#define STAGE_NO_ACK_READY_FOR_PARTIAL_ACK 1338
>
> #define UFENCE_EVENT_COUNT_EXPECTED 4
> #define UFENCE_EVENT_COUNT_MAX 100
> @@ -1973,6 +1975,72 @@ static void client_wait_ufences(struct xe_eudebug_client *c,
> }
> }
>
> +#define NO_ACK_HELD_COUNT 2
> +
> +static void client_wait_ufences_no_ack(struct xe_eudebug_client *c,
> + int fd, uint32_t vm,
> + struct ufence_bind *binds, int count)
> +{
> + const int64_t short_timeout_ns = 500 * NSEC_PER_MSEC;
> + const int64_t long_timeout_ns = XE_EUDEBUG_DEFAULT_TIMEOUT_SEC * NSEC_PER_SEC;
> + int64_t timeout_ns;
> + int err;
> +
> + igt_assert(count >= NO_ACK_HELD_COUNT);
> +
> + /* Signal debugger that binds are done - it will ACK first (N-2) fences */
> + xe_eudebug_client_signal_stage(c, STAGE_NO_ACK_READY_FOR_PARTIAL_ACK);
> +
> + /* First (count - NO_ACK_HELD_COUNT) fences should be ACKed already - expect success */
> + for (int i = 0; i < count - NO_ACK_HELD_COUNT; i++) {
> + struct ufence_bind *b = &binds[i];
> +
> + timeout_ns = long_timeout_ns;
> + err = __xe_wait_ufence(fd, &b->fence_data->vm_sync, b->f.timeline_value,
> + 0, &timeout_ns);
> + igt_assert_eq(err, 0);
> + igt_assert_eq(b->fence_data->vm_sync, b->f.timeline_value);
> + igt_debug("no-ack: wait #%d completed (was ACKed)\n", i);
> + }
> +
> + /* Last NO_ACK_HELD_COUNT fences should NOT be ACKed yet - expect timeout */
> + for (int i = count - NO_ACK_HELD_COUNT; i < count; i++) {
> + struct ufence_bind *b = &binds[i];
> +
> + timeout_ns = short_timeout_ns;
> + err = __xe_wait_ufence(fd, &b->fence_data->vm_sync, b->f.timeline_value,
> + 0, &timeout_ns);
> + igt_assert_eq(err, -ETIME);
> + igt_assert_neq(b->fence_data->vm_sync, b->f.timeline_value);
> + igt_debug("no-ack: wait #%d blocked as expected (not ACKed)\n", i);
> + }
> +
> + /* Try to unbind un-ACKed VMAs - kernel should deny with -EBUSY */
> + for (int i = count - NO_ACK_HELD_COUNT; i < count; i++) {
> + struct ufence_bind *b = &binds[i];
> +
> + err = __xe_vm_bind(fd, vm, 0, 0, 0, b->addr, b->range,
> + DRM_XE_VM_BIND_OP_UNMAP, 0, NULL, 0, 0, 0, 0);
> + igt_assert_eq(err, -EBUSY);
> + igt_debug("no-ack: unbind #%d denied with -EBUSY as expected\n", i);
> + }
> +
Hi Janek,
I would feel much better if I saw that there is two way communication
between client and debugger/test.
Right now, as I read it, both are running simply in parallel not
synchronizing actions between (more or less).
This part should generally work even on very busy systems with a lot of
delay.
> + /* Signal debugger that we verified the blocked state - it will now send remaining ACKs */
> + xe_eudebug_client_signal_stage(c, STAGE_CLIENT_WAIT_ON_UFENCE_DONE);
> +
> + /* Now last NO_ACK_HELD_COUNT fences should complete after debugger ACKs them */
> + for (int i = count - NO_ACK_HELD_COUNT; i < count; i++) {
> + struct ufence_bind *b = &binds[i];
> +
> + timeout_ns = long_timeout_ns;
> + err = __xe_wait_ufence(fd, &b->fence_data->vm_sync, b->f.timeline_value,
> + 0, &timeout_ns);
> + igt_assert_eq(err, 0);
> + igt_assert_eq(b->fence_data->vm_sync, b->f.timeline_value);
> + igt_debug("no-ack: wait #%d completed after delayed ACK\n", i);
> + }
> +}
> +
but this part is something I fear may cause sporadic error.
What I would suggest is to add additional stages:
Debugger tells - done with acking ufences 1 and 2
This will synchronize the clients checks with debugger actions.
> static struct ufence_bind *create_binds_with_ufence(int fd, int count)
> {
> struct ufence_bind *binds;
> @@ -2024,7 +2092,10 @@ static void basic_ufence_client(struct xe_eudebug_client *c)
> &b->f, 1, 0);
> }
>
> - client_wait_ufences(c, fd, binds, n);
> + if (c->flags & VM_BIND_UFENCE_NO_ACK)
> + client_wait_ufences_no_ack(c, fd, vm, binds, n);
> + else
> + client_wait_ufences(c, fd, binds, n);
>
> for (int i = 0; i < n; i++) {
> struct ufence_bind *b = &binds[i];
> @@ -2147,6 +2218,13 @@ static int wait_for_ufence_events(struct ufence_priv *priv, int timeout_ms)
> * Functionality: SIGINT
> * Description:
> * Give user fence in application, hold it, send SIGINT to client and check if anything breaks.
> + *
> + * SUBTEST: basic-vm-bind-ufence-no-ack
> + * Functionality: VM bind event
> + * Description:
> + * Verify that missing debugger ACK for VM_BIND ufence blocks the application.
> + * ACKs only the first (N-2) ufences immediately, verifies last 2 are blocked,
> + * then delivers remaining ACKs and confirms client unblocks.
> */
> static void test_basic_ufence(int fd, unsigned int flags)
> {
> @@ -2169,26 +2247,49 @@ static void test_basic_ufence(int fd, unsigned int flags)
> xe_eudebug_debugger_start_worker(d);
> xe_eudebug_client_start(c);
>
> - xe_eudebug_debugger_wait_stage(s, STAGE_CLIENT_WAIT_ON_UFENCE_DONE);
> - xe_eudebug_assert_f(d, wait_for_ufence_events(priv, XE_EUDEBUG_DEFAULT_TIMEOUT_SEC * MSEC_PER_SEC) == 0,
> - "missing ufence events\n");
> -
> - if (flags & VM_BIND_DELAY_UFENCE_ACK)
> - sleep(XE_EUDEBUG_DEFAULT_TIMEOUT_SEC * 4 / 5);
> -
> - if (flags & VM_BIND_UFENCE_SIGINT_CLIENT) {
> - filter = XE_EUDEBUG_FILTER_ALL;
> - kill(c->pid, SIGINT);
> - c->pid = 0;
> - c->done = 1;
> - } else if (flags & VM_BIND_UFENCE_RECONNECT) {
> - filter = XE_EUDEBUG_FILTER_EVENT_VM_BIND | XE_EUDEBUG_FILTER_EVENT_VM |
> - XE_EUDEBUG_FILTER_EVENT_OPEN;
> - xe_eudebug_debugger_detach(d);
> - xe_eudebug_client_wait_done(c);
> - igt_assert_eq(xe_eudebug_debugger_attach(d, c), 0);
> + if (flags & VM_BIND_UFENCE_NO_ACK) {
> + /* Wait for client to signal binds are done */
> + xe_eudebug_debugger_wait_stage(s, STAGE_NO_ACK_READY_FOR_PARTIAL_ACK);
> + xe_eudebug_assert_f(d,
> + wait_for_ufence_events(priv, XE_EUDEBUG_DEFAULT_TIMEOUT_SEC *
> + MSEC_PER_SEC) == 0,
> + "missing ufence events\n");
> +
> + /* ACK only first (n-2) fences */
> + for (int i = 0; i < UFENCE_EVENT_COUNT_EXPECTED - NO_ACK_HELD_COUNT; i++)
> + xe_eudebug_ack_ufence(d->fd, &priv->ufence_events[i]);
> +
xe_eudebug_debugger_signal_stage(s, STAGE_DBG_UFENCE_ACK_DONE_1);
> + /* Wait for client to verify blocked state and unbind attempts */
> + xe_eudebug_debugger_wait_stage(s, STAGE_CLIENT_WAIT_ON_UFENCE_DONE);
> +
> + /* ACK remaining fences */
> + for (int i = UFENCE_EVENT_COUNT_EXPECTED - NO_ACK_HELD_COUNT;
> + i < UFENCE_EVENT_COUNT_EXPECTED; i++)
> + xe_eudebug_ack_ufence(d->fd, &priv->ufence_events[i]);
xe_eudebug_debugger_signal_stage(s, STAGE_DBG_UFENCE_ACK_DONE_2);
> } else {
> - ack_fences(d);
> + xe_eudebug_debugger_wait_stage(s, STAGE_CLIENT_WAIT_ON_UFENCE_DONE);
> + xe_eudebug_assert_f(d,
> + wait_for_ufence_events(priv, XE_EUDEBUG_DEFAULT_TIMEOUT_SEC *
> + MSEC_PER_SEC) == 0,
> + "missing ufence events\n");
> +
> + if (flags & VM_BIND_DELAY_UFENCE_ACK)
> + sleep(XE_EUDEBUG_DEFAULT_TIMEOUT_SEC * 4 / 5);
> +
> + if (flags & VM_BIND_UFENCE_SIGINT_CLIENT) {
> + filter = XE_EUDEBUG_FILTER_ALL;
> + kill(c->pid, SIGINT);
> + c->pid = 0;
> + c->done = 1;
> + } else if (flags & VM_BIND_UFENCE_RECONNECT) {
> + filter = XE_EUDEBUG_FILTER_EVENT_VM_BIND | XE_EUDEBUG_FILTER_EVENT_VM |
> + XE_EUDEBUG_FILTER_EVENT_OPEN;
> + xe_eudebug_debugger_detach(d);
> + xe_eudebug_client_wait_done(c);
> + igt_assert_eq(xe_eudebug_debugger_attach(d, c), 0);
> + } else {
> + ack_fences(d);
> + }
> }
>
> xe_eudebug_client_wait_done(c);
> @@ -2882,6 +2983,9 @@ int igt_main()
> igt_subtest("basic-vm-bind-ufence-sigint-client")
> test_basic_ufence(fd, VM_BIND_UFENCE_SIGINT_CLIENT);
>
> + igt_subtest("basic-vm-bind-ufence-no-ack")
> + test_basic_ufence(fd, VM_BIND_UFENCE_NO_ACK);
> +
> igt_subtest("basic-vm-bind-discovery")
> test_basic_discovery(fd, VM_BIND, true);
>
With that it's done.
Maciej
next prev parent reply other threads:[~2026-05-07 8:53 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-27 14:26 [PATCH 0/1] tests/intel/xe_eudebug: Add basic-vm-bind-ufence-no-ack test Jan Maslak
2026-02-27 14:26 ` [PATCH 1/1] " Jan Maslak
2026-05-07 8:52 ` Maciej Patelczyk [this message]
2026-02-27 20:55 ` ✓ Xe.CI.BAT: success for " Patchwork
2026-02-27 20:57 ` ✗ i915.CI.BAT: failure " Patchwork
2026-02-28 10:22 ` ✗ Xe.CI.FULL: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=24aa9483-a6a9-46e2-b5e6-0a775ab6cc34@intel.com \
--to=maciej.patelczyk@intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=jan.maslak@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox