[lkml]   [2020]   [Mar]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
Subject[PATCH 5.4 110/168] dm zoned: Fix reference counter initial value of chunk works
From: Shin'ichiro Kawasaki <>

commit ee63634bae02e13c8c0df1209a6a0ca5326f3189 upstream.

Dm-zoned initializes reference counters of new chunk works with zero
value and refcount_inc() is called to increment the counter. However, the
refcount_inc() function handles the addition to zero value as an error
and triggers the warning as follows:

refcount_t: addition on 0; use-after-free.
WARNING: CPU: 7 PID: 1506 at lib/refcount.c:25 refcount_warn_saturate+0x68/0xf0
CPU: 7 PID: 1506 Comm: systemd-udevd Not tainted 5.4.0+ #134
Call Trace:
dmz_map+0x2d2/0x350 [dm_zoned]
? kmem_cache_alloc+0x165/0x220
? generic_make_request_checks+0x2e7/0x680
? memcg_drain_all_list_lrus+0x1c0/0x1c0
? guard_bio_eod+0x2c/0x130
? bdev_evict_inode+0xf0/0xf0
? __seccomp_filter+0x7b/0x670

After this warning, following refcount API calls for the counter all fail
to change the counter value.

Fix this by setting the initial reference counter value not zero but one
for the new chunk works. Instead, do not call refcount_inc() via
dmz_get_chunk_work() for the new chunks works.

The failure was observed with linux version 5.4 with CONFIG_REFCOUNT_FULL
enabled. Refcount rework was merged to linux version 5.5 by the
commit 168829ad09ca ("Merge branch 'locking-core-for-linus' of
git://"). After this
commit, CONFIG_REFCOUNT_FULL was removed and the failure was observed
regardless of kernel configuration.

Linux version 4.20 merged the commit 092b5648760a ("dm zoned: target: use
refcount_t for dm zoned reference counters"). Before this commit, dm
zoned used atomic_t APIs which does not check addition to zero, then this
fix is not necessary.

Fixes: 092b5648760a ("dm zoned: target: use refcount_t for dm zoned reference counters")
Cc: # 5.4+
Signed-off-by: Shin'ichiro Kawasaki <>
Reviewed-by: Damien Le Moal <>
Signed-off-by: Mike Snitzer <>
Signed-off-by: Greg Kroah-Hartman <>

drivers/md/dm-zoned-target.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

--- a/drivers/md/dm-zoned-target.c
+++ b/drivers/md/dm-zoned-target.c
@@ -533,8 +533,9 @@ static int dmz_queue_chunk_work(struct d

/* Get the BIO chunk work. If one is not active yet, create one */
cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk);
- if (!cw) {
+ if (cw) {
+ dmz_get_chunk_work(cw);
+ } else {
/* Create a new chunk work */
cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
if (unlikely(!cw)) {
@@ -543,7 +544,7 @@ static int dmz_queue_chunk_work(struct d

INIT_WORK(&cw->work, dmz_chunk_work);
- refcount_set(&cw->refcount, 0);
+ refcount_set(&cw->refcount, 1);
cw->target = dmz;
cw->chunk = chunk;
@@ -556,7 +557,6 @@ static int dmz_queue_chunk_work(struct d

bio_list_add(&cw->bio_list, bio);
- dmz_get_chunk_work(cw);

if (queue_work(dmz->chunk_wq, &cw->work))

 \ /
  Last update: 2020-03-10 14:29    [W:0.732 / U:0.092 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site