[PATCH] bdbuf: Fix race condition with sync active flag
Gedare Bloom
gedare at rtems.org
Thu Nov 27 15:49:23 UTC 2014
Looks OK. Need to apply to releases?
On Thu, Nov 27, 2014 at 8:43 AM, Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
> Bug report by Oleg Kravtsov:
>
> In rtems_bdbuf_swapout_processing() function there is the following
> lines:
>
> if (bdbuf_cache.sync_active && !transfered_buffers)
> {
>
> rtems_id sync_requester;
> rtems_bdbuf_lock_cache ();
> ...
>
> }
>
> Here access to bdbuf_cache.sync_active is not protected with anything.
> Imagine the following test case:
>
> 1. Task1 releases buffer(s) with bdbuf_release_modified() calls;
>
> 2. After a while swapout task starts and flushes all buffers;
>
> 3. In the end of that swapout flush we are before that part of code, and
> assume there is task switching (just before "if (bdbuf_cache.sync_active
> && !transfered_buffers)");
>
> 4. Some other task (with higher priority) does bdbuf_release_modified
> and rtems_bdbuf_syncdev().
>
> This task successfully gets both locks sync and pool (in
> rtems_bdbuf_syncdev() function), sets sync_active to true and starts
> waiting for RTEMS_BDBUF_TRANSFER_SYNC event with only sync lock got.
>
> 5. Task switching happens again and we are again before "if
> (bdbuf_cache.sync_active && !transfered_buffers)".
>
> As the result we check sync_active and we come inside that "if"
> statement.
>
> 6. The result is that we send RTEMS_BDBUF_TRANSFER_SYNC event! Though
> ALL modified messages of that task are not flushed yet!
>
> close #1485
> ---
> cpukit/libblock/src/bdbuf.c | 16 +++++++++++-----
> 1 file changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c
> index bae57e2..8ea8cba 100644
> --- a/cpukit/libblock/src/bdbuf.c
> +++ b/cpukit/libblock/src/bdbuf.c
> @@ -2749,10 +2749,16 @@ rtems_bdbuf_swapout_processing (unsigned long timer_delta,
> {
> rtems_bdbuf_swapout_worker* worker;
> bool transfered_buffers = false;
> + bool sync_active;
>
> rtems_bdbuf_lock_cache ();
>
> /*
> + * To set this to true you need the cache and the sync lock.
> + */
> + sync_active = bdbuf_cache.sync_active;
> +
> + /*
> * If a sync is active do not use a worker because the current code does not
> * cleaning up after. We need to know the buffers have been written when
> * syncing to release sync lock and currently worker threads do not return to
> @@ -2761,7 +2767,7 @@ rtems_bdbuf_swapout_processing (unsigned long timer_delta,
> * lock. The simplest solution is to get the main swap out task perform all
> * sync operations.
> */
> - if (bdbuf_cache.sync_active)
> + if (sync_active)
> worker = NULL;
> else
> {
> @@ -2773,14 +2779,14 @@ rtems_bdbuf_swapout_processing (unsigned long timer_delta,
>
> rtems_chain_initialize_empty (&transfer->bds);
> transfer->dd = BDBUF_INVALID_DEV;
> - transfer->syncing = bdbuf_cache.sync_active;
> + transfer->syncing = sync_active;
>
> /*
> * When the sync is for a device limit the sync to that device. If the sync
> * is for a buffer handle process the devices in the order on the sync
> * list. This means the dev is BDBUF_INVALID_DEV.
> */
> - if (bdbuf_cache.sync_active)
> + if (sync_active)
> transfer->dd = bdbuf_cache.sync_device;
>
> /*
> @@ -2799,7 +2805,7 @@ rtems_bdbuf_swapout_processing (unsigned long timer_delta,
> rtems_bdbuf_swapout_modified_processing (&transfer->dd,
> &bdbuf_cache.modified,
> &transfer->bds,
> - bdbuf_cache.sync_active,
> + sync_active,
> update_timers,
> timer_delta);
>
> @@ -2830,7 +2836,7 @@ rtems_bdbuf_swapout_processing (unsigned long timer_delta,
> transfered_buffers = true;
> }
>
> - if (bdbuf_cache.sync_active && !transfered_buffers)
> + if (sync_active && !transfered_buffers)
> {
> rtems_id sync_requester;
> rtems_bdbuf_lock_cache ();
> --
> 1.8.4.5
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list