Received: by 2002:a05:6a10:1a4d:0:0:0:0 with SMTP id nk13csp1665755pxb; Wed, 9 Feb 2022 01:37:39 -0800 (PST) X-Google-Smtp-Source: ABdhPJwUfs0dsrMwBiLQi88TbPKGi9BW1AwcUVSmhzfky35VIWg7XWiz/AzgJpJh3rwFtA75zjs9 X-Received: by 2002:a17:90a:8c8b:: with SMTP id b11mr2395179pjo.197.1644399459788; Wed, 09 Feb 2022 01:37:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644399459; cv=none; d=google.com; s=arc-20160816; b=eB6BbUshVdmxr94g5gARV04CIiCHmltyBKHCpmVbksIFeb87TiNwq7yM0lcpEB0HaA YVdhvgxQWjlpc8qRQrITzA453PV0FbtOlr1xuSTNwOXzfIaMaXUVxY4JriJoersxwkzd dMDLKZju6f6zpV0cbF7jlWmgo5QSQPKpZjZji3+3Z2yr91kDHndfIsadxQNcetAmIMXO PF4zv2rg2N0SyxjNHa364kL/+T3btgFEZhzVCKo+uk/7mSJO4PTEwrkTj1PyRrfZPhhi ttazAX2Ld7tVjETFnzD5VXaYGZjDAYibZUlvPAMIudBZRqqpvxq/oGXUva96h7V6hMG2 pNrg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:dkim-signature; bh=afzJpCERAmk3yFBzidPNdDx8rS5idfCgJ4X6kw/EPaM=; b=OS0nX0/xJXszOyNpyRcujF3gpHu+1cRGCiWHUs5UVBNbNNMh9dNDyN+WZYefE9NGvd CP/eE9U2PIXfxgWEQU+BAVHJ1+t2CBKthaIOLIEd9P3KQzZI/jDdaqDi2MlorDobuo4J SM+7MkzmnC1bX68WKCgLsyX6NsCU8219gGZzz0v9gfdMZhL6QG3hU0V4FuSMzkG1p4ti UGol5GwhKFxZVJV4J6bSVONCoz0vCFfyBpZw83Xg6i5LxtXfhPCfd2/4/ccTxG83qvWE yGUly4WJ+NIImbzkxpEt9qf+7/teW36kekANbmz7vFHzEHcr2pTTkQJ4UJzQNGoyqU/8 gh8g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@eclypsium.com header.s=google header.b=eEUrW4OF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=eclypsium.com Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id t16si16884486plg.257.2022.02.09.01.37.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Feb 2022 01:37:39 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@eclypsium.com header.s=google header.b=eEUrW4OF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=eclypsium.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7C51CE066E0B; Wed, 9 Feb 2022 01:02:31 -0800 (PST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1388414AbiBHWcy (ORCPT + 99 others); Tue, 8 Feb 2022 17:32:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34314 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1386658AbiBHVEx (ORCPT ); Tue, 8 Feb 2022 16:04:53 -0500 Received: from mail-pj1-x1033.google.com (mail-pj1-x1033.google.com [IPv6:2607:f8b0:4864:20::1033]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C16CC0612BD for ; Tue, 8 Feb 2022 13:04:51 -0800 (PST) Received: by mail-pj1-x1033.google.com with SMTP id on2so299724pjb.4 for ; Tue, 08 Feb 2022 13:04:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=eclypsium.com; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=afzJpCERAmk3yFBzidPNdDx8rS5idfCgJ4X6kw/EPaM=; b=eEUrW4OF40G7F+WuRB6qBYML3NnN8jyRLUuDZQ36/XwjKQrosY7EncGqdoZ56goO11 xq22cEWlVcV/nfTZEgwOl4cltBYzFo5qBDhHsxZIXIfbl/ev31PA89aerwPLPjquVt41 bY0xhOiHnke5u4XhoMvSuQatKLPM9ope1sJvXd2uTxspzkQiDP8VZ4s1wrfo6tk5IrOU A6r85p6t3+zI13d14ceOdn91Vz20yvAhdXYKsJQULVcHMNuj5RsQfYF+P5tX1QutEYJE 6qCcVAOXut7WXPhiIObuboj20J0WcrVEUKTbTC8X33BIepw3pq1fHPDyOd0Q5SaN7CQI k9Nw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=afzJpCERAmk3yFBzidPNdDx8rS5idfCgJ4X6kw/EPaM=; b=pyUZdb1k+v+yHigG7pjZnluteD4ZrVK0bFfYNMqM3kL2IhXMrOHBpFQQytbaWiFh3x CUK/jOJQuMWP36VhXQKGKJv23fr8qADAytUYrpvBBrcxWXgx2NWY0vQBKtXP3BHkS6YF dSpKhfuqtoBpJopuPAK288JhlCDcCBtOXeOqXofHQNL7SMhzo+jgNBqru6QdvgRE9IBF 8Vu8DcT3Ngn/KoB3jEOzBsxRGJxBvkCubLEIeTOfYekEx6/StBTkMjRJYd62mjBHBM1S NU408Re02YRk0YSBbfA5YwNoW6Dzxguz9DbQJWH/8MBjT4j1HsyCebjInHe7fMQUN3Pk wXig== X-Gm-Message-State: AOAM532uR0BnBPvTrZWW0RnDbJxENZvfmpo48EnBHgS8Ah6HYXVMrg4P ewrATvPzyRZDn8IS8iRv/kFLVW51lJ411XxRFxfgoA== X-Received: by 2002:a17:902:ab53:: with SMTP id ij19mr6335813plb.45.1644354290468; Tue, 08 Feb 2022 13:04:50 -0800 (PST) MIME-Version: 1.0 References: <20220203164328.203629-1-martin.fernandez@eclypsium.com> <20220203164328.203629-4-martin.fernandez@eclypsium.com> In-Reply-To: <20220203164328.203629-4-martin.fernandez@eclypsium.com> From: Daniel Gutson Date: Tue, 8 Feb 2022 18:04:39 -0300 Message-ID: Subject: Re: [PATCH v6 3/6] x86/e820: Refactor range_update and range_remove To: Martin Fernandez Cc: linux-kernel , linux-efi@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-mm@kvack.org, Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , ardb@kernel.org, dvhart@infradead.org, andy@infradead.org, Greg Kroah-Hartman , rafael@kernel.org, rppt@kernel.org, akpm@linux-foundation.org, Richard Hughes , Alex Bazhaniuk , Alison Schofield , Kees Cook Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, Feb 3, 2022 at 1:44 PM Martin Fernandez wrote: > > __e820__range_update and e820__range_remove had a very similar > implementation with a few lines different from each other, the lines > that actually perform the modification over the e820_table. The > similiraties were found in the checks for the different cases on how > each entry intersects with the given range (if it does at all). These > checks were very presice and error prone so it was not a good idea to > have them in both places. > > I propose a refactor of those functions, given that I need to create a > similar one for this patchset. > > Add a function to modify a E820 table in a given range. This > modification is done backed up by two helper structs: > e820_entry_updater and e820_*_data. > > The first one, e820_entry_updater, carries 3 callbacks which function > as the actions to take on the table. > > The other one, e820_*_data carries information needed by the > callbacks, for example in the case of range_update it will carry the > type that we are targeting. > > Signed-off-by: Martin Fernandez > --- > arch/x86/kernel/e820.c | 383 ++++++++++++++++++++++++++++++----------- > 1 file changed, 283 insertions(+), 100 deletions(-) > > diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c > index bc0657f0deed..89b78c6b345b 100644 > --- a/arch/x86/kernel/e820.c > +++ b/arch/x86/kernel/e820.c > @@ -459,144 +459,327 @@ static int __init append_e820_table(struct boot_e820_entry *entries, u32 nr_entr > return __append_e820_table(entries, nr_entries); > } > > +/** > + * e820_entry_updater - Helper type for __e820__handle_range_update(). > + * @should_update: Return true if @entry needs to be updated, false > + * otherwise. > + * @update: Apply desired actions to an @entry that is inside the > + * range and satisfies @should_update. > + * @new: Create new entry in the table with information gathered from > + * @original and @data. > + * > + * Each function corresponds to an action that > + * __e820__handle_range_update() does. Callbacks need to cast @data back > + * to the corresponding type. > + */ > +struct e820_entry_updater { > + bool (*should_update)(const struct e820_entry *entry, const void *data); > + void (*update)(struct e820_entry *entry, const void *data); > + void (*new)(struct e820_table *table, u64 new_start, u64 new_size, > + const struct e820_entry *original, const void *data); > +}; > + > +/** > + * e820_remove_data - Helper type for e820__range_remove(). > + * @old_type: old_type parameter of e820__range_remove(). > + * @check_type: check_type parameter of e820__range_remove(). > + * > + * This is intended to be used as the @data argument for the > + * e820_entry_updater callbacks. > + */ > +struct e820_remover_data { > + enum e820_type old_type; > + bool check_type; > +}; > + > +/** > + * e820_type_updater_data - Helper type for __e820__range_update(). > + * @old_type: old_type parameter of __e820__range_update(). > + * @new_type: new_type parameter of __e820__range_update(). > + * > + * This is intended to be used as the @data argument for the > + * e820_entry_updater callbacks. > + */ > +struct e820_type_updater_data { > + enum e820_type old_type; > + enum e820_type new_type; > +}; > + > +/** > + * __e820__handle_intersected_range_update() - Helper function for > + * __e820__handle_range_update(). > + * @table: Target e820_table. > + * @start: Start of the range. > + * @size: Size of the range. > + * @entry: Current entry that __e820__handle_range_update() was > + * looking into. > + * @updater: updater parameter of __e820__handle_range_update(). > + * @data: data parameter of __e820__handle_range_update(). > + * > + * Helper for __e820__handle_range_update to handle the case where > + * neither the entry completely covers the range nor the range > + * completely covers the entry. > + * > + * Return: The updated size. > + */ > static u64 __init > -__e820__range_update(struct e820_table *table, u64 start, u64 size, enum e820_type old_type, enum e820_type new_type) > +__e820__handle_intersected_range_update(struct e820_table *table, > + u64 start, > + u64 size, > + struct e820_entry *entry, > + const struct e820_entry_updater *updater, > + const void *data) > { > u64 end; > - unsigned int i; > - u64 real_updated_size = 0; > - > - BUG_ON(old_type == new_type); > + u64 entry_end = entry->addr + entry->size; > + u64 inner_start; > + u64 inner_end; > + u64 updated_size = 0; > > if (size > (ULLONG_MAX - start)) > size = ULLONG_MAX - start; > > end = start + size; > - printk(KERN_DEBUG "e820: update [mem %#010Lx-%#010Lx] ", start, end - 1); > - e820_print_type(old_type); > - pr_cont(" ==> "); > - e820_print_type(new_type); > - pr_cont("\n"); > - > - for (i = 0; i < table->nr_entries; i++) { > - struct e820_entry *entry = &table->entries[i]; > - u64 final_start, final_end; > - u64 entry_end; > + inner_start = max(start, entry->addr); > + inner_end = min(end, entry_end); > + > + /* Range and entry do intersect and... */ > + if (inner_start < inner_end) { > + /* Entry is on the left */ > + if (entry->addr < inner_start) { > + /* Resize current entry */ > + entry->size = inner_start - entry->addr; > + /* Entry is on the right */ > + } else { > + /* Resize and move current section */ > + entry->addr = inner_end; > + entry->size = entry_end - inner_end; > + } > + /* Create new entry with intersected region */ > + updater->new(table, inner_start, inner_end - inner_start, entry, data); > > - if (entry->type != old_type) > - continue; > + updated_size += inner_end - inner_start; > + } /* Else: [start, end) doesn't cover entry */ > > - entry_end = entry->addr + entry->size; > + return updated_size; > +} > > - /* Completely covered by new range? */ > - if (entry->addr >= start && entry_end <= end) { > - entry->type = new_type; > - real_updated_size += entry->size; > - continue; > - } > +/** __e820__handle_range_update(): Helper function to update a address > + * range in a e820_table > + * @table: e820_table that we want to modify. > + * @start: Start of the range. > + * @size: Size of the range. > + * @updater: Callbacks to modify the table. > + * @data: Information to modify the table. > + * > + * Update the table @table in [@start, @start + @size) doing the > + * actions given in @updater. > + * > + * Return: The updated size. > + */ > +static u64 __init > +__e820__handle_range_update(struct e820_table *table, > + u64 start, > + u64 size, > + const struct e820_entry_updater *updater, > + const void *data) > +{ > + u64 updated_size = 0; > + u64 end; > + unsigned int i; > > - /* New range is completely covered? */ > - if (entry->addr < start && entry_end > end) { > - __e820__range_add(table, start, size, new_type); > - __e820__range_add(table, end, entry_end - end, entry->type); > - entry->size = start - entry->addr; > - real_updated_size += size; > - continue; > - } > + if (size > (ULLONG_MAX - start)) > + size = ULLONG_MAX - start; > > - /* Partially covered: */ > - final_start = max(start, entry->addr); > - final_end = min(end, entry_end); > - if (final_start >= final_end) > - continue; > + end = start + size; > > - __e820__range_add(table, final_start, final_end - final_start, new_type); > + for (i = 0; i < table->nr_entries; i++) { > + struct e820_entry *entry = &table->entries[i]; > + u64 entry_end = entry->addr + entry->size; > + > + if (updater->should_update(data, entry)) { > + /* Range completely covers entry */ > + if (entry->addr >= start && entry_end <= end) { > + updater->update(entry, data); > + updated_size += entry->size; > + /* Entry completely covers range */ > + } else if (start > entry->addr && end < entry_end) { > + /* Resize current entry */ > + entry->size = start - entry->addr; > + > + /* Create new entry with intersection region */ > + updater->new(table, start, size, entry, data); > + > + /* > + * Create a new entry for the leftover > + * of the current entry > + */ > + __e820__range_add(table, end, entry_end - end, > + entry->type); > + > + updated_size += size; > + } else { > + updated_size = > + __e820__handle_intersected_range_update(table, start, size, > + entry, updater, data); > + } > + } > + } > > - real_updated_size += final_end - final_start; > + return updated_size; > +} > > - /* > - * Left range could be head or tail, so need to update > - * its size first: > - */ > - entry->size -= final_end - final_start; > - if (entry->addr < final_start) > - continue; > +static bool __init type_updater__should_update(const struct e820_entry *entry, > + const void *data) > +{ > + struct e820_type_updater_data *type_updater_data = > + (struct e820_type_updater_data *)data; Please preserve const correctness. You are removing the const qualifier. > > - entry->addr = final_end; > - } > - return real_updated_size; > + return entry->type == type_updater_data->old_type; > } > > -u64 __init e820__range_update(u64 start, u64 size, enum e820_type old_type, enum e820_type new_type) > +static void __init type_updater__update(struct e820_entry *entry, > + const void *data) > { > - return __e820__range_update(e820_table, start, size, old_type, new_type); > + struct e820_type_updater_data *type_updater_data = > + (struct e820_type_updater_data *)data; > + > + entry->type = type_updater_data->new_type; > } > > -static u64 __init e820__range_update_kexec(u64 start, u64 size, enum e820_type old_type, enum e820_type new_type) > +static void __init type_updater__new(struct e820_table *table, u64 new_start, > + u64 new_size, > + const struct e820_entry *original, > + const void *data) > { > - return __e820__range_update(e820_table_kexec, start, size, old_type, new_type); > + struct e820_type_updater_data *type_updater_data = > + (struct e820_type_updater_data *)data; > + > + __e820__range_add(table, new_start, new_size, > + type_updater_data->new_type); > } > > -/* Remove a range of memory from the E820 table: */ > -u64 __init e820__range_remove(u64 start, u64 size, enum e820_type old_type, bool check_type) > +static u64 __init __e820__range_update(struct e820_table *table, u64 start, > + u64 size, enum e820_type old_type, > + enum e820_type new_type) > { > - int i; > - u64 end; > - u64 real_removed_size = 0; > + struct e820_entry_updater updater = { > + .should_update = type_updater__should_update, > + .update = type_updater__update, > + .new = type_updater__new > + }; > > - if (size > (ULLONG_MAX - start)) > - size = ULLONG_MAX - start; > + struct e820_type_updater_data data = { > + .old_type = old_type, > + .new_type = new_type > + }; > > - end = start + size; > - printk(KERN_DEBUG "e820: remove [mem %#010Lx-%#010Lx] ", start, end - 1); > - if (check_type) > - e820_print_type(old_type); > + BUG_ON(old_type == new_type); > + > + printk(KERN_DEBUG "e820: update [mem %#018Lx-%#018Lx] ", start, > + start + size - 1); > + e820_print_type(old_type); > + pr_cont(" ==> "); > + e820_print_type(new_type); > pr_cont("\n"); > > - for (i = 0; i < e820_table->nr_entries; i++) { > - struct e820_entry *entry = &e820_table->entries[i]; > - u64 final_start, final_end; > - u64 entry_end; > + return __e820__handle_range_update(table, start, size, &updater, &data); > +} > > - if (check_type && entry->type != old_type) > - continue; > +static bool __init remover__should_update(const struct e820_entry *entry, > + const void *data) > +{ > + struct e820_remover_data *remover_data = > + (struct e820_remover_data *)data; > > - entry_end = entry->addr + entry->size; > + return !remover_data->check_type || > + entry->type == remover_data->old_type; > +} > > - /* Completely covered? */ > - if (entry->addr >= start && entry_end <= end) { > - real_removed_size += entry->size; > - memset(entry, 0, sizeof(*entry)); > - continue; > - } > +static void __init remover__update(struct e820_entry *entry, const void *data) > +{ > + memset(entry, 0, sizeof(*entry)); > +} > > - /* Is the new range completely covered? */ > - if (entry->addr < start && entry_end > end) { > - e820__range_add(end, entry_end - end, entry->type); > - entry->size = start - entry->addr; > - real_removed_size += size; > - continue; > - } > +static void __init remover__new(struct e820_table *table, u64 new_start, > + u64 new_size, const struct e820_entry *original, > + const void *data) > +{ > +} > > - /* Partially covered: */ > - final_start = max(start, entry->addr); > - final_end = min(end, entry_end); > - if (final_start >= final_end) > - continue; > +/** > + * e820__range_remove() - Remove an address range from e820_table. > + * @start: Start of the address range. > + * @size: Size of the address range. > + * @old_type: Type of the entries that we want to remove. > + * @check_type: Bool to decide if ignore @old_type or not. > + * > + * Remove [@start, @start + @size) from e820_table. If @check_type is > + * true remove only entries with type @old_type. > + * > + * Return: The size removed. > + */ > +u64 __init e820__range_remove(u64 start, u64 size, enum e820_type old_type, > + bool check_type) > +{ > + struct e820_entry_updater updater = { > + .should_update = remover__should_update, > + .update = remover__update, > + .new = remover__new > + }; > + > + struct e820_remover_data data = { > + .check_type = check_type, > + .old_type = old_type > + }; > + > + printk(KERN_DEBUG "e820: remove [mem %#018Lx-%#018Lx] ", start, > + start + size - 1); > + if (check_type) > + e820_print_type(old_type); > + pr_cont("\n"); > > - real_removed_size += final_end - final_start; > + return __e820__handle_range_update(e820_table, start, size, &updater, > + &data); > +} > > - /* > - * Left range could be head or tail, so need to update > - * the size first: > - */ > - entry->size -= final_end - final_start; > - if (entry->addr < final_start) > - continue; > +/** > + * e820__range_update() - Update the type of a given address range in > + * e820_table. > + * @start: Start of the range. > + * @size: Size of the range. > + * @old_type: Type that we want to change. > + * @new_type: New type to replace @old_type. > + * > + * Update type of addresses in [@start, @start + @size) from @old_type > + * to @new_type in e820_table. > + * > + * Return: The size updated. > + */ > +u64 __init e820__range_update(u64 start, u64 size, enum e820_type old_type, > + enum e820_type new_type) > +{ > + return __e820__range_update(e820_table, start, size, old_type, new_type); > +} > > - entry->addr = final_end; > - } > - return real_removed_size; > +/** > + * e820__range_update_kexec() - Update the type of a given address > + * range in e820_table_kexec. > + * @start: Start of the range. > + * @size: Size of the range. > + * @old_type: Type that we want to change. > + * @new_type: New type to replace @old_type. > + * > + * Update type of addresses in [@start, @start + @size) from @old_type > + * to @new_type in e820_table_kexec. > + * > + * Return: The size updated. > + */ > +static u64 __init e820__range_update_kexec(u64 start, u64 size, > + enum e820_type old_type, > + enum e820_type new_type) > +{ > + return __e820__range_update(e820_table_kexec, start, size, old_type, new_type); > } > > void __init e820__update_table_print(void) > -- > 2.30.2 >