Skip to content
  • Joe Thornber's avatar
    dm thin: fix rcu_read_lock being held in code that can sleep · b10ebd34
    Joe Thornber authored
    Commit c140e1c4
    
     ("dm thin: use per thin device deferred bio lists")
    introduced the use of an rculist for all active thin devices.  The use
    of rcu_read_lock() in process_deferred_bios() can result in a BUG if a
    dm_bio_prison_cell must be allocated as a side-effect of bio_detain():
    
     BUG: sleeping function called from invalid context at mm/mempool.c:203
     in_atomic(): 1, irqs_disabled(): 0, pid: 6, name: kworker/u8:0
     3 locks held by kworker/u8:0/6:
       #0:  ("dm-" "thin"){.+.+..}, at: [<ffffffff8106be42>] process_one_work+0x192/0x550
       #1:  ((&pool->worker)){+.+...}, at: [<ffffffff8106be42>] process_one_work+0x192/0x550
       #2:  (rcu_read_lock){.+.+..}, at: [<ffffffff816360b5>] do_worker+0x5/0x4d0
    
    We can't process deferred bios with the rcu lock held, since
    dm_bio_prison_cell allocation may block if the bio-prison's cell mempool
    is exhausted.
    
    To fix:
    
    - Introduce a refcount and completion field to each thin_c
    
    - Add thin_get/put methods for adjusting the refcount.  If the refcount
      hits zero then the completion is triggered.
    
    - Initialise refcount to 1 when creating thin_c
    
    - When iterating the active_thins list we thin_get() whilst the rcu
      lock is held.
    
    - After the rcu lock is dropped we process the deferred bios for that
      thin.
    
    - When destroying a thin_c we thin_put() and then wait for the
      completion -- to avoid a race between the worker thread iterating
      from that thin_c and destroying the thin_c.
    
    Signed-off-by: default avatarJoe Thornber <ejt@redhat.com>
    Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
    b10ebd34