1. 06 11月, 2019 3 次提交
    • M
      dm snapshot: rework COW throttling to fix deadlock · a8afda77
      Mikulas Patocka 提交于
      [ Upstream commit b21555786f18cd77f2311ad89074533109ae3ffa ]
      
      Commit 721b1d98fb517a ("dm snapshot: Fix excessive memory usage and
      workqueue stalls") introduced a semaphore to limit the maximum number of
      in-flight kcopyd (COW) jobs.
      
      The implementation of this throttling mechanism is prone to a deadlock:
      
      1. One or more threads write to the origin device causing COW, which is
         performed by kcopyd.
      
      2. At some point some of these threads might reach the s->cow_count
         semaphore limit and block in down(&s->cow_count), holding a read lock
         on _origins_lock.
      
      3. Someone tries to acquire a write lock on _origins_lock, e.g.,
         snapshot_ctr(), which blocks because the threads at step (2) already
         hold a read lock on it.
      
      4. A COW operation completes and kcopyd runs dm-snapshot's completion
         callback, which ends up calling pending_complete().
         pending_complete() tries to resubmit any deferred origin bios. This
         requires acquiring a read lock on _origins_lock, which blocks.
      
         This happens because the read-write semaphore implementation gives
         priority to writers, meaning that as soon as a writer tries to enter
         the critical section, no readers will be allowed in, until all
         writers have completed their work.
      
         So, pending_complete() waits for the writer at step (3) to acquire
         and release the lock. This writer waits for the readers at step (2)
         to release the read lock and those readers wait for
         pending_complete() (the kcopyd thread) to signal the s->cow_count
         semaphore: DEADLOCK.
      
      The above was thoroughly analyzed and documented by Nikos Tsironis as
      part of his initial proposal for fixing this deadlock, see:
      https://www.redhat.com/archives/dm-devel/2019-October/msg00001.html
      
      Fix this deadlock by reworking COW throttling so that it waits without
      holding any locks. Add a variable 'in_progress' that counts how many
      kcopyd jobs are running. A function wait_for_in_progress() will sleep if
      'in_progress' is over the limit. It drops _origins_lock in order to
      avoid the deadlock.
      Reported-by: NGuruswamy Basavaiah <guru2018@gmail.com>
      Reported-by: NNikos Tsironis <ntsironis@arrikto.com>
      Reviewed-by: NNikos Tsironis <ntsironis@arrikto.com>
      Tested-by: NNikos Tsironis <ntsironis@arrikto.com>
      Fixes: 721b1d98fb51 ("dm snapshot: Fix excessive memory usage and workqueue stalls")
      Cc: stable@vger.kernel.org # v5.0+
      Depends-on: 4a3f111a73a8c ("dm snapshot: introduce account_start_copy() and account_end_copy()")
      Signed-off-by: NMikulas Patocka <mpatocka@redhat.com>
      Signed-off-by: NMike Snitzer <snitzer@redhat.com>
      Signed-off-by: NSasha Levin <sashal@kernel.org>
      a8afda77
    • M
      dm snapshot: introduce account_start_copy() and account_end_copy() · 223f1af6
      Mikulas Patocka 提交于
      [ Upstream commit a2f83e8b0c82c9500421a26c49eb198b25fcdea3 ]
      
      This simple refactoring moves code for modifying the semaphore cow_count
      into separate functions to prepare for changes that will extend these
      methods to provide for a more sophisticated mechanism for COW
      throttling.
      Signed-off-by: NMikulas Patocka <mpatocka@redhat.com>
      Reviewed-by: NNikos Tsironis <ntsironis@arrikto.com>
      Signed-off-by: NMike Snitzer <snitzer@redhat.com>
      Signed-off-by: NSasha Levin <sashal@kernel.org>
      223f1af6
    • S
      zram: fix race between backing_dev_show and backing_dev_store · 0ca37291
      Sasha Levin 提交于
      [ Upstream commit f7daefe4231e57381d92c2e2ad905a899c28e402 ]
      
      CPU0:				       CPU1:
      backing_dev_show		       backing_dev_store
          ......				   ......
          file = zram->backing_dev;
          down_read(&zram->init_lock);	   down_read(&zram->init_init_lock)
          file_path(file, ...);		   zram->backing_dev = backing_dev;
          up_read(&zram->init_lock);		   up_read(&zram->init_lock);
      
      gets the value of zram->backing_dev too early in backing_dev_show, which
      resultin the value being NULL at the beginning, and not NULL later.
      
      backtrace:
        d_path+0xcc/0x174
        file_path+0x10/0x18
        backing_dev_show+0x40/0xb4
        dev_attr_show+0x20/0x54
        sysfs_kf_seq_show+0x9c/0x10c
        kernfs_seq_show+0x28/0x30
        seq_read+0x184/0x488
        kernfs_fop_read+0x5c/0x1a4
        __vfs_read+0x44/0x128
        vfs_read+0xa0/0x138
        SyS_read+0x54/0xb4
      
      Link: http://lkml.kernel.org/r/1571046839-16814-1-git-send-email-chenwandun@huawei.comSigned-off-by: NChenwandun <chenwandun@huawei.com>
      Acked-by: NMinchan Kim <minchan@kernel.org>
      Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
      Cc: Jens Axboe <axboe@kernel.dk>
      Cc: <stable@vger.kernel.org>	[4.14+]
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      Signed-off-by: NSasha Levin <sashal@kernel.org>
      0ca37291
  2. 29 10月, 2019 37 次提交