-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ioengines.c:346: td_io_queue: Assertion `res == 0' failed #1521
ioengines.c:346: td_io_queue: Assertion `res == 0' failed #1521
Conversation
Assertion in ioengines.c::td_io_queue() fails for pthread_mutex_unlock() on overlap_check mutex when serialize_overlap=1, io_submit_mode=offload, and verify=<any> are used together. backend.c::fio_io_sync() invokes td_io_queue(), which expects the caller to have ownership of the overlap_check mutex when serialize_overlap and offloading are configured, as part of the overlap-check interlock with IO_U_F_FLIGHT. The mutex is not acquired for this path because it's not an I/O requiring an overlap check. The fix is to refine the conditional that triggers td_io_queue() to release the overlap_check mutex. Rather than using broad config options, the conditional now uses a new io_u flag named IO_U_F_OVERLAP_LOCK, which is only set for the offload worker thread path that acquires the mutex. Link: axboe#1520 Signed-off-by: Adam Horshack (horshack@live.com)
This is causing a crash, and I should've done a better job reviewing it. The rate-submit.c is nonsensical. Did you test this at all? I'm going to revert the change for now. |
I tested it against a matrix of configurations, like I do all my changes. I have my own automated test bench to do this. What options caused it to crash and what about the change to rate-submit.c is nonsensical? |
Just run: ./fio t/jobs/t0013.fio and it'll insta-crash. |
Reproduced. I don't know how I added that line to rate-submit.c without seeing the obvious terminating value issue for I was more perplexed how my test runs didn't catch it. Turns out it only faults when
To prevent others from making my same careless mistake I'd like to propose changing |
Option 1 seems nicer. Even if efficiency isn't THAT important so we could tolerate just clearing it, it'd still just crash rather than be safe by design. |
@axboe Thanks. I wanted to give both
Even if we wanted to only restrict the scope of
To work around this i must be initialized outside the for() loop initializer:
Which is fine but not beautiful. Next issue: Every snippet which uses It's doable but comes down to style and whether the juice is worth the squeeze. The alternative is the original option 2, where we assure |
@axboe, Here is the corrected fix for the original issue. Would you like me to create a new pull request or can you pull it from it from my branch? |
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine, since the scope will be different). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope both both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each_td() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each_td() The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) That bug is corrected as part of this commit.
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine, since the scope will be different). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope both both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each_td() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each_td() The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) That bug is corrected as part of this commit. Signed-off-by: Adam Horshack (horshack@live.com)
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine because the scopes are separate). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope for both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each_td() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each_td() The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope of the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) That bug is corrected as part of this commit. Signed-off-by: Adam Horshack (horshack@live.com)
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine because the scopes are separate). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope for both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each_td() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each_td() The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td, i) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope of the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) That bug is corrected as part of this commit. Signed-off-by: Adam Horshack (horshack@live.com)
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine because the scopes are separate). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope for both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each(); The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope of the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) Signed-off-by: Adam Horshack (horshack@live.com)
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine because the scopes are separate). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope for both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each(); The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope of the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) Signed-off-by: Adam Horshack (horshack@live.com)
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine because the scopes are separate). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope for both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each(); The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope of the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) Signed-off-by: Adam Horshack (horshack@live.com)
I recently introduced a bug caused by reusing a struct thread_data *td after the end of a for_each_td() loop construct. Link: axboe#1521 (comment) To prevent others from making this same mistake, this commit refactors for_each_td() so that both the struct thread_data * and the loop index variable are placed inside their own scope for the loop. This will cause any reference to those variables outside the for_each_td() to produce an undeclared identifier error, provided the outer scope doesn't already reuse those same variable names for other code within the routine (which is fine because the scopes are separate). Because C/C++ doesn't let you declare two different variable types within the scope of a for() loop initializer, creating a scope for both struct thread_data * and the loop index required explicitly declaring a scope with a curly brace. This means for_each_td() includes an opening curly brace to create the scope, which means all uses of for_each_td() must now end with an invocation of a new macro named end_for_each() to emit an ending curly brace to match the scope brace created by for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); } end_for_each(); The alternative is to end every for_each_td() construct with an inline curly brace, which is off-putting since the implementation of an extra opening curly brace is abstracted in for_each_td(): for_each_td(td) { while (td->runstate < TD_EXITED) sleep(1); }} Most fio logic only declares "struct thread_data *td" and "int i" for use in for_each_td(), which means those declarations will now cause -Wunused-variable warnings since they're not used outside the scope of the refactored for_each_td(). Those declarations have been removed. Implementing this change caught a latent bug in eta.c::calc_thread_status() that accesses the ending value of struct thread_data *td after the end of for_each_td(), now manifesting as a compile error, so working as designed :) Signed-off-by: Adam Horshack (horshack@live.com)
Assertion in ioengines.c::td_io_queue() fails for pthread_mutex_unlock() on overlap_check mutex when serialize_overlap=1, io_submit_mode=offload, and verify= are used together.
backend.c::fio_io_sync() invokes td_io_queue(), which expects the caller to have ownership of the overlap_check mutex when serialize_overlap and offloading are configured, as part of the overlap-check interlock with IO_U_F_FLIGHT. The mutex is not acquired for this path because it's not an I/O requiring an overlap check.
The fix is to refine the conditional that triggers td_io_queue() to release the overlap_check mutex. Rather than using broad config options, the conditional now uses a new io_u flag named IO_U_F_OVERLAP_LOCK, which is only set for the offload worker thread path that acquires the mutex.
Link: #1520
Signed-off-by: Adam Horshack (horshack@live.com)