Received: by 2002:a05:7412:d8a:b0:e2:908c:2ebd with SMTP id b10csp81428rdg; Tue, 10 Oct 2023 05:04:35 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGqgUaPgGI556Ej4liuFER3gs7HcC2AN7zFM88aZ8L0EFKZPLaCHZ8yiCkLGKWnVQrG2MON X-Received: by 2002:a05:6358:88f:b0:135:47e8:76e2 with SMTP id m15-20020a056358088f00b0013547e876e2mr22586448rwj.4.1696939475394; Tue, 10 Oct 2023 05:04:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1696939475; cv=none; d=google.com; s=arc-20160816; b=v7pIllS2okN+OuPJK/yS+LMNUSl1R1hS0N1UT/+cNGo+T8l4nFrb/5mudO7eOTXTKT GSgeY4v1cTLQEvSJQuDvK2uFKvpxuOwFqKqhxqlfg2zdfjBgHIBAUKbkk9pmbLUHilg4 L2RlWWsZRhMrvqgG8QT5emlFf3uEYPqv4Fmvwy73BQ7H+kfuQvzHaw2xHX2R/rWBxSeY 3z6zoO+FEIsF6uBU7Nz0me12qwSAza9WIK5vNeTvP9DvIjEs9XBKT2lTlRSiGdBbMauz 9PfviYjTL2VXhDpBWvFADVrYNp+SoCF3q/t2ainQ1+b8jyrl/lZkVvAmshl2yPYkXZfP vQvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:in-reply-to :organization:from:references:cc:to:content-language:subject :user-agent:mime-version:date:message-id:dkim-signature; bh=kn3Sm/V2VVNLCw+r9D4hL0wnnNRO3TvuxExHK7/iZ64=; fh=5rCvKDnyWYNc2e4XeRxkYTLUMnJuJRqjaZWJB9/JtsI=; b=D6kfsJ+lrp0l+UoXGekelaNYWLlvAPxHTce7MRro3kqoXLnsSwMN8y8xWm0V6r3r/1 VBsRc0t7WwdqahRCwWPK2C89i0E83KSPgvwFbRm75e9yRD4MAgtbbrtF45wyeiYp4Mv3 4VyHFpPGSPpWfbt6FeELkJ7qRlYTrMFMeHZwdcTl0JPuy6zYlZtDu/9AIj3GZHoYADBM KGY9uKvyevrbS5TDSVzhoFIL7TD/P23rLqVaHVEL+jz5YtoNvBIzuqWwWr8GyRVfssuO M7Twj7EScP6T0m/vvIlHifSkCBtrOeT2i3lJxoKVIsHLikAf/hnEM6BAOb8WsIpGwTm4 vTwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=FPe2+V1h; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.34 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from howler.vger.email (howler.vger.email. [23.128.96.34]) by mx.google.com with ESMTPS id x185-20020a6386c2000000b00578bea3c10esi11056697pgd.756.2023.10.10.05.04.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Oct 2023 05:04:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.34 as permitted sender) client-ip=23.128.96.34; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=FPe2+V1h; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.34 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by howler.vger.email (Postfix) with ESMTP id 64AF280241AB; Tue, 10 Oct 2023 05:04:31 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at howler.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231348AbjJJMEA (ORCPT + 99 others); Tue, 10 Oct 2023 08:04:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46242 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231861AbjJJMDq (ORCPT ); Tue, 10 Oct 2023 08:03:46 -0400 Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.88]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DDCDB11F for ; Tue, 10 Oct 2023 05:03:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1696939383; x=1728475383; h=message-id:date:mime-version:subject:to:cc:references: from:in-reply-to:content-transfer-encoding; bh=a4c3M+Jokf+rlTYMTvfK4kVpcRX4L5tV26F4pNU+sFo=; b=FPe2+V1h6IPrpWc4xOsmOd7DRRLAEfapJpgKLhdVQL7YFYQHcDtdN1Pd qSyH4bJLfNBF09h00DOcA6fKB97Y5w3cR5Z2nE1d1ytpmvKgl3kNnjZzJ lvLZ/UNtB8ciO+iXFevm+n9kFSCORqFY9SZ2kCXvsV+MoacXBUqLzHvmE Rxu3zpWQpY3BqaC0MOiIFywuS0QIz0356qlhNMgGvMrDXbgOBgWuSmMT6 Cm7maaa5T3CelwMpEAwEnoeYnVeTitWp8fU2eoyHiHpfDL2w6EkbgmZ7E SmKElHsNZYqNayYDUuDjfIm7nALjkF4+E7OTh3S72Tu7oLoslqcddDxjg Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10858"; a="415382895" X-IronPort-AV: E=Sophos;i="6.03,212,1694761200"; d="scan'208";a="415382895" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2023 05:02:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10858"; a="819214237" X-IronPort-AV: E=Sophos;i="6.03,212,1694761200"; d="scan'208";a="819214237" Received: from ahajda-mobl.ger.corp.intel.com (HELO [10.213.14.169]) ([10.213.14.169]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2023 05:02:57 -0700 Message-ID: Date: Tue, 10 Oct 2023 14:02:54 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v2] debugobjects: stop accessing objects after releasing spinlock Content-Language: en-US To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-mm@kvack.org, Thomas Gleixner Cc: Andi Shyti , Nirmoy Das , Janusz Krzysztofik References: <20230925131359.2948827-1-andrzej.hajda@intel.com> From: Andrzej Hajda Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 In-Reply-To: <20230925131359.2948827-1-andrzej.hajda@intel.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=2.7 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_SBL_CSS,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on howler.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (howler.vger.email [0.0.0.0]); Tue, 10 Oct 2023 05:04:31 -0700 (PDT) X-Spam-Level: ** On 25.09.2023 15:13, Andrzej Hajda wrote: > After spinlock release object can be modified/freed by concurrent thread. > Using it in such case is error prone, even for printing object state. > To avoid such situation local copy of the object is created if necessary. > > Signed-off-by: Andrzej Hajda > --- > v2: add missing switch breaks > --- Ping, any volunteer to review? Regards Andrzej > lib/debugobjects.c | 206 +++++++++++++++++++++------------------------ > 1 file changed, 97 insertions(+), 109 deletions(-) > > diff --git a/lib/debugobjects.c b/lib/debugobjects.c > index a517256a270b71..3afff2f668fc1e 100644 > --- a/lib/debugobjects.c > +++ b/lib/debugobjects.c > @@ -620,9 +620,8 @@ static void debug_objects_fill_pool(void) > static void > __debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack) > { > - enum debug_obj_state state; > struct debug_bucket *db; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > unsigned long flags; > > debug_objects_fill_pool(); > @@ -644,23 +643,19 @@ __debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack > case ODEBUG_STATE_INACTIVE: > obj->state = ODEBUG_STATE_INIT; > break; > - > - case ODEBUG_STATE_ACTIVE: > - state = obj->state; > - raw_spin_unlock_irqrestore(&db->lock, flags); > - debug_print_object(obj, "init"); > - debug_object_fixup(descr->fixup_init, addr, state); > - return; > - > - case ODEBUG_STATE_DESTROYED: > - raw_spin_unlock_irqrestore(&db->lock, flags); > - debug_print_object(obj, "init"); > - return; > default: > - break; > + o = *obj; > + obj = NULL; > } > > raw_spin_unlock_irqrestore(&db->lock, flags); > + > + if (obj) > + return; > + > + debug_print_object(&o, "init"); > + if (o.state == ODEBUG_STATE_ACTIVE) > + debug_object_fixup(descr->fixup_init, addr, o.state); > } > > /** > @@ -700,12 +695,9 @@ EXPORT_SYMBOL_GPL(debug_object_init_on_stack); > */ > int debug_object_activate(void *addr, const struct debug_obj_descr *descr) > { > - struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; > - enum debug_obj_state state; > struct debug_bucket *db; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > unsigned long flags; > - int ret; > > if (!debug_objects_enabled) > return 0; > @@ -717,49 +709,47 @@ int debug_object_activate(void *addr, const struct debug_obj_descr *descr) > raw_spin_lock_irqsave(&db->lock, flags); > > obj = lookup_object_or_alloc(addr, db, descr, false, true); > - if (likely(!IS_ERR_OR_NULL(obj))) { > - bool print_object = false; > - > + if (unlikely(!obj)) { > + raw_spin_unlock_irqrestore(&db->lock, flags); > + debug_objects_oom(); > + return 0; > + } else if (likely(!IS_ERR(obj))) { > switch (obj->state) { > case ODEBUG_STATE_INIT: > case ODEBUG_STATE_INACTIVE: > obj->state = ODEBUG_STATE_ACTIVE; > - ret = 0; > break; > - > case ODEBUG_STATE_ACTIVE: > - state = obj->state; > - raw_spin_unlock_irqrestore(&db->lock, flags); > - debug_print_object(obj, "activate"); > - ret = debug_object_fixup(descr->fixup_activate, addr, state); > - return ret ? 0 : -EINVAL; > - > case ODEBUG_STATE_DESTROYED: > - print_object = true; > - ret = -EINVAL; > + o = *obj; > + obj = NULL; > break; > default: > - ret = 0; > break; > } > - raw_spin_unlock_irqrestore(&db->lock, flags); > - if (print_object) > - debug_print_object(obj, "activate"); > - return ret; > + } else { > + o.object = addr; > + o.state = ODEBUG_STATE_NOTAVAILABLE; > + o.descr = descr; > + obj = NULL; > } > > raw_spin_unlock_irqrestore(&db->lock, flags); > > - /* If NULL the allocation has hit OOM */ > - if (!obj) { > - debug_objects_oom(); > + if (obj) > return 0; > - } > > - /* Object is neither static nor tracked. It's not initialized */ > debug_print_object(&o, "activate"); > - ret = debug_object_fixup(descr->fixup_activate, addr, ODEBUG_STATE_NOTAVAILABLE); > - return ret ? 0 : -EINVAL; > + > + switch (o.state) { > + case ODEBUG_STATE_ACTIVE: > + case ODEBUG_STATE_NOTAVAILABLE: > + if (debug_object_fixup(descr->fixup_activate, addr, o.state)) > + return 0; > + fallthrough; > + default: > + return -EINVAL; > + } > } > EXPORT_SYMBOL_GPL(debug_object_activate); > > @@ -771,9 +761,8 @@ EXPORT_SYMBOL_GPL(debug_object_activate); > void debug_object_deactivate(void *addr, const struct debug_obj_descr *descr) > { > struct debug_bucket *db; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > unsigned long flags; > - bool print_object = false; > > if (!debug_objects_enabled) > return; > @@ -788,30 +777,29 @@ void debug_object_deactivate(void *addr, const struct debug_obj_descr *descr) > case ODEBUG_STATE_INIT: > case ODEBUG_STATE_INACTIVE: > case ODEBUG_STATE_ACTIVE: > - if (!obj->astate) > + if (!obj->astate) { > obj->state = ODEBUG_STATE_INACTIVE; > - else > - print_object = true; > - break; > - > + break; > + } > + fallthrough; > case ODEBUG_STATE_DESTROYED: > - print_object = true; > + o = *obj; > + obj = NULL; > break; > default: > break; > } > + } else { > + o.object = addr; > + o.state = ODEBUG_STATE_NOTAVAILABLE; > + o.descr = descr; > + obj = NULL; > } > > raw_spin_unlock_irqrestore(&db->lock, flags); > - if (!obj) { > - struct debug_obj o = { .object = addr, > - .state = ODEBUG_STATE_NOTAVAILABLE, > - .descr = descr }; > > + if (!obj) > debug_print_object(&o, "deactivate"); > - } else if (print_object) { > - debug_print_object(obj, "deactivate"); > - } > } > EXPORT_SYMBOL_GPL(debug_object_deactivate); > > @@ -822,11 +810,9 @@ EXPORT_SYMBOL_GPL(debug_object_deactivate); > */ > void debug_object_destroy(void *addr, const struct debug_obj_descr *descr) > { > - enum debug_obj_state state; > struct debug_bucket *db; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > unsigned long flags; > - bool print_object = false; > > if (!debug_objects_enabled) > return; > @@ -836,8 +822,10 @@ void debug_object_destroy(void *addr, const struct debug_obj_descr *descr) > raw_spin_lock_irqsave(&db->lock, flags); > > obj = lookup_object(addr, db); > - if (!obj) > - goto out_unlock; > + if (!obj) { > + raw_spin_unlock_irqrestore(&db->lock, flags); > + return; > + } > > switch (obj->state) { > case ODEBUG_STATE_NONE: > @@ -846,22 +834,23 @@ void debug_object_destroy(void *addr, const struct debug_obj_descr *descr) > obj->state = ODEBUG_STATE_DESTROYED; > break; > case ODEBUG_STATE_ACTIVE: > - state = obj->state; > - raw_spin_unlock_irqrestore(&db->lock, flags); > - debug_print_object(obj, "destroy"); > - debug_object_fixup(descr->fixup_destroy, addr, state); > - return; > - > case ODEBUG_STATE_DESTROYED: > - print_object = true; > + o = *obj; > + obj = NULL; > break; > default: > break; > } > -out_unlock: > + > raw_spin_unlock_irqrestore(&db->lock, flags); > - if (print_object) > - debug_print_object(obj, "destroy"); > + > + if (obj) > + return; > + > + debug_print_object(&o, "destroy"); > + > + if (o.state == ODEBUG_STATE_ACTIVE) > + debug_object_fixup(descr->fixup_destroy, addr, o.state); > } > EXPORT_SYMBOL_GPL(debug_object_destroy); > > @@ -872,9 +861,8 @@ EXPORT_SYMBOL_GPL(debug_object_destroy); > */ > void debug_object_free(void *addr, const struct debug_obj_descr *descr) > { > - enum debug_obj_state state; > struct debug_bucket *db; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > unsigned long flags; > > if (!debug_objects_enabled) > @@ -885,24 +873,29 @@ void debug_object_free(void *addr, const struct debug_obj_descr *descr) > raw_spin_lock_irqsave(&db->lock, flags); > > obj = lookup_object(addr, db); > - if (!obj) > - goto out_unlock; > + if (!obj) { > + raw_spin_unlock_irqrestore(&db->lock, flags); > + return; > + } > > switch (obj->state) { > case ODEBUG_STATE_ACTIVE: > - state = obj->state; > - raw_spin_unlock_irqrestore(&db->lock, flags); > - debug_print_object(obj, "free"); > - debug_object_fixup(descr->fixup_free, addr, state); > - return; > + o = *obj; > + obj = NULL; > + break; > default: > hlist_del(&obj->node); > - raw_spin_unlock_irqrestore(&db->lock, flags); > + } > + > + raw_spin_unlock_irqrestore(&db->lock, flags); > + > + if (obj) { > free_object(obj); > return; > } > -out_unlock: > - raw_spin_unlock_irqrestore(&db->lock, flags); > + > + debug_print_object(&o, "free"); > + debug_object_fixup(descr->fixup_free, addr, o.state); > } > EXPORT_SYMBOL_GPL(debug_object_free); > > @@ -955,9 +948,8 @@ debug_object_active_state(void *addr, const struct debug_obj_descr *descr, > unsigned int expect, unsigned int next) > { > struct debug_bucket *db; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > unsigned long flags; > - bool print_object = false; > > if (!debug_objects_enabled) > return; > @@ -970,28 +962,27 @@ debug_object_active_state(void *addr, const struct debug_obj_descr *descr, > if (obj) { > switch (obj->state) { > case ODEBUG_STATE_ACTIVE: > - if (obj->astate == expect) > + if (obj->astate == expect) { > obj->astate = next; > - else > - print_object = true; > - break; > - > + break; > + } > + fallthrough; > default: > - print_object = true; > + o = *obj; > + obj = NULL; > break; > } > + } else { > + o.object = addr; > + o.state = ODEBUG_STATE_NOTAVAILABLE; > + o.descr = descr; > + obj = NULL; > } > > raw_spin_unlock_irqrestore(&db->lock, flags); > - if (!obj) { > - struct debug_obj o = { .object = addr, > - .state = ODEBUG_STATE_NOTAVAILABLE, > - .descr = descr }; > > + if (!obj) > debug_print_object(&o, "active_state"); > - } else if (print_object) { > - debug_print_object(obj, "active_state"); > - } > } > EXPORT_SYMBOL_GPL(debug_object_active_state); > > @@ -999,11 +990,9 @@ EXPORT_SYMBOL_GPL(debug_object_active_state); > static void __debug_check_no_obj_freed(const void *address, unsigned long size) > { > unsigned long flags, oaddr, saddr, eaddr, paddr, chunks; > - const struct debug_obj_descr *descr; > - enum debug_obj_state state; > struct debug_bucket *db; > struct hlist_node *tmp; > - struct debug_obj *obj; > + struct debug_obj *obj, o; > int cnt, objs_checked = 0; > > saddr = (unsigned long) address; > @@ -1026,12 +1015,11 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size) > > switch (obj->state) { > case ODEBUG_STATE_ACTIVE: > - descr = obj->descr; > - state = obj->state; > + o = *obj; > raw_spin_unlock_irqrestore(&db->lock, flags); > - debug_print_object(obj, "free"); > - debug_object_fixup(descr->fixup_free, > - (void *) oaddr, state); > + debug_print_object(&o, "free"); > + debug_object_fixup(o.descr->fixup_free, > + (void *) oaddr, o.state); > goto repeat; > default: > hlist_del(&obj->node);