diff options
-rw-r--r-- | Documentation/fault-injection/fault-injection.txt | 11 | ||||
-rw-r--r-- | kernel/futex.c | 89 | ||||
-rw-r--r-- | lib/Kconfig.debug | 7 |
3 files changed, 105 insertions, 2 deletions
diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index 4cf1a2a6bd72..415484f3d59a 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt | |||
@@ -15,6 +15,10 @@ o fail_page_alloc | |||
15 | 15 | ||
16 | injects page allocation failures. (alloc_pages(), get_free_pages(), ...) | 16 | injects page allocation failures. (alloc_pages(), get_free_pages(), ...) |
17 | 17 | ||
18 | o fail_futex | ||
19 | |||
20 | injects futex deadlock and uaddr fault errors. | ||
21 | |||
18 | o fail_make_request | 22 | o fail_make_request |
19 | 23 | ||
20 | injects disk IO errors on devices permitted by setting | 24 | injects disk IO errors on devices permitted by setting |
@@ -113,6 +117,12 @@ configuration of fault-injection capabilities. | |||
113 | specifies the minimum page allocation order to be injected | 117 | specifies the minimum page allocation order to be injected |
114 | failures. | 118 | failures. |
115 | 119 | ||
120 | - /sys/kernel/debug/fail_futex/ignore-private: | ||
121 | |||
122 | Format: { 'Y' | 'N' } | ||
123 | default is 'N', setting it to 'Y' will disable failure injections | ||
124 | when dealing with private (address space) futexes. | ||
125 | |||
116 | o Boot option | 126 | o Boot option |
117 | 127 | ||
118 | In order to inject faults while debugfs is not available (early boot time), | 128 | In order to inject faults while debugfs is not available (early boot time), |
@@ -121,6 +131,7 @@ use the boot option: | |||
121 | failslab= | 131 | failslab= |
122 | fail_page_alloc= | 132 | fail_page_alloc= |
123 | fail_make_request= | 133 | fail_make_request= |
134 | fail_futex= | ||
124 | mmc_core.fail_request=<interval>,<probability>,<space>,<times> | 135 | mmc_core.fail_request=<interval>,<probability>,<space>,<times> |
125 | 136 | ||
126 | How to add new fault injection capability | 137 | How to add new fault injection capability |
diff --git a/kernel/futex.c b/kernel/futex.c index 153eb22b0fc0..6ea31bb703c9 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/hugetlb.h> | 64 | #include <linux/hugetlb.h> |
65 | #include <linux/freezer.h> | 65 | #include <linux/freezer.h> |
66 | #include <linux/bootmem.h> | 66 | #include <linux/bootmem.h> |
67 | #include <linux/fault-inject.h> | ||
67 | 68 | ||
68 | #include <asm/futex.h> | 69 | #include <asm/futex.h> |
69 | 70 | ||
@@ -258,6 +259,66 @@ static unsigned long __read_mostly futex_hashsize; | |||
258 | 259 | ||
259 | static struct futex_hash_bucket *futex_queues; | 260 | static struct futex_hash_bucket *futex_queues; |
260 | 261 | ||
262 | /* | ||
263 | * Fault injections for futexes. | ||
264 | */ | ||
265 | #ifdef CONFIG_FAIL_FUTEX | ||
266 | |||
267 | static struct { | ||
268 | struct fault_attr attr; | ||
269 | |||
270 | u32 ignore_private; | ||
271 | } fail_futex = { | ||
272 | .attr = FAULT_ATTR_INITIALIZER, | ||
273 | .ignore_private = 0, | ||
274 | }; | ||
275 | |||
276 | static int __init setup_fail_futex(char *str) | ||
277 | { | ||
278 | return setup_fault_attr(&fail_futex.attr, str); | ||
279 | } | ||
280 | __setup("fail_futex=", setup_fail_futex); | ||
281 | |||
282 | bool should_fail_futex(bool fshared) | ||
283 | { | ||
284 | if (fail_futex.ignore_private && !fshared) | ||
285 | return false; | ||
286 | |||
287 | return should_fail(&fail_futex.attr, 1); | ||
288 | } | ||
289 | |||
290 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
291 | |||
292 | static int __init fail_futex_debugfs(void) | ||
293 | { | ||
294 | umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | ||
295 | struct dentry *dir; | ||
296 | |||
297 | dir = fault_create_debugfs_attr("fail_futex", NULL, | ||
298 | &fail_futex.attr); | ||
299 | if (IS_ERR(dir)) | ||
300 | return PTR_ERR(dir); | ||
301 | |||
302 | if (!debugfs_create_bool("ignore-private", mode, dir, | ||
303 | &fail_futex.ignore_private)) { | ||
304 | debugfs_remove_recursive(dir); | ||
305 | return -ENOMEM; | ||
306 | } | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | late_initcall(fail_futex_debugfs); | ||
312 | |||
313 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
314 | |||
315 | #else | ||
316 | static inline bool should_fail_futex(bool fshared) | ||
317 | { | ||
318 | return false; | ||
319 | } | ||
320 | #endif /* CONFIG_FAIL_FUTEX */ | ||
321 | |||
261 | static inline void futex_get_mm(union futex_key *key) | 322 | static inline void futex_get_mm(union futex_key *key) |
262 | { | 323 | { |
263 | atomic_inc(&key->private.mm->mm_count); | 324 | atomic_inc(&key->private.mm->mm_count); |
@@ -413,6 +474,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) | |||
413 | if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) | 474 | if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) |
414 | return -EFAULT; | 475 | return -EFAULT; |
415 | 476 | ||
477 | if (unlikely(should_fail_futex(fshared))) | ||
478 | return -EFAULT; | ||
479 | |||
416 | /* | 480 | /* |
417 | * PROCESS_PRIVATE futexes are fast. | 481 | * PROCESS_PRIVATE futexes are fast. |
418 | * As the mm cannot disappear under us and the 'key' only needs | 482 | * As the mm cannot disappear under us and the 'key' only needs |
@@ -428,6 +492,10 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) | |||
428 | } | 492 | } |
429 | 493 | ||
430 | again: | 494 | again: |
495 | /* Ignore any VERIFY_READ mapping (futex common case) */ | ||
496 | if (unlikely(should_fail_futex(fshared))) | ||
497 | return -EFAULT; | ||
498 | |||
431 | err = get_user_pages_fast(address, 1, 1, &page); | 499 | err = get_user_pages_fast(address, 1, 1, &page); |
432 | /* | 500 | /* |
433 | * If write access is not required (eg. FUTEX_WAIT), try | 501 | * If write access is not required (eg. FUTEX_WAIT), try |
@@ -516,7 +584,7 @@ again: | |||
516 | * A RO anonymous page will never change and thus doesn't make | 584 | * A RO anonymous page will never change and thus doesn't make |
517 | * sense for futex operations. | 585 | * sense for futex operations. |
518 | */ | 586 | */ |
519 | if (ro) { | 587 | if (unlikely(should_fail_futex(fshared)) || ro) { |
520 | err = -EFAULT; | 588 | err = -EFAULT; |
521 | goto out; | 589 | goto out; |
522 | } | 590 | } |
@@ -974,6 +1042,9 @@ static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) | |||
974 | { | 1042 | { |
975 | u32 uninitialized_var(curval); | 1043 | u32 uninitialized_var(curval); |
976 | 1044 | ||
1045 | if (unlikely(should_fail_futex(true))) | ||
1046 | return -EFAULT; | ||
1047 | |||
977 | if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))) | 1048 | if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))) |
978 | return -EFAULT; | 1049 | return -EFAULT; |
979 | 1050 | ||
@@ -1015,12 +1086,18 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, | |||
1015 | if (get_futex_value_locked(&uval, uaddr)) | 1086 | if (get_futex_value_locked(&uval, uaddr)) |
1016 | return -EFAULT; | 1087 | return -EFAULT; |
1017 | 1088 | ||
1089 | if (unlikely(should_fail_futex(true))) | ||
1090 | return -EFAULT; | ||
1091 | |||
1018 | /* | 1092 | /* |
1019 | * Detect deadlocks. | 1093 | * Detect deadlocks. |
1020 | */ | 1094 | */ |
1021 | if ((unlikely((uval & FUTEX_TID_MASK) == vpid))) | 1095 | if ((unlikely((uval & FUTEX_TID_MASK) == vpid))) |
1022 | return -EDEADLK; | 1096 | return -EDEADLK; |
1023 | 1097 | ||
1098 | if ((unlikely(should_fail_futex(true)))) | ||
1099 | return -EDEADLK; | ||
1100 | |||
1024 | /* | 1101 | /* |
1025 | * Lookup existing state first. If it exists, try to attach to | 1102 | * Lookup existing state first. If it exists, try to attach to |
1026 | * its pi_state. | 1103 | * its pi_state. |
@@ -1155,6 +1232,9 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this, | |||
1155 | */ | 1232 | */ |
1156 | newval = FUTEX_WAITERS | task_pid_vnr(new_owner); | 1233 | newval = FUTEX_WAITERS | task_pid_vnr(new_owner); |
1157 | 1234 | ||
1235 | if (unlikely(should_fail_futex(true))) | ||
1236 | ret = -EFAULT; | ||
1237 | |||
1158 | if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) | 1238 | if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) |
1159 | ret = -EFAULT; | 1239 | ret = -EFAULT; |
1160 | else if (curval != uval) | 1240 | else if (curval != uval) |
@@ -1457,6 +1537,9 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, | |||
1457 | if (get_futex_value_locked(&curval, pifutex)) | 1537 | if (get_futex_value_locked(&curval, pifutex)) |
1458 | return -EFAULT; | 1538 | return -EFAULT; |
1459 | 1539 | ||
1540 | if (unlikely(should_fail_futex(true))) | ||
1541 | return -EFAULT; | ||
1542 | |||
1460 | /* | 1543 | /* |
1461 | * Find the top_waiter and determine if there are additional waiters. | 1544 | * Find the top_waiter and determine if there are additional waiters. |
1462 | * If the caller intends to requeue more than 1 waiter to pifutex, | 1545 | * If the caller intends to requeue more than 1 waiter to pifutex, |
@@ -2537,7 +2620,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, | |||
2537 | * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2 | 2620 | * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2 |
2538 | * @uaddr: the futex we initially wait on (non-pi) | 2621 | * @uaddr: the futex we initially wait on (non-pi) |
2539 | * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be | 2622 | * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be |
2540 | * the same type, no requeueing from private to shared, etc. | 2623 | * the same type, no requeueing from private to shared, etc. |
2541 | * @val: the expected value of uaddr | 2624 | * @val: the expected value of uaddr |
2542 | * @abs_time: absolute timeout | 2625 | * @abs_time: absolute timeout |
2543 | * @bitset: 32 bit wakeup bitset set by userspace, defaults to all | 2626 | * @bitset: 32 bit wakeup bitset set by userspace, defaults to all |
@@ -3012,6 +3095,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, | |||
3012 | if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || | 3095 | if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || |
3013 | cmd == FUTEX_WAIT_BITSET || | 3096 | cmd == FUTEX_WAIT_BITSET || |
3014 | cmd == FUTEX_WAIT_REQUEUE_PI)) { | 3097 | cmd == FUTEX_WAIT_REQUEUE_PI)) { |
3098 | if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG)))) | ||
3099 | return -EFAULT; | ||
3015 | if (copy_from_user(&ts, utime, sizeof(ts)) != 0) | 3100 | if (copy_from_user(&ts, utime, sizeof(ts)) != 0) |
3016 | return -EFAULT; | 3101 | return -EFAULT; |
3017 | if (!timespec_valid(&ts)) | 3102 | if (!timespec_valid(&ts)) |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e2894b23efb6..22554d6f720f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -1542,6 +1542,13 @@ config FAIL_MMC_REQUEST | |||
1542 | and to test how the mmc host driver handles retries from | 1542 | and to test how the mmc host driver handles retries from |
1543 | the block device. | 1543 | the block device. |
1544 | 1544 | ||
1545 | config FAIL_FUTEX | ||
1546 | bool "Fault-injection capability for futexes" | ||
1547 | select DEBUG_FS | ||
1548 | depends on FAULT_INJECTION && FUTEX | ||
1549 | help | ||
1550 | Provide fault-injection capability for futexes. | ||
1551 | |||
1545 | config FAULT_INJECTION_DEBUG_FS | 1552 | config FAULT_INJECTION_DEBUG_FS |
1546 | bool "Debugfs entries for fault-injection capabilities" | 1553 | bool "Debugfs entries for fault-injection capabilities" |
1547 | depends on FAULT_INJECTION && SYSFS && DEBUG_FS | 1554 | depends on FAULT_INJECTION && SYSFS && DEBUG_FS |