• Nikos Tsironis's avatar
    dm kcopyd: Fix bug causing workqueue stalls · d7e6b8df
    Nikos Tsironis authored
    When using kcopyd to run callbacks through dm_kcopyd_do_callback() or
    submitting copy jobs with a source size of 0, the jobs are pushed
    directly to the complete_jobs list, which could be under processing by
    the kcopyd thread. As a result, the kcopyd thread can continue running
    completed jobs indefinitely, without releasing the CPU, as long as
    someone keeps submitting new completed jobs through the aforementioned
    paths. Processing of work items, queued for execution on the same CPU as
    the currently running kcopyd thread, is thus stalled for excessive
    amounts of time, hurting performance.
    
    Running the following test, from the device mapper test suite [1],
    
      dmtest run --suite snapshot -n parallel_io_to_many_snaps_N
    
    , with 8 active snapshots, we get, in dmesg, messages like the
    following:
    
    [68899.948523] BUG: workqueue lockup - pool cpus=0 node=0 flags=0x0 nice=0 stuck for 95s!
    [68899.949282] Showing busy workqueues and worker pools:
    [68899.949288] workqueue events: flags=0x0
    [68899.949295]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=2/256
    [68899.949306]     pending: vmstat_shepherd, cache_reap
    [68899.949331] workqueue mm_percpu_wq: flags=0x8
    [68899.949337]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=1/256
    [68899.949345]     pending: vmstat_update
    [68899.949387] workqueue dm_bufio_cache: flags=0x8
    [68899.949392]   pwq 4: cpus=2 node=0 flags=0x0 nice=0 active=1/256
    [68899.949400]     pending: work_fn [dm_bufio]
    [68899.949423] workqueue kcopyd: flags=0x8
    [68899.949429]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=1/256
    [68899.949437]     pending: do_work [dm_mod]
    [68899.949452] workqueue kcopyd: flags=0x8
    [68899.949458]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=2/256
    [68899.949466]     in-flight: 13:do_work [dm_mod]
    [68899.949474]     pending: do_work [dm_mod]
    [68899.949487] workqueue kcopyd: flags=0x8
    [68899.949493]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=1/256
    [68899.949501]     pending: do_work [dm_mod]
    [68899.949515] workqueue kcopyd: flags=0x8
    [68899.949521]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=1/256
    [68899.949529]     pending: do_work [dm_mod]
    [68899.949541] workqueue kcopyd: flags=0x8
    [68899.949547]   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=1/256
    [68899.949555]     pending: do_work [dm_mod]
    [68899.949568] pool 0: cpus=0 node=0 flags=0x0 nice=0 hung=95s workers=4 idle: 27130 27223 1084
    
    Fix this by splitting the complete_jobs list into two parts: A user
    facing part, named callback_jobs, and one used internally by kcopyd,
    retaining the name complete_jobs. dm_kcopyd_do_callback() and
    dispatch_job() now push their jobs to the callback_jobs list, which is
    spliced to the complete_jobs list once, every time the kcopyd thread
    wakes up. This prevents kcopyd from hogging the CPU indefinitely and
    causing workqueue stalls.
    
    Re-running the aforementioned test:
    
      * Workqueue stalls are eliminated
      * The maximum writing time among all targets is reduced from 09m37.10s
        to 06m04.85s and the total run time of the test is reduced from
        10m43.591s to 7m19.199s
    
    [1] https://github.com/jthornber/device-mapper-test-suiteSigned-off-by: default avatarNikos Tsironis <ntsironis@arrikto.com>
    Signed-off-by: default avatarIlias Tsitsimpis <iliastsi@arrikto.com>
    Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
    d7e6b8df
dm-kcopyd.c 20.8 KB