Received: by 10.223.185.116 with SMTP id b49csp6403724wrg; Wed, 28 Feb 2018 08:51:26 -0800 (PST) X-Google-Smtp-Source: AG47ELu6/WAOnV3KMk4IF0zXjyGl89ebnihctPNk/y9bIBVgIwEGBGjRx+swavCvH0U5u2m85ZUi X-Received: by 10.98.249.10 with SMTP id o10mr5806097pfh.222.1519836686075; Wed, 28 Feb 2018 08:51:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519836686; cv=none; d=google.com; s=arc-20160816; b=K0Lg5/eFuIn2Ui7pFiQdsj3JVXy1UYzH6jOLuUKExN0fhaxqsObVah5/3ew3BFFmx1 5HGmAnPHDigHYkVYz5Pw3fifCc1or6MylvsrGOt0Y3bjp1fwrRmhewtwY98wJg6ud1TJ IHg/UBvij6cXe3mK6Evj1zv3tUWdBh9CJBDy04ZUe01sfi7q1NXQlUUIFYDsBibC7fUe Rn6WXlF6i1ejDCvYjZr7V1tn4J1Wf8rLEN33F9qwfYBdiqX+5pVVn4P2XALXaKAIl+Zy alBk82tnYT0NyR75jhf6igrI+d1+WXl/CmIqbx0ugKbhIzxErlDA+Siy1Wh+E6LIZGDM KHHw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:subject:message-id:date:cc:to :from:mime-version:content-transfer-encoding:content-disposition :arc-authentication-results; bh=5b8RlMT5qbfga2910LG4czP84WEW3Czm51sXzD/MwWk=; b=XSu3z/DQa7aAsrtQ98dox+dOQ+UHMuO0FK17dr016BpffVmpl0AMfzC2snR5yo3UAx eBYRRGg7phkCWWP/FVwKiE9S7x/pJZy9edb9+GORV59v6JGyOFH/g5FPptat1pthSd94 AjFJFKF0iIO19ytgWERgR50uCCoLybRbUTatHYbwPqONYfvXgLyQoosPsrKadDcUZWaV 5rMy4RkLjtiS6ssXwaPmOlY3LcZyGshAjfarDLmIIqLBx6VjbAKzFYwubJiZb08w1cOQ l1K3WUoB1ffREQhz1JmDrAjmVaBkYaGedHJyJqTz88AVl7D4kGsy749ue661uu5H8Ja3 d+6Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m12-v6si1523601pln.400.2018.02.28.08.51.10; Wed, 28 Feb 2018 08:51:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934261AbeB1P6f (ORCPT + 99 others); Wed, 28 Feb 2018 10:58:35 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:34563 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934242AbeB1P63 (ORCPT ); Wed, 28 Feb 2018 10:58:29 -0500 Received: from [2a02:8011:400e:2:6f00:88c8:c921:d332] (helo=deadeye) by shadbolt.decadent.org.uk with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1er3Yf-0006Xg-IN; Wed, 28 Feb 2018 15:22:17 +0000 Received: from ben by deadeye with local (Exim 4.90_1) (envelope-from ) id 1er3Ye-0008RM-IB; Wed, 28 Feb 2018 15:22:16 +0000 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Mike Snitzer" , "monty_pavel@sina.com" Date: Wed, 28 Feb 2018 15:20:18 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.16 054/254] dm: fix various targets to dm_register_target after module __init resources created In-Reply-To: X-SA-Exim-Connect-IP: 2a02:8011:400e:2:6f00:88c8:c921:d332 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.16.55-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: "monty_pavel@sina.com" commit 7e6358d244e4706fe612a77b9c36519a33600ac0 upstream. A NULL pointer is seen if two concurrent "vgchange -ay -K " processes race to load the dm-thin-pool module: PID: 25992 TASK: ffff883cd7d23500 CPU: 4 COMMAND: "vgchange" #0 [ffff883cd743d600] machine_kexec at ffffffff81038fa9 0000001 [ffff883cd743d660] crash_kexec at ffffffff810c5992 0000002 [ffff883cd743d730] oops_end at ffffffff81515c90 0000003 [ffff883cd743d760] no_context at ffffffff81049f1b 0000004 [ffff883cd743d7b0] __bad_area_nosemaphore at ffffffff8104a1a5 0000005 [ffff883cd743d800] bad_area at ffffffff8104a2ce 0000006 [ffff883cd743d830] __do_page_fault at ffffffff8104aa6f 0000007 [ffff883cd743d950] do_page_fault at ffffffff81517bae 0000008 [ffff883cd743d980] page_fault at ffffffff81514f95 [exception RIP: kmem_cache_alloc+108] RIP: ffffffff8116ef3c RSP: ffff883cd743da38 RFLAGS: 00010046 RAX: 0000000000000004 RBX: ffffffff81121b90 RCX: ffff881bf1e78cc0 RDX: 0000000000000000 RSI: 00000000000000d0 RDI: 0000000000000000 RBP: ffff883cd743da68 R8: ffff881bf1a4eb00 R9: 0000000080042000 R10: 0000000000002000 R11: 0000000000000000 R12: 00000000000000d0 R13: 0000000000000000 R14: 00000000000000d0 R15: 0000000000000246 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 0000009 [ffff883cd743da70] mempool_alloc_slab at ffffffff81121ba5 0000010 [ffff883cd743da80] mempool_create_node at ffffffff81122083 0000011 [ffff883cd743dad0] mempool_create at ffffffff811220f4 0000012 [ffff883cd743dae0] pool_ctr at ffffffffa08de049 [dm_thin_pool] 0000013 [ffff883cd743dbd0] dm_table_add_target at ffffffffa0005f2f [dm_mod] 0000014 [ffff883cd743dc30] table_load at ffffffffa0008ba9 [dm_mod] 0000015 [ffff883cd743dc90] ctl_ioctl at ffffffffa0009dc4 [dm_mod] The race results in a NULL pointer because: Process A (vgchange -ay -K): a. send DM_LIST_VERSIONS_CMD ioctl; b. pool_target not registered; c. modprobe dm_thin_pool and wait until end. Process B (vgchange -ay -K): a. send DM_LIST_VERSIONS_CMD ioctl; b. pool_target registered; c. table_load->dm_table_add_target->pool_ctr; d. _new_mapping_cache is NULL and panic. Note: 1. process A and process B are two concurrent processes. 2. pool_target can be detected by process B but _new_mapping_cache initialization has not ended. To fix dm-thin-pool, and other targets (cache, multipath, and snapshot) with the same problem, simply dm_register_target() after all resources created during module init (as labelled with __init) are finished. Signed-off-by: monty Signed-off-by: Mike Snitzer [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings --- drivers/md/dm-cache-target.c | 12 +++++------ drivers/md/dm-mpath.c | 18 ++++++++--------- drivers/md/dm-snap.c | 48 ++++++++++++++++++++++---------------------- drivers/md/dm-thin.c | 22 +++++++++----------- 4 files changed, 49 insertions(+), 51 deletions(-) --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -3108,18 +3108,18 @@ static int __init dm_cache_init(void) { int r; - r = dm_register_target(&cache_target); - if (r) { - DMERR("cache target registration failed: %d", r); - return r; - } - migration_cache = KMEM_CACHE(dm_cache_migration, 0); if (!migration_cache) { dm_unregister_target(&cache_target); return -ENOMEM; } + r = dm_register_target(&cache_target); + if (r) { + DMERR("cache target registration failed: %d", r); + return r; + } + return 0; } --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1688,13 +1688,6 @@ static int __init dm_multipath_init(void if (!_mpio_cache) return -ENOMEM; - r = dm_register_target(&multipath_target); - if (r < 0) { - DMERR("register failed %d", r); - r = -EINVAL; - goto bad_register_target; - } - kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); if (!kmultipathd) { DMERR("failed to create workqueue kmpathd"); @@ -1716,17 +1709,24 @@ static int __init dm_multipath_init(void goto bad_alloc_kmpath_handlerd; } + r = dm_register_target(&multipath_target); + if (r < 0) { + DMERR("register failed %d", r); + r = -EINVAL; + goto bad_register_target; + } + DMINFO("version %u.%u.%u loaded", multipath_target.version[0], multipath_target.version[1], multipath_target.version[2]); return 0; +bad_register_target: + destroy_workqueue(kmpath_handlerd); bad_alloc_kmpath_handlerd: destroy_workqueue(kmultipathd); bad_alloc_kmultipathd: - dm_unregister_target(&multipath_target); -bad_register_target: kmem_cache_destroy(_mpio_cache); return r; --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -2404,24 +2404,6 @@ static int __init dm_snapshot_init(void) return r; } - r = dm_register_target(&snapshot_target); - if (r < 0) { - DMERR("snapshot target register failed %d", r); - goto bad_register_snapshot_target; - } - - r = dm_register_target(&origin_target); - if (r < 0) { - DMERR("Origin target register failed %d", r); - goto bad_register_origin_target; - } - - r = dm_register_target(&merge_target); - if (r < 0) { - DMERR("Merge target register failed %d", r); - goto bad_register_merge_target; - } - r = init_origin_hash(); if (r) { DMERR("init_origin_hash failed."); @@ -2442,19 +2424,37 @@ static int __init dm_snapshot_init(void) goto bad_pending_cache; } + r = dm_register_target(&snapshot_target); + if (r < 0) { + DMERR("snapshot target register failed %d", r); + goto bad_register_snapshot_target; + } + + r = dm_register_target(&origin_target); + if (r < 0) { + DMERR("Origin target register failed %d", r); + goto bad_register_origin_target; + } + + r = dm_register_target(&merge_target); + if (r < 0) { + DMERR("Merge target register failed %d", r); + goto bad_register_merge_target; + } + return 0; -bad_pending_cache: - kmem_cache_destroy(exception_cache); -bad_exception_cache: - exit_origin_hash(); -bad_origin_hash: - dm_unregister_target(&merge_target); bad_register_merge_target: dm_unregister_target(&origin_target); bad_register_origin_target: dm_unregister_target(&snapshot_target); bad_register_snapshot_target: + kmem_cache_destroy(pending_cache); +bad_pending_cache: + kmem_cache_destroy(exception_cache); +bad_exception_cache: + exit_origin_hash(); +bad_origin_hash: dm_exception_store_exit(); return r; --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3521,30 +3521,28 @@ static struct target_type thin_target = static int __init dm_thin_init(void) { - int r; + int r = -ENOMEM; pool_table_init(); + _new_mapping_cache = KMEM_CACHE(dm_thin_new_mapping, 0); + if (!_new_mapping_cache) + return r; + r = dm_register_target(&thin_target); if (r) - return r; + goto bad_new_mapping_cache; r = dm_register_target(&pool_target); if (r) - goto bad_pool_target; - - r = -ENOMEM; - - _new_mapping_cache = KMEM_CACHE(dm_thin_new_mapping, 0); - if (!_new_mapping_cache) - goto bad_new_mapping_cache; + goto bad_thin_target; return 0; -bad_new_mapping_cache: - dm_unregister_target(&pool_target); -bad_pool_target: +bad_thin_target: dm_unregister_target(&thin_target); +bad_new_mapping_cache: + kmem_cache_destroy(_new_mapping_cache); return r; }