Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

locking/ww_mutex: Add kselftests for ww_mutex ABBA deadlock detection

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Maarten Lankhorst <dev@mblankhorst.nl>
Cc: Nicolai Hähnle <nhaehnle@gmail.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20161201114711.28697-6-chris@chris-wilson.co.uk
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Chris Wilson and committed by
Ingo Molnar
70207686 c22fb380

+98
+98
kernel/locking/test-ww_mutex.c
··· 153 153 return ret; 154 154 } 155 155 156 + struct test_abba { 157 + struct work_struct work; 158 + struct ww_mutex a_mutex; 159 + struct ww_mutex b_mutex; 160 + struct completion a_ready; 161 + struct completion b_ready; 162 + bool resolve; 163 + int result; 164 + }; 165 + 166 + static void test_abba_work(struct work_struct *work) 167 + { 168 + struct test_abba *abba = container_of(work, typeof(*abba), work); 169 + struct ww_acquire_ctx ctx; 170 + int err; 171 + 172 + ww_acquire_init(&ctx, &ww_class); 173 + ww_mutex_lock(&abba->b_mutex, &ctx); 174 + 175 + complete(&abba->b_ready); 176 + wait_for_completion(&abba->a_ready); 177 + 178 + err = ww_mutex_lock(&abba->a_mutex, &ctx); 179 + if (abba->resolve && err == -EDEADLK) { 180 + ww_mutex_unlock(&abba->b_mutex); 181 + ww_mutex_lock_slow(&abba->a_mutex, &ctx); 182 + err = ww_mutex_lock(&abba->b_mutex, &ctx); 183 + } 184 + 185 + if (!err) 186 + ww_mutex_unlock(&abba->a_mutex); 187 + ww_mutex_unlock(&abba->b_mutex); 188 + ww_acquire_fini(&ctx); 189 + 190 + abba->result = err; 191 + } 192 + 193 + static int test_abba(bool resolve) 194 + { 195 + struct test_abba abba; 196 + struct ww_acquire_ctx ctx; 197 + int err, ret; 198 + 199 + ww_mutex_init(&abba.a_mutex, &ww_class); 200 + ww_mutex_init(&abba.b_mutex, &ww_class); 201 + INIT_WORK_ONSTACK(&abba.work, test_abba_work); 202 + init_completion(&abba.a_ready); 203 + init_completion(&abba.b_ready); 204 + abba.resolve = resolve; 205 + 206 + schedule_work(&abba.work); 207 + 208 + ww_acquire_init(&ctx, &ww_class); 209 + ww_mutex_lock(&abba.a_mutex, &ctx); 210 + 211 + complete(&abba.a_ready); 212 + wait_for_completion(&abba.b_ready); 213 + 214 + err = ww_mutex_lock(&abba.b_mutex, &ctx); 215 + if (resolve && err == -EDEADLK) { 216 + ww_mutex_unlock(&abba.a_mutex); 217 + ww_mutex_lock_slow(&abba.b_mutex, &ctx); 218 + err = ww_mutex_lock(&abba.a_mutex, &ctx); 219 + } 220 + 221 + if (!err) 222 + ww_mutex_unlock(&abba.b_mutex); 223 + ww_mutex_unlock(&abba.a_mutex); 224 + ww_acquire_fini(&ctx); 225 + 226 + flush_work(&abba.work); 227 + destroy_work_on_stack(&abba.work); 228 + 229 + ret = 0; 230 + if (resolve) { 231 + if (err || abba.result) { 232 + pr_err("%s: failed to resolve ABBA deadlock, A err=%d, B err=%d\n", 233 + __func__, err, abba.result); 234 + ret = -EINVAL; 235 + } 236 + } else { 237 + if (err != -EDEADLK && abba.result != -EDEADLK) { 238 + pr_err("%s: missed ABBA deadlock, A err=%d, B err=%d\n", 239 + __func__, err, abba.result); 240 + ret = -EINVAL; 241 + } 242 + } 243 + return ret; 244 + } 245 + 156 246 static int __init test_ww_mutex_init(void) 157 247 { 158 248 int ret; ··· 252 162 return ret; 253 163 254 164 ret = test_aa(); 165 + if (ret) 166 + return ret; 167 + 168 + ret = test_abba(false); 169 + if (ret) 170 + return ret; 171 + 172 + ret = test_abba(true); 255 173 if (ret) 256 174 return ret; 257 175