/* * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker * * Licensed under the terms of the GNU GPL License version 2 * * Selftests for a few posix timers interface. * * Kernel loop code stolen from Steven Rostedt */ #include #include #include #include #include #include #include "../kselftest.h" #define DELAY 2 #define USECS_PER_SEC 1000000 static volatile int done; /* Busy loop in userspace to elapse ITIMER_VIRTUAL */ static void user_loop(void) { while (!done); } /* * Try to spend as much time as possible in kernelspace * to elapse ITIMER_PROF. */ static void kernel_loop(void) { void *addr = sbrk(0); int err = 0; while (!done && !err) { err = brk(addr + 4096); err |= brk(addr); } } /* * Sleep until ITIMER_REAL expiration. */ static void idle_loop(void) { pause(); } static void sig_handler(int nr) { done = 1; } /* * Check the expected timer expiration matches the GTOD elapsed delta since * we armed the timer. Keep a 0.5 sec error margin due to various jitter. */ static int check_diff(struct timeval start, struct timeval end) { long long diff; diff = end.tv_usec - start.tv_usec; diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC; if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) { printf("Diff too high: %lld..", diff); return -1; } return 0; } static int check_itimer(int which) { int err; struct timeval start, end; struct itimerval val = { .it_value.tv_sec = DELAY, }; printf("Check itimer "); if (which == ITIMER_VIRTUAL) printf("virtual... "); else if (which == ITIMER_PROF) printf("prof... "); else if (which == ITIMER_REAL) printf("real... "); fflush(stdout); done = 0; if (which == ITIMER_VIRTUAL) signal(SIGVTALRM, sig_handler); else if (which == ITIMER_PROF) signal(SIGPROF, sig_handler); else if (which == ITIMER_REAL) signal(SIGALRM, sig_handler); err = gettimeofday(&start, NULL); if (err < 0) { perror("Can't call gettimeofday()\n"); return -1; } err = setitimer(which, &val, NULL); if (err < 0) { perror("Can't set timer\n"); return -1; } if (which == ITIMER_VIRTUAL) user_loop(); else if (which == ITIMER_PROF) kernel_loop(); else if (which == ITIMER_REAL) idle_loop(); err = gettimeofday(&end, NULL); if (err < 0) { perror("Can't call gettimeofday()\n"); return -1; } if (!check_diff(start, end)) printf("[OK]\n"); else printf("[FAIL]\n"); return 0; } static int check_timer_create(int which) { int err; timer_t id; struct timeval start, end; struct itimerspec val = { .it_value.tv_sec = DELAY, }; printf("Check timer_create() "); if (which == CLOCK_THREAD_CPUTIME_ID) { printf("per thread... "); } else if (which == CLOCK_PROCESS_CPUTIME_ID) { printf("per process... "); } fflush(stdout); done = 0; err = timer_create(which, NULL, &id); if (err < 0) { perror("Can't create timer\n"); return -1; } signal(SIGALRM, sig_handler); err = gettimeofday(&start, NULL); if (err < 0) { perror("Can't call gettimeofday()\n"); return -1; } err = timer_settime(id, 0, &val, NULL); if (err < 0) { perror("Can't set timer\n"); return -1; } user_loop(); err = gettimeofday(&end, NULL); if (err < 0) { perror("Can't call gettimeofday()\n"); return -1; } if (!check_diff(start, end)) printf("[OK]\n"); else printf("[FAIL]\n"); return 0; } int main(int argc, char **argv) { printf("Testing posix timers. False negative may happen on CPU execution \n"); printf("based timers if other threads run on the CPU...\n"); if (check_itimer(ITIMER_VIRTUAL) < 0) return ksft_exit_fail(); if (check_itimer(ITIMER_PROF) < 0) return ksft_exit_fail(); if (check_itimer(ITIMER_REAL) < 0) return ksft_exit_fail(); if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) return ksft_exit_fail(); /* * It's unfortunately hard to reliably test a timer expiration * on parallel multithread cputime. We could arm it to expire * on DELAY * nr_threads, with nr_threads busy looping, then wait * the normal DELAY since the time is elapsing nr_threads faster. * But for that we need to ensure we have real physical free CPUs * to ensure true parallelism. So test only one thread until we * find a better solution. */ if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) return ksft_exit_fail(); return ksft_exit_pass(); } e='2'>stat only
authorIago Abal <mail@iagoabal.eu>2017-01-11 14:00:21 +0100
committerVinod Koul <vinod.koul@intel.com>2017-01-25 15:35:11 +0530
commit91539eb1fda2d530d3b268eef542c5414e54bf1a (patch)
tree960f5ca6342ad20837aff18aad6e8ecd7da32fd6 /fs/xfs/libxfs/xfs_dir2_priv.h
parent6610d0edf6dc7ee97e46ab3a538a565c79d26199 (diff)
dmaengine: pl330: fix double lock
The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'fs/xfs/libxfs/xfs_dir2_priv.h')