[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250110200508.353290-5-andrealmeid@igalia.com>
Date: Fri, 10 Jan 2025 17:05:08 -0300
From: André Almeida <andrealmeid@...lia.com>
To: Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...hat.com>,
Peter Zijlstra <peterz@...radead.org>,
Darren Hart <dvhart@...radead.org>,
Davidlohr Bueso <dave@...olabs.net>,
Arnd Bergmann <arnd@...db.de>,
Florian Weimer <fweimer@...hat.com>
Cc: linux-kernel@...r.kernel.org,
kernel-dev@...lia.com,
Vinicius Peixoto <vpeixoto@...amp.dev>,
André Almeida <andrealmeid@...lia.com>
Subject: [PATCH 4/4] selftests/futex: Create tests for long and circular robust lists
After dropping ROBUST_LIST_LIMIT, create new robust list tests to ensure
two conditions:
- That the kernel can correctly handle circular lists
- That the kernel can correctly wake up elements in very long lists,
larger that the old ROBUST_LIST_LIMIT.
Signed-off-by: André Almeida <andrealmeid@...lia.com>
---
.../selftests/futex/functional/robust_list.c | 127 +++++++++++++++++-
1 file changed, 126 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index bd4437c6aebb..4bd6795b3ac5 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -471,6 +471,128 @@ static void test_robust_list_multiple_elements(void)
ksft_test_result_pass("%s\n", __func__);
}
+/*
+ * This is the old limit defined by the kernel
+ */
+#define ROBUST_LIST_LIMIT 2048
+#define CHILD_LIST_LIMIT (ROBUST_LIST_LIMIT + 10)
+
+static int child_robust_list_limit(void *arg)
+{
+ struct lock_struct *locks;
+ struct robust_list *list;
+ struct robust_list_head head;
+ int ret, i;
+
+ locks = (struct lock_struct *) arg;
+
+ ret = set_list(&head);
+ if (ret)
+ ksft_test_result_fail("set_list error\n");
+
+ /*
+ * Create a very long list of locks
+ */
+ head.list.next = &locks[0].list;
+
+ list = head.list.next;
+ for (i = 0; i < CHILD_LIST_LIMIT - 1; i++) {
+ list->next = &locks[i+1].list;
+ list = list->next;
+ }
+ list->next = &head.list;
+
+ /*
+ * Grab the lock in the last one, and die without releasing it
+ */
+ mutex_lock(&locks[CHILD_LIST_LIMIT], &head, false);
+ pthread_barrier_wait(&barrier);
+
+ sleep(1);
+
+ return 0;
+}
+
+/*
+ * Robust list used to have a limit of 2048 items from the kernel side. After
+ * this limit the kernel would stop walking the list and ignore the other
+ * futexes, causing deadlocks.
+ *
+ * After this limit has been dropped, test if we can wait for a list of more
+ * than 2048 elements.
+ */
+static void test_robust_list_limit(void)
+{
+ struct lock_struct locks[CHILD_LIST_LIMIT + 1];
+ _Atomic(unsigned int) *futex = &locks[CHILD_LIST_LIMIT].futex;
+ struct robust_list_head head;
+ int ret;
+
+ *futex = 0;
+
+ ret = set_list(&head);
+ ASSERT_EQ(ret, 0);
+
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ASSERT_EQ(ret, 0);
+
+ create_child(child_robust_list_limit, locks);
+
+ /*
+ * After the child thread creates the very long list of locks, wait on
+ * the last one.
+ */
+ pthread_barrier_wait(&barrier);
+ ret = mutex_lock(&locks[CHILD_LIST_LIMIT], &head, false);
+
+ if (ret != 0)
+ printf("futex wait returned %d\n", errno);
+ ASSERT_EQ(ret, 0);
+
+ ASSERT_TRUE(*futex | FUTEX_OWNER_DIED);
+
+ wait(NULL);
+ pthread_barrier_destroy(&barrier);
+
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+static int child_circular_list(void *arg)
+{
+ static struct robust_list_head head;
+ struct lock_struct a, b, c;
+ int ret;
+
+ ret = set_list(&head);
+ if (ret)
+ ksft_test_result_fail("set_list error\n");
+
+ head.list.next = &a.list;
+
+ /*
+ * The last element should point to head list, but we short circuit it
+ */
+ a.list.next = &b.list;
+ b.list.next = &c.list;
+ c.list.next = &a.list;
+
+ return 0;
+}
+
+/*
+ * Create a circular robust list. The kernel should be able to destroy the list
+ * while processing it so it won't be trapped in an infinite loop while handling
+ * a process exit
+ */
+static void test_circular_list(void)
+{
+ create_child(child_circular_list, NULL);
+
+ wait(NULL);
+
+ ksft_test_result_pass("%s\n", __func__);
+}
+
void usage(char *prog)
{
printf("Usage: %s\n", prog);
@@ -502,14 +624,17 @@ int main(int argc, char *argv[])
}
ksft_print_header();
- ksft_set_plan(6);
+ ksft_set_plan(8);
test_robustness();
+
test_set_robust_list_invalid_size();
test_get_robust_list_self();
test_get_robust_list_child();
test_set_list_op_pending();
test_robust_list_multiple_elements();
+ test_robust_list_limit();
+ test_circular_list();
ksft_print_cnts();
return 0;
--
2.47.1
Powered by blists - more mailing lists