aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/dmatest.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-23 12:28:16 -0500
committerTejun Heo <tj@kernel.org>2011-11-23 12:28:16 -0500
commitadfa543e7314b36ac55a40019977de6e47946dd7 (patch)
treeff307bc785d28f77783676b117ae89559668bd4e /drivers/dma/dmatest.c
parentec012476af73a1a8a82565a915e9b48c2e337878 (diff)
dmatest: don't use set_freezable_with_signal()
Commit 981ed70d8e (dmatest: make dmatest threads freezable) made dmatest kthread use set_freezable_with_signal(); however, the interface is scheduled to be removed in the next merge window. The problem is that unlike userland tasks there's no default place which handles signal pending state and it isn't clear who owns and/or is responsible for clearing TIF_SIGPENDING. For example, in the current code, try_to_freeze() clears TIF_SIGPENDING but it isn't sure whether it actually owns the TIF_SIGPENDING nor is it race-free - ie. the task may continue to run with TIF_SIGPENDING set after the freezable section. Unfortunately, we don't have wait_for_completion_freezable_timeout(). This patch open codes it and uses wait_event_freezable_timeout() instead and removes timeout reloading - wait_event_freezable_timeout() won't return across freezing events (currently racy but fix scheduled) and timer doesn't decrement while the task is in freezer. Although this does lose timer-reset-over-freezing, given that timeout is supposed to be long enough and failure to finish inside is considered irrecoverable, I don't think this is worth the complexity. While at it, move completion to outer scope and explain that we're ignoring dangling pointer problem after timeout. This should give slightly better chance at avoiding oops after timeout. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Dan Williams <dan.j.williams@intel.com> Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'drivers/dma/dmatest.c')
-rw-r--r--drivers/dma/dmatest.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index eb1d8641cf5c..2b8661b54eaf 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -214,9 +214,18 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
214 return error_count; 214 return error_count;
215} 215}
216 216
217static void dmatest_callback(void *completion) 217/* poor man's completion - we want to use wait_event_freezable() on it */
218struct dmatest_done {
219 bool done;
220 wait_queue_head_t *wait;
221};
222
223static void dmatest_callback(void *arg)
218{ 224{
219 complete(completion); 225 struct dmatest_done *done = arg;
226
227 done->done = true;
228 wake_up_all(done->wait);
220} 229}
221 230
222/* 231/*
@@ -235,7 +244,9 @@ static void dmatest_callback(void *completion)
235 */ 244 */
236static int dmatest_func(void *data) 245static int dmatest_func(void *data)
237{ 246{
247 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);
238 struct dmatest_thread *thread = data; 248 struct dmatest_thread *thread = data;
249 struct dmatest_done done = { .wait = &done_wait };
239 struct dma_chan *chan; 250 struct dma_chan *chan;
240 const char *thread_name; 251 const char *thread_name;
241 unsigned int src_off, dst_off, len; 252 unsigned int src_off, dst_off, len;
@@ -252,7 +263,7 @@ static int dmatest_func(void *data)
252 int i; 263 int i;
253 264
254 thread_name = current->comm; 265 thread_name = current->comm;
255 set_freezable_with_signal(); 266 set_freezable();
256 267
257 ret = -ENOMEM; 268 ret = -ENOMEM;
258 269
@@ -306,9 +317,6 @@ static int dmatest_func(void *data)
306 struct dma_async_tx_descriptor *tx = NULL; 317 struct dma_async_tx_descriptor *tx = NULL;
307 dma_addr_t dma_srcs[src_cnt]; 318 dma_addr_t dma_srcs[src_cnt];
308 dma_addr_t dma_dsts[dst_cnt]; 319 dma_addr_t dma_dsts[dst_cnt];
309 struct completion cmp;
310 unsigned long start, tmo, end = 0 /* compiler... */;
311 bool reload = true;
312 u8 align = 0; 320 u8 align = 0;
313 321
314 total_tests++; 322 total_tests++;
@@ -391,9 +399,9 @@ static int dmatest_func(void *data)
391 continue; 399 continue;
392 } 400 }
393 401
394 init_completion(&cmp); 402 done.done = false;
395 tx->callback = dmatest_callback; 403 tx->callback = dmatest_callback;
396 tx->callback_param = &cmp; 404 tx->callback_param = &done;
397 cookie = tx->tx_submit(tx); 405 cookie = tx->tx_submit(tx);
398 406
399 if (dma_submit_error(cookie)) { 407 if (dma_submit_error(cookie)) {
@@ -407,20 +415,20 @@ static int dmatest_func(void *data)
407 } 415 }
408 dma_async_issue_pending(chan); 416 dma_async_issue_pending(chan);
409 417
410 do { 418 wait_event_freezable_timeout(done_wait, done.done,
411 start = jiffies; 419 msecs_to_jiffies(timeout));
412 if (reload)
413 end = start + msecs_to_jiffies(timeout);
414 else if (end <= start)
415 end = start + 1;
416 tmo = wait_for_completion_interruptible_timeout(&cmp,
417 end - start);
418 reload = try_to_freeze();
419 } while (tmo == -ERESTARTSYS);
420 420
421 status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); 421 status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
422 422
423 if (tmo == 0) { 423 if (!done.done) {
424 /*
425 * We're leaving the timed out dma operation with
426 * dangling pointer to done_wait. To make this
427 * correct, we'll need to allocate wait_done for
428 * each test iteration and perform "who's gonna
429 * free it this time?" dancing. For now, just
430 * leave it dangling.
431 */
424 pr_warning("%s: #%u: test timed out\n", 432 pr_warning("%s: #%u: test timed out\n",
425 thread_name, total_tests - 1); 433 thread_name, total_tests - 1);
426 failed_tests++; 434 failed_tests++;