1 /* 2 * Module-based API test facility for ww_mutexes 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, you can access it online at 16 * http://www.gnu.org/licenses/gpl-2.0.html. 17 */ 18 19 #include <linux/kernel.h> 20 21 #include <linux/completion.h> 22 #include <linux/kthread.h> 23 #include <linux/module.h> 24 #include <linux/ww_mutex.h> 25 26 static DEFINE_WW_CLASS(ww_class); 27 28 struct test_mutex { 29 struct work_struct work; 30 struct ww_mutex mutex; 31 struct completion ready, go, done; 32 unsigned int flags; 33 }; 34 35 #define TEST_MTX_SPIN BIT(0) 36 #define TEST_MTX_TRY BIT(1) 37 #define TEST_MTX_CTX BIT(2) 38 #define __TEST_MTX_LAST BIT(3) 39 40 static void test_mutex_work(struct work_struct *work) 41 { 42 struct test_mutex *mtx = container_of(work, typeof(*mtx), work); 43 44 complete(&mtx->ready); 45 wait_for_completion(&mtx->go); 46 47 if (mtx->flags & TEST_MTX_TRY) { 48 while (!ww_mutex_trylock(&mtx->mutex)) 49 cpu_relax(); 50 } else { 51 ww_mutex_lock(&mtx->mutex, NULL); 52 } 53 complete(&mtx->done); 54 ww_mutex_unlock(&mtx->mutex); 55 } 56 57 static int __test_mutex(unsigned int flags) 58 { 59 #define TIMEOUT (HZ / 16) 60 struct test_mutex mtx; 61 struct ww_acquire_ctx ctx; 62 int ret; 63 64 ww_mutex_init(&mtx.mutex, &ww_class); 65 ww_acquire_init(&ctx, &ww_class); 66 67 INIT_WORK_ONSTACK(&mtx.work, test_mutex_work); 68 init_completion(&mtx.ready); 69 init_completion(&mtx.go); 70 init_completion(&mtx.done); 71 mtx.flags = flags; 72 73 schedule_work(&mtx.work); 74 75 wait_for_completion(&mtx.ready); 76 ww_mutex_lock(&mtx.mutex, (flags & TEST_MTX_CTX) ? &ctx : NULL); 77 complete(&mtx.go); 78 if (flags & TEST_MTX_SPIN) { 79 unsigned long timeout = jiffies + TIMEOUT; 80 81 ret = 0; 82 do { 83 if (completion_done(&mtx.done)) { 84 ret = -EINVAL; 85 break; 86 } 87 cpu_relax(); 88 } while (time_before(jiffies, timeout)); 89 } else { 90 ret = wait_for_completion_timeout(&mtx.done, TIMEOUT); 91 } 92 ww_mutex_unlock(&mtx.mutex); 93 ww_acquire_fini(&ctx); 94 95 if (ret) { 96 pr_err("%s(flags=%x): mutual exclusion failure\n", 97 __func__, flags); 98 ret = -EINVAL; 99 } 100 101 flush_work(&mtx.work); 102 destroy_work_on_stack(&mtx.work); 103 return ret; 104 #undef TIMEOUT 105 } 106 107 static int test_mutex(void) 108 { 109 int ret; 110 int i; 111 112 for (i = 0; i < __TEST_MTX_LAST; i++) { 113 ret = __test_mutex(i); 114 if (ret) 115 return ret; 116 } 117 118 return 0; 119 } 120 121 static int __init test_ww_mutex_init(void) 122 { 123 int ret; 124 125 ret = test_mutex(); 126 if (ret) 127 return ret; 128 129 return 0; 130 } 131 132 static void __exit test_ww_mutex_exit(void) 133 { 134 } 135 136 module_init(test_ww_mutex_init); 137 module_exit(test_ww_mutex_exit); 138 139 MODULE_LICENSE("GPL"); 140 MODULE_AUTHOR("Intel Corporation"); 141