Changeset f0f2a3d in rtems


Ignore:
Timestamp:
Nov 27, 2014, 1:41:17 PM (5 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.10
Children:
0863e8e3
Parents:
7d015db0
git-author:
Sebastian Huber <sebastian.huber@…> (11/27/14 13:41:17)
git-committer:
Sebastian Huber <sebastian.huber@…> (11/28/14 10:15:18)
Message:

bdbuf: Fix race condition with sync active flag

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;
  1. After a while swapout task starts and flushes all buffers;
  1. 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)");

  1. 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.

  1. 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.

  1. The result is that we send RTEMS_BDBUF_TRANSFER_SYNC event! Though

ALL modified messages of that task are not flushed yet!

close #1485

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libblock/src/bdbuf.c

    r7d015db0 rf0f2a3d  
    25352535  rtems_bdbuf_swapout_worker* worker;
    25362536  bool                        transfered_buffers = false;
     2537  bool                        sync_active;
    25372538
    25382539  rtems_bdbuf_lock_cache ();
     2540
     2541  /*
     2542   * To set this to true you need the cache and the sync lock.
     2543   */
     2544  sync_active = bdbuf_cache.sync_active;
    25392545
    25402546  /*
     
    25472553   * sync operations.
    25482554   */
    2549   if (bdbuf_cache.sync_active)
     2555  if (sync_active)
    25502556    worker = NULL;
    25512557  else
     
    25592565  rtems_chain_initialize_empty (&transfer->bds);
    25602566  transfer->dev = BDBUF_INVALID_DEV;
    2561   transfer->syncing = bdbuf_cache.sync_active;
    2562  
     2567  transfer->syncing = sync_active;
     2568
    25632569  /*
    25642570   * When the sync is for a device limit the sync to that device. If the sync
     
    25662572   * list. This means the dev is BDBUF_INVALID_DEV.
    25672573   */
    2568   if (bdbuf_cache.sync_active)
     2574  if (sync_active)
    25692575    transfer->dev = bdbuf_cache.sync_device;
    2570    
     2576
    25712577  /*
    25722578   * If we have any buffers in the sync queue move them to the modified
     
    25852591                                           &bdbuf_cache.modified,
    25862592                                           &transfer->bds,
    2587                                            bdbuf_cache.sync_active,
     2593                                           sync_active,
    25882594                                           update_timers,
    25892595                                           timer_delta);
     
    26162622  }
    26172623
    2618   if (bdbuf_cache.sync_active && !transfered_buffers)
     2624  if (sync_active && !transfered_buffers)
    26192625  {
    26202626    rtems_id sync_requester;
Note: See TracChangeset for help on using the changeset viewer.