Received: by 10.213.65.68 with SMTP id h4csp3928504imn; Tue, 10 Apr 2018 06:48:40 -0700 (PDT) X-Google-Smtp-Source: AIpwx4//mPM0yyIQ6ieeyZZnFE99KLjlnsGsURhHI9smDs2uOJ7MgL2l2H4g2uvLmtYKCnGpB1uH X-Received: by 10.99.55.1 with SMTP id e1mr351250pga.237.1523368120786; Tue, 10 Apr 2018 06:48:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523368120; cv=none; d=google.com; s=arc-20160816; b=eQqX1EraPtGqS4u/657t8hcHWtd2RgTy3dEQBINrOGiRJuDT7vqL9K/N0ADm+HbVe6 5286myI4QNR0opzY9WVj95p0Y58O/vcsvNWQQyOyV0K3cU9ZEKyxfQKgf7hF+diQ4IcV aTqTSrwN+ONi6vGFgZVjpQHPG1GkEgnZMfg9XjJHb0OJpeNwZbm4HFx+l75TvQFQTt1J 3fbgSfBv7eldy5H+68lRvNIcQG7t4PzC2uPOGgIudgPjYgIRWi98VOHS+ztPpVKKMOmz HaKhuCH+veA6UfF95WqF/RWAd/ECEDc84+rxFsDpYYu4ERuQ7PGPz8wrXwVabouKergv YHNw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:arc-authentication-results; bh=an6eFg2v/aKqUWxKDnQ+7eZARk85eUauOgIt5ZSYWYQ=; b=BQS5GUoAEJtSBZJS37M4/5XSHEuNn099Z4+W+C4380ViIOjlPDZVgbV8UoF1kgwa4j tQ3fQMU3CQPcWT4T7hreLgQOs3pholevHOe6wWehZ+zvfnNADkLyC3aCeZQshIhmAEYo 2gBjVOpThrJr97ZeCBfBt0qiynfpWQDGZsGO7+Pb94NFRnj0rUuSkNBLumGJ18D5o6u9 3pe56GVa9WmgqxkVBWg89qwfhGjNHVQjxXJ0byIkjR16rsgC5qaRGY5xURXF7oQJeN2F ySxzOGeBsSEw93obCwIyjONggGoBItK5W6gSxsrADI+5cmwhM0k9FVXbnUft1dH22HZx t0yw== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g8si1778637pgv.281.2018.04.10.06.48.02; Tue, 10 Apr 2018 06:48:40 -0700 (PDT) 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753662AbeDJNo0 (ORCPT + 99 others); Tue, 10 Apr 2018 09:44:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:58690 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752951AbeDJNoW (ORCPT ); Tue, 10 Apr 2018 09:44:22 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2A98F406E8BD; Tue, 10 Apr 2018 13:44:21 +0000 (UTC) Received: from localhost (ovpn-8-16.pek2.redhat.com [10.72.8.16]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E1B58202660C; Tue, 10 Apr 2018 13:44:18 +0000 (UTC) Date: Tue, 10 Apr 2018 21:44:16 +0800 From: Baoquan He To: Rob Herring Cc: Nicolas Pitre , "linux-kernel@vger.kernel.org" , Patrik Jakobsson , David Airlie , "K. Y. Srinivasan" , Haiyang Zhang , Stephen Hemminger , Dmitry Torokhov , Dan Williams , Frank Rowand , Keith Busch , Jonathan Derrick , Lorenzo Pieralisi , Bjorn Helgaas , Thomas Gleixner , Brijesh Singh , =?iso-8859-1?B?Suly9G1l?= Glisse , Borislav Petkov , Tom Lendacky , Greg Kroah-Hartman , Yaowei Bai , Wei Yang , devel@linuxdriverproject.org, linux-input@vger.kernel.org, linux-nvdimm@lists.01.org, devicetree@vger.kernel.org, linux-pci@vger.kernel.org Subject: Re: [PATCH v3 1/3] resource: Use list_head to link resource sibling Message-ID: <20180410134416.GM19345@localhost.localdomain> References: <20180408024724.16812-1-bhe@redhat.com> <20180408024724.16812-2-bhe@redhat.com> <20180409090853.GJ19345@localhost.localdomain> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.9.1 (2017-09-22) X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 10 Apr 2018 13:44:21 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 10 Apr 2018 13:44:21 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'bhe@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Rob, Thanks a lot for looking into this and involve Nico to this thread! On 04/09/18 at 09:49am, Rob Herring wrote: > +Nico who has been working on tinification of the kernel. > > On Mon, Apr 9, 2018 at 4:08 AM, Baoquan He wrote: > > The struct resource uses singly linked list to link siblings. It's not > > easy to do reverse iteration on sibling list. So replace it with list_head. > > Why is reverse iteration needed? This is the explanation I made when Andrew helped to review the v1 post: https://lkml.org/lkml/2018/3/23/78 Because we have been using kexec-tools utility to search available System RAM space for loading kernel/initrd/purgatory from top to down. That is done in user space by searching /proc/iomem. While later added kexec_file interface, the searching code happened in kernel, and it only search System RAM region bottom up, then take an area in that found RAM region from top to down. We need unify these two interfaces on behaviour since they are the same on essense from the users' point of view, though implementation is different. As you know, the singly linked list implementation of the current resource's sibling linking, makes the searching from top to down very hard to satisfy people. Below is the v1 post, we make an temporary array to copy iomem_resource's first level of children, then iterate the array reversedly. Andrew suggested me to try list_head after reviewing. In fact we can optimize that patch to only copy resource pointer into array, still the way is ugly. https://lkml.org/lkml/2018/3/21/952 Then Wei pasted a patch he had made as below. He didn't mention if he also has requirement on reversed iteration of resource. That is an O(n*n) way, from personal feelings, hard to say if it's bettern than v1 post. https://lkml.org/lkml/2018/3/24/157 That's why I would like to have a try of the list_head linking. > > > And code refactoring makes codes in kernel/resource.c more readable than > > pointer operation. > > resource_for_each_* helpers could solve that without the size increase. Nico mentioned llist, that is a linux kernel standard singly linked list, very elegant code existed. Still can not satisfy the reversed iteration requirement. > > > Besides, type of member variables of struct resource, sibling and child, are > > changed from 'struct resource *' to 'struct list_head'. Kernel size will > > increase because of those statically defined struct resource instances. > > The DT struct device_node also has the same tree structure with > parent, child, sibling pointers and converting to list_head had been > on the todo list for a while. ACPI also has some tree walking > functions (drivers/acpi/acpica/pstree.c). Perhaps there should be a > common tree struct and helpers defined either on top of list_head or a > new struct if that saves some size. We have had many this kind of trees in kernel, the obvious examples is task_struct. And struct task_group {} too. They have used list_head already. struct task_struct { ... /* Real parent process: */ struct task_struct __rcu *real_parent; /* Recipient of SIGCHLD, wait4() reports: */ struct task_struct __rcu *parent; struct list_head children; struct list_head sibling; ... } root /// | \\\ /// | \\\ /// | \\\ /// | \\\ (child)<->(child)<->(child) /// | \\\ /// | \\\ /// | \\\ /// | \\\ (grandchild)<->(grandchild)<->(grandchild) If define an new struct, , like tree_list, or tlist? struct tlist { void *parent; struct list_head sibling; struct list_head child; } Just a rough idea, feel it might not bring too much benefit compared with direct list operation. > > > > > Signed-off-by: Baoquan He > > --- > > v2->v3: > > Make sibling() and first_child() global so that they can be called > > out of kernel/resource.c to simplify code. > > These should probably be inline functions. Or exported if not. > > > > > Fix several code bugs found by kbuild test robot. > > > > Got report from lkp that kernel size increased. It's on purpose since > > the type change of sibling and child inside struct resource{}. For > > each struct resource variable, it will cost another 16 bytes on x86 64. > > The size increase should be mentioned in the commit log. More > generally, the size increase is 2 pointers. Simply mentioned the size increase in this updated version. Yes, 2 pointers increased. Will add it to log ot make it more specifically. Thanks Baoquan > > > > arch/sparc/kernel/ioport.c | 2 +- > > drivers/gpu/drm/drm_memory.c | 3 +- > > drivers/gpu/drm/gma500/gtt.c | 5 +- > > drivers/hv/vmbus_drv.c | 52 ++++---- > > drivers/input/joystick/iforce/iforce-main.c | 4 +- > > drivers/nvdimm/e820.c | 2 +- > > drivers/nvdimm/namespace_devs.c | 6 +- > > drivers/nvdimm/nd.h | 5 +- > > drivers/of/address.c | 4 +- > > drivers/parisc/lba_pci.c | 4 +- > > drivers/pci/host/vmd.c | 8 +- > > drivers/pci/probe.c | 2 + > > drivers/pci/setup-bus.c | 2 +- > > include/linux/ioport.h | 6 +- > > kernel/resource.c | 193 ++++++++++++++-------------- > > 15 files changed, 149 insertions(+), 149 deletions(-) > > > > diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c > > index 3bcef9ce74df..4e91fbbbedcc 100644 > > --- a/arch/sparc/kernel/ioport.c > > +++ b/arch/sparc/kernel/ioport.c > > @@ -669,7 +669,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v) > > struct resource *root = m->private, *r; > > const char *nm; > > > > - for (r = root->child; r != NULL; r = r->sibling) { > > + list_for_each_entry(r, &root->child, sibling) { > > if ((nm = r->name) == NULL) nm = "???"; > > seq_printf(m, "%016llx-%016llx: %s\n", > > (unsigned long long)r->start, > > diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c > > index 3c54044214db..53e300a993dc 100644 > > --- a/drivers/gpu/drm/drm_memory.c > > +++ b/drivers/gpu/drm/drm_memory.c > > @@ -155,9 +155,8 @@ u64 drm_get_max_iomem(void) > > struct resource *tmp; > > resource_size_t max_iomem = 0; > > > > - for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) { > > + list_for_each_entry(tmp, &iomem_resource.child, sibling) > > max_iomem = max(max_iomem, tmp->end); > > - } > > > > return max_iomem; > > } > > diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c > > index 3949b0990916..addd3bc009af 100644 > > --- a/drivers/gpu/drm/gma500/gtt.c > > +++ b/drivers/gpu/drm/gma500/gtt.c > > @@ -565,7 +565,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) > > int psb_gtt_restore(struct drm_device *dev) > > { > > struct drm_psb_private *dev_priv = dev->dev_private; > > - struct resource *r = dev_priv->gtt_mem->child; > > + struct resource *r; > > struct gtt_range *range; > > unsigned int restored = 0, total = 0, size = 0; > > > > @@ -573,14 +573,13 @@ int psb_gtt_restore(struct drm_device *dev) > > mutex_lock(&dev_priv->gtt_mutex); > > psb_gtt_init(dev, 1); > > > > - while (r != NULL) { > > + list_for_each_entry(r, &dev_priv->gtt_mem->child, sibling) { > > range = container_of(r, struct gtt_range, resource); > > if (range->pages) { > > psb_gtt_insert(dev, range, 1); > > size += range->resource.end - range->resource.start; > > restored++; > > } > > - r = r->sibling; > > total++; > > } > > mutex_unlock(&dev_priv->gtt_mutex); > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > > index bc65c4d79c1f..7ba8a25520d9 100644 > > --- a/drivers/hv/vmbus_drv.c > > +++ b/drivers/hv/vmbus_drv.c > > @@ -1413,9 +1413,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) > > { > > resource_size_t start = 0; > > resource_size_t end = 0; > > - struct resource *new_res; > > + struct resource *new_res, *tmp; > > struct resource **old_res = &hyperv_mmio; > > - struct resource **prev_res = NULL; > > > > switch (res->type) { > > > > @@ -1462,44 +1461,36 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) > > /* > > * If two ranges are adjacent, merge them. > > */ > > - do { > > - if (!*old_res) { > > - *old_res = new_res; > > - break; > > - } > > - > > - if (((*old_res)->end + 1) == new_res->start) { > > - (*old_res)->end = new_res->end; > > + if (!*old_res) { > > + *old_res = new_res; > > + return AE_OK; > > + } > > + tmp = *old_res; > > + list_for_each_entry_from(tmp, &tmp->parent->child, sibling) { > > + if ((tmp->end + 1) == new_res->start) { > > + tmp->end = new_res->end; > > kfree(new_res); > > break; > > } > > > > - if ((*old_res)->start == new_res->end + 1) { > > - (*old_res)->start = new_res->start; > > + if (tmp->start == new_res->end + 1) { > > + tmp->start = new_res->start; > > kfree(new_res); > > break; > > } > > > > - if ((*old_res)->start > new_res->end) { > > - new_res->sibling = *old_res; > > - if (prev_res) > > - (*prev_res)->sibling = new_res; > > - *old_res = new_res; > > + if (tmp->start > new_res->end) { > > + list_add(&new_res->sibling, tmp->sibling.prev); > > break; > > } > > - > > - prev_res = old_res; > > - old_res = &(*old_res)->sibling; > > - > > - } while (1); > > + } > > > > return AE_OK; > > } > > > > static int vmbus_acpi_remove(struct acpi_device *device) > > { > > - struct resource *cur_res; > > - struct resource *next_res; > > + struct resource *res; > > > > if (hyperv_mmio) { > > if (fb_mmio) { > > @@ -1508,10 +1499,9 @@ static int vmbus_acpi_remove(struct acpi_device *device) > > fb_mmio = NULL; > > } > > > > - for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) { > > - next_res = cur_res->sibling; > > - kfree(cur_res); > > - } > > + res = hyperv_mmio; > > + list_for_each_entry_from(res, &res->parent->child, sibling) > > + kfree(res); > > } > > > > return 0; > > @@ -1597,7 +1587,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, > > } > > } > > > > - for (iter = hyperv_mmio; iter; iter = iter->sibling) { > > + iter = hyperv_mmio; > > + list_for_each_entry_from(iter, &iter->parent->child, sibling) { > > if ((iter->start >= max) || (iter->end <= min)) > > continue; > > > > @@ -1640,7 +1631,8 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) > > struct resource *iter; > > > > down(&hyperv_mmio_lock); > > - for (iter = hyperv_mmio; iter; iter = iter->sibling) { > > + iter = hyperv_mmio; > > + list_for_each_entry_from(iter, &iter->parent->child, sibling) { > > if ((iter->start >= start + size) || (iter->end <= start)) > > continue; > > > > diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c > > index daeeb4c7e3b0..5c0be27b33ff 100644 > > --- a/drivers/input/joystick/iforce/iforce-main.c > > +++ b/drivers/input/joystick/iforce/iforce-main.c > > @@ -305,8 +305,8 @@ int iforce_init_device(struct iforce *iforce) > > iforce->device_memory.end = 200; > > iforce->device_memory.flags = IORESOURCE_MEM; > > iforce->device_memory.parent = NULL; > > - iforce->device_memory.child = NULL; > > - iforce->device_memory.sibling = NULL; > > + INIT_LIST_HEAD(&iforce->device_memory.child); > > + INIT_LIST_HEAD(&iforce->device_memory.sibling); > > > > /* > > * Wait until device ready - until it sends its first response. > > diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c > > index 6f9a6ffd7cde..513e661bb0d8 100644 > > --- a/drivers/nvdimm/e820.c > > +++ b/drivers/nvdimm/e820.c > > @@ -53,7 +53,7 @@ static int e820_pmem_probe(struct platform_device *pdev) > > goto err; > > platform_set_drvdata(pdev, nvdimm_bus); > > > > - for (p = iomem_resource.child; p ; p = p->sibling) { > > + list_for_each_entry(p, &iomem_resource.child, sibling) { > > struct nd_region_desc ndr_desc; > > > > if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY) > > diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c > > index 658ada497be0..bcbdf5335909 100644 > > --- a/drivers/nvdimm/namespace_devs.c > > +++ b/drivers/nvdimm/namespace_devs.c > > @@ -637,7 +637,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region, > > retry: > > first = 0; > > for_each_dpa_resource(ndd, res) { > > - struct resource *next = res->sibling, *new_res = NULL; > > + struct resource *next = sibling(res), *new_res = NULL; > > resource_size_t allocate, available = 0; > > enum alloc_loc loc = ALLOC_ERR; > > const char *action; > > @@ -763,7 +763,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region, > > * an initial "pmem-reserve pass". Only do an initial BLK allocation > > * when none of the DPA space is reserved. > > */ > > - if ((is_pmem || !ndd->dpa.child) && n == to_allocate) > > + if ((is_pmem || list_empty(&ndd->dpa.child)) && n == to_allocate) > > return init_dpa_allocation(label_id, nd_region, nd_mapping, n); > > return n; > > } > > @@ -779,7 +779,7 @@ static int merge_dpa(struct nd_region *nd_region, > > retry: > > for_each_dpa_resource(ndd, res) { > > int rc; > > - struct resource *next = res->sibling; > > + struct resource *next = sibling(res); > > resource_size_t end = res->start + resource_size(res); > > > > if (!next || strcmp(res->name, label_id->id) != 0 > > diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h > > index 184e070d50a2..1dc0b2370bd1 100644 > > --- a/drivers/nvdimm/nd.h > > +++ b/drivers/nvdimm/nd.h > > @@ -102,11 +102,10 @@ unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd); > > (unsigned long long) (res ? res->start : 0), ##arg) > > > > #define for_each_dpa_resource(ndd, res) \ > > - for (res = (ndd)->dpa.child; res; res = res->sibling) > > + list_for_each_entry(res, &(ndd)->dpa.child, sibling) > > > > #define for_each_dpa_resource_safe(ndd, res, next) \ > > - for (res = (ndd)->dpa.child, next = res ? res->sibling : NULL; \ > > - res; res = next, next = next ? next->sibling : NULL) > > + list_for_each_entry_safe(res, next, &(ndd)->dpa.child, sibling) > > > > struct nd_percpu_lane { > > int count; > > diff --git a/drivers/of/address.c b/drivers/of/address.c > > index 53349912ac75..e2e25719ab52 100644 > > --- a/drivers/of/address.c > > +++ b/drivers/of/address.c > > @@ -330,7 +330,9 @@ int of_pci_range_to_resource(struct of_pci_range *range, > > { > > int err; > > res->flags = range->flags; > > - res->parent = res->child = res->sibling = NULL; > > + res->parent = NULL; > > + INIT_LIST_HEAD(&res->child); > > + INIT_LIST_HEAD(&res->sibling); > > res->name = np->full_name; > > > > if (res->flags & IORESOURCE_IO) { > > diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c > > index 69bd98421eb1..84f04418ae0b 100644 > > --- a/drivers/parisc/lba_pci.c > > +++ b/drivers/parisc/lba_pci.c > > @@ -170,8 +170,8 @@ lba_dump_res(struct resource *r, int d) > > for (i = d; i ; --i) printk(" "); > > printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, > > (long)r->start, (long)r->end, r->flags); > > - lba_dump_res(r->child, d+2); > > - lba_dump_res(r->sibling, d); > > + lba_dump_res(first_child(&r->child), d+2); > > + lba_dump_res(sibling(r), d); > > } > > > > > > diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c > > index 930a8fa08bd6..c3000af903ea 100644 > > --- a/drivers/pci/host/vmd.c > > +++ b/drivers/pci/host/vmd.c > > @@ -520,14 +520,14 @@ static struct pci_ops vmd_ops = { > > > > static void vmd_attach_resources(struct vmd_dev *vmd) > > { > > - vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1]; > > - vmd->dev->resource[VMD_MEMBAR2].child = &vmd->resources[2]; > > + list_add(&vmd->resources[1].sibling, &vmd->dev->resource[VMD_MEMBAR1].child); > > + list_add(&vmd->resources[2].sibling, &vmd->dev->resource[VMD_MEMBAR2].child); > > } > > > > static void vmd_detach_resources(struct vmd_dev *vmd) > > { > > - vmd->dev->resource[VMD_MEMBAR1].child = NULL; > > - vmd->dev->resource[VMD_MEMBAR2].child = NULL; > > + INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR1].child); > > + INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR2].child); > > } > > > > /* > > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > > index ac91b6fd0bcd..d162c77bec29 100644 > > --- a/drivers/pci/probe.c > > +++ b/drivers/pci/probe.c > > @@ -59,6 +59,8 @@ static struct resource *get_pci_domain_busn_res(int domain_nr) > > r->res.start = 0; > > r->res.end = 0xff; > > r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED; > > + INIT_LIST_HEAD(&r->res.child); > > + INIT_LIST_HEAD(&r->res.sibling); > > > > list_add_tail(&r->list, &pci_domain_busn_res_list); > > > > diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c > > index 072784f55ea5..0d5e30004ca6 100644 > > --- a/drivers/pci/setup-bus.c > > +++ b/drivers/pci/setup-bus.c > > @@ -2107,7 +2107,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) > > continue; > > > > /* Ignore BARs which are still in use */ > > - if (res->child) > > + if (!list_empty(&res->child)) > > continue; > > > > ret = add_to_list(&saved, bridge, res, 0, 0); > > diff --git a/include/linux/ioport.h b/include/linux/ioport.h > > index da0ebaec25f0..03d1510f03e0 100644 > > --- a/include/linux/ioport.h > > +++ b/include/linux/ioport.h > > @@ -22,7 +22,8 @@ struct resource { > > const char *name; > > unsigned long flags; > > unsigned long desc; > > - struct resource *parent, *sibling, *child; > > + struct list_head child, sibling; > > + struct resource *parent; > > }; > > > > /* > > @@ -189,6 +190,8 @@ extern int allocate_resource(struct resource *root, struct resource *new, > > resource_size_t, > > resource_size_t), > > void *alignf_data); > > +extern struct resource *sibling(struct resource *res); > > +extern struct resource *first_child(struct list_head *head); > > struct resource *lookup_resource(struct resource *root, resource_size_t start); > > int adjust_resource(struct resource *res, resource_size_t start, > > resource_size_t size); > > @@ -215,7 +218,6 @@ static inline bool resource_contains(struct resource *r1, struct resource *r2) > > return r1->start <= r2->start && r1->end >= r2->end; > > } > > > > - > > /* Convenience shorthand with allocation */ > > #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0) > > #define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED) > > diff --git a/kernel/resource.c b/kernel/resource.c > > index e270b5048988..473c624606f9 100644 > > --- a/kernel/resource.c > > +++ b/kernel/resource.c > > @@ -31,6 +31,8 @@ struct resource ioport_resource = { > > .start = 0, > > .end = IO_SPACE_LIMIT, > > .flags = IORESOURCE_IO, > > + .sibling = LIST_HEAD_INIT(ioport_resource.sibling), > > + .child = LIST_HEAD_INIT(ioport_resource.child), > > }; > > EXPORT_SYMBOL(ioport_resource); > > > > @@ -39,6 +41,8 @@ struct resource iomem_resource = { > > .start = 0, > > .end = -1, > > .flags = IORESOURCE_MEM, > > + .sibling = LIST_HEAD_INIT(iomem_resource.sibling), > > + .child = LIST_HEAD_INIT(iomem_resource.child), > > }; > > EXPORT_SYMBOL(iomem_resource); > > > > @@ -57,20 +61,32 @@ static DEFINE_RWLOCK(resource_lock); > > * by boot mem after the system is up. So for reusing the resource entry > > * we need to remember the resource. > > */ > > -static struct resource *bootmem_resource_free; > > +static struct list_head bootmem_resource_free = LIST_HEAD_INIT(bootmem_resource_free); > > static DEFINE_SPINLOCK(bootmem_resource_lock); > > > > +struct resource *sibling(struct resource *res) > > +{ > > + if (res->parent && !list_is_last(&res->sibling, &res->parent->child)) > > + return list_next_entry(res, sibling); > > + return NULL; > > +} > > + > > +struct resource *first_child(struct list_head *head) > > +{ > > + return list_first_entry_or_null(head, struct resource, sibling); > > +} > > + > > static struct resource *next_resource(struct resource *p, bool sibling_only) > > { > > /* Caller wants to traverse through siblings only */ > > if (sibling_only) > > - return p->sibling; > > + return sibling(p); > > > > - if (p->child) > > - return p->child; > > - while (!p->sibling && p->parent) > > + if (!list_empty(&p->child)) > > + return first_child(&p->child); > > + while (!sibling(p) && p->parent) > > p = p->parent; > > - return p->sibling; > > + return sibling(p); > > } > > > > static void *r_next(struct seq_file *m, void *v, loff_t *pos) > > @@ -90,7 +106,7 @@ static void *r_start(struct seq_file *m, loff_t *pos) > > struct resource *p = m->private; > > loff_t l = 0; > > read_lock(&resource_lock); > > - for (p = p->child; p && l < *pos; p = r_next(m, p, &l)) > > + for (p = first_child(&p->child); p && l < *pos; p = r_next(m, p, &l)) > > ; > > return p; > > } > > @@ -186,8 +202,7 @@ static void free_resource(struct resource *res) > > > > if (!PageSlab(virt_to_head_page(res))) { > > spin_lock(&bootmem_resource_lock); > > - res->sibling = bootmem_resource_free; > > - bootmem_resource_free = res; > > + list_add(&res->sibling, &bootmem_resource_free); > > spin_unlock(&bootmem_resource_lock); > > } else { > > kfree(res); > > @@ -199,10 +214,9 @@ static struct resource *alloc_resource(gfp_t flags) > > struct resource *res = NULL; > > > > spin_lock(&bootmem_resource_lock); > > - if (bootmem_resource_free) { > > - res = bootmem_resource_free; > > - bootmem_resource_free = res->sibling; > > - } > > + res = first_child(&bootmem_resource_free); > > + if (res) > > + list_del(&res->sibling); > > spin_unlock(&bootmem_resource_lock); > > > > if (res) > > @@ -210,6 +224,8 @@ static struct resource *alloc_resource(gfp_t flags) > > else > > res = kzalloc(sizeof(struct resource), flags); > > > > + INIT_LIST_HEAD(&res->child); > > + INIT_LIST_HEAD(&res->sibling); > > return res; > > } > > > > @@ -218,7 +234,7 @@ static struct resource * __request_resource(struct resource *root, struct resour > > { > > resource_size_t start = new->start; > > resource_size_t end = new->end; > > - struct resource *tmp, **p; > > + struct resource *tmp; > > > > if (end < start) > > return root; > > @@ -226,64 +242,62 @@ static struct resource * __request_resource(struct resource *root, struct resour > > return root; > > if (end > root->end) > > return root; > > - p = &root->child; > > - for (;;) { > > - tmp = *p; > > - if (!tmp || tmp->start > end) { > > - new->sibling = tmp; > > - *p = new; > > + > > + if (list_empty(&root->child)) { > > + list_add(&new->sibling, &root->child); > > + new->parent = root; > > + INIT_LIST_HEAD(&new->child); > > + return NULL; > > + } > > + > > + list_for_each_entry(tmp, &root->child, sibling) { > > + if (tmp->start > end) { > > + list_add(&new->sibling, tmp->sibling.prev); > > new->parent = root; > > + INIT_LIST_HEAD(&new->child); > > return NULL; > > } > > - p = &tmp->sibling; > > if (tmp->end < start) > > continue; > > return tmp; > > } > > + > > + list_add_tail(&new->sibling, &root->child); > > + new->parent = root; > > + INIT_LIST_HEAD(&new->child); > > + return NULL; > > } > > > > static int __release_resource(struct resource *old, bool release_child) > > { > > - struct resource *tmp, **p, *chd; > > + struct resource *tmp, *next, *chd; > > > > - p = &old->parent->child; > > - for (;;) { > > - tmp = *p; > > - if (!tmp) > > - break; > > + list_for_each_entry_safe(tmp, next, &old->parent->child, sibling) { > > if (tmp == old) { > > - if (release_child || !(tmp->child)) { > > - *p = tmp->sibling; > > + if (release_child || list_empty(&tmp->child)) { > > + list_del(&tmp->sibling); > > } else { > > - for (chd = tmp->child;; chd = chd->sibling) { > > + list_for_each_entry(chd, &tmp->child, sibling) > > chd->parent = tmp->parent; > > - if (!(chd->sibling)) > > - break; > > - } > > - *p = tmp->child; > > - chd->sibling = tmp->sibling; > > + list_splice(&tmp->child, tmp->sibling.prev); > > + list_del(&tmp->sibling); > > } > > + > > old->parent = NULL; > > return 0; > > } > > - p = &tmp->sibling; > > } > > return -EINVAL; > > } > > > > static void __release_child_resources(struct resource *r) > > { > > - struct resource *tmp, *p; > > + struct resource *tmp, *next; > > resource_size_t size; > > > > - p = r->child; > > - r->child = NULL; > > - while (p) { > > - tmp = p; > > - p = p->sibling; > > - > > + list_for_each_entry_safe(tmp, next, &r->child, sibling) { > > tmp->parent = NULL; > > - tmp->sibling = NULL; > > + INIT_LIST_HEAD(&tmp->sibling); > > __release_child_resources(tmp); > > > > printk(KERN_DEBUG "release child resource %pR\n", tmp); > > @@ -292,6 +306,8 @@ static void __release_child_resources(struct resource *r) > > tmp->start = 0; > > tmp->end = size - 1; > > } > > + > > + INIT_LIST_HEAD(&tmp->child); > > } > > > > void release_child_resources(struct resource *r) > > @@ -376,7 +392,8 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc, > > > > read_lock(&resource_lock); > > > > - for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) { > > + for (p = first_child(&iomem_resource.child); p; > > + p = next_resource(p, sibling_only)) { > > if ((p->flags & res->flags) != res->flags) > > continue; > > if ((desc != IORES_DESC_NONE) && (desc != p->desc)) > > @@ -564,7 +581,7 @@ int region_intersects(resource_size_t start, size_t size, unsigned long flags, > > struct resource *p; > > > > read_lock(&resource_lock); > > - for (p = iomem_resource.child; p ; p = p->sibling) { > > + list_for_each_entry(p, &iomem_resource.child, sibling) { > > bool is_type = (((p->flags & flags) == flags) && > > ((desc == IORES_DESC_NONE) || > > (desc == p->desc))); > > @@ -618,7 +635,7 @@ static int __find_resource(struct resource *root, struct resource *old, > > resource_size_t size, > > struct resource_constraint *constraint) > > { > > - struct resource *this = root->child; > > + struct resource *this = first_child(&root->child); > > struct resource tmp = *new, avail, alloc; > > > > tmp.start = root->start; > > @@ -628,7 +645,7 @@ static int __find_resource(struct resource *root, struct resource *old, > > */ > > if (this && this->start == root->start) { > > tmp.start = (this == old) ? old->start : this->end + 1; > > - this = this->sibling; > > + this = sibling(this); > > } > > for(;;) { > > if (this) > > @@ -663,7 +680,7 @@ next: if (!this || this->end == root->end) > > > > if (this != old) > > tmp.start = this->end + 1; > > - this = this->sibling; > > + this = sibling(this); > > } > > return -EBUSY; > > } > > @@ -707,7 +724,7 @@ static int reallocate_resource(struct resource *root, struct resource *old, > > goto out; > > } > > > > - if (old->child) { > > + if (!list_empty(&old->child)) { > > err = -EBUSY; > > goto out; > > } > > @@ -788,7 +805,7 @@ struct resource *lookup_resource(struct resource *root, resource_size_t start) > > struct resource *res; > > > > read_lock(&resource_lock); > > - for (res = root->child; res; res = res->sibling) { > > + list_for_each_entry(res, &root->child, sibling) { > > if (res->start == start) > > break; > > } > > @@ -821,32 +838,27 @@ static struct resource * __insert_resource(struct resource *parent, struct resou > > break; > > } > > > > - for (next = first; ; next = next->sibling) { > > + for (next = first; ; next = sibling(next)) { > > /* Partial overlap? Bad, and unfixable */ > > if (next->start < new->start || next->end > new->end) > > return next; > > - if (!next->sibling) > > + if (!sibling(next)) > > break; > > - if (next->sibling->start > new->end) > > + if (sibling(next)->start > new->end) > > break; > > } > > - > > new->parent = parent; > > - new->sibling = next->sibling; > > - new->child = first; > > + list_add(&new->sibling, &next->sibling); > > + INIT_LIST_HEAD(&new->child); > > > > - next->sibling = NULL; > > - for (next = first; next; next = next->sibling) > > + /* > > + * From first to next, they all fall into new's region, so change them > > + * as new's children. > > + */ > > + list_cut_position(&new->child, first->sibling.prev, &next->sibling); > > + list_for_each_entry(next, &new->child, sibling) > > next->parent = new; > > > > - if (parent->child == first) { > > - parent->child = new; > > - } else { > > - next = parent->child; > > - while (next->sibling != first) > > - next = next->sibling; > > - next->sibling = new; > > - } > > return NULL; > > } > > > > @@ -968,19 +980,17 @@ static int __adjust_resource(struct resource *res, resource_size_t start, > > if ((start < parent->start) || (end > parent->end)) > > goto out; > > > > - if (res->sibling && (res->sibling->start <= end)) > > + if (sibling(res) && (sibling(res)->start <= end)) > > goto out; > > > > - tmp = parent->child; > > - if (tmp != res) { > > - while (tmp->sibling != res) > > - tmp = tmp->sibling; > > + if (res->sibling.prev != &parent->child) { > > + tmp = list_prev_entry(res, sibling); > > if (start <= tmp->end) > > goto out; > > } > > > > skip: > > - for (tmp = res->child; tmp; tmp = tmp->sibling) > > + list_for_each_entry(tmp, &res->child, sibling) > > if ((tmp->start < start) || (tmp->end > end)) > > goto out; > > > > @@ -1205,34 +1215,32 @@ EXPORT_SYMBOL(__request_region); > > void __release_region(struct resource *parent, resource_size_t start, > > resource_size_t n) > > { > > - struct resource **p; > > + struct resource *res; > > resource_size_t end; > > > > - p = &parent->child; > > + res = first_child(&parent->child); > > end = start + n - 1; > > > > write_lock(&resource_lock); > > > > for (;;) { > > - struct resource *res = *p; > > - > > if (!res) > > break; > > if (res->start <= start && res->end >= end) { > > if (!(res->flags & IORESOURCE_BUSY)) { > > - p = &res->child; > > + res = first_child(&res->child); > > continue; > > } > > if (res->start != start || res->end != end) > > break; > > - *p = res->sibling; > > + list_del(&res->sibling); > > write_unlock(&resource_lock); > > if (res->flags & IORESOURCE_MUXED) > > wake_up(&muxed_resource_wait); > > free_resource(res); > > return; > > } > > - p = &res->sibling; > > + res = sibling(res); > > } > > > > write_unlock(&resource_lock); > > @@ -1267,9 +1275,7 @@ EXPORT_SYMBOL(__release_region); > > int release_mem_region_adjustable(struct resource *parent, > > resource_size_t start, resource_size_t size) > > { > > - struct resource **p; > > - struct resource *res; > > - struct resource *new_res; > > + struct resource *res, *new_res; > > resource_size_t end; > > int ret = -EINVAL; > > > > @@ -1280,16 +1286,16 @@ int release_mem_region_adjustable(struct resource *parent, > > /* The alloc_resource() result gets checked later */ > > new_res = alloc_resource(GFP_KERNEL); > > > > - p = &parent->child; > > + res = first_child(&parent->child); > > write_lock(&resource_lock); > > > > - while ((res = *p)) { > > + while ((res)) { > > if (res->start >= end) > > break; > > > > /* look for the next resource if it does not fit into */ > > if (res->start > start || res->end < end) { > > - p = &res->sibling; > > + res = sibling(res); > > continue; > > } > > > > @@ -1297,14 +1303,14 @@ int release_mem_region_adjustable(struct resource *parent, > > break; > > > > if (!(res->flags & IORESOURCE_BUSY)) { > > - p = &res->child; > > + res = first_child(&res->child); > > continue; > > } > > > > /* found the target resource; let's adjust accordingly */ > > if (res->start == start && res->end == end) { > > /* free the whole entry */ > > - *p = res->sibling; > > + list_del(&res->sibling); > > free_resource(res); > > ret = 0; > > } else if (res->start == start && res->end != end) { > > @@ -1327,14 +1333,13 @@ int release_mem_region_adjustable(struct resource *parent, > > new_res->flags = res->flags; > > new_res->desc = res->desc; > > new_res->parent = res->parent; > > - new_res->sibling = res->sibling; > > - new_res->child = NULL; > > + INIT_LIST_HEAD(&new_res->child); > > > > ret = __adjust_resource(res, res->start, > > start - res->start); > > if (ret) > > break; > > - res->sibling = new_res; > > + list_add(&new_res->sibling, &res->sibling); > > new_res = NULL; > > } > > > > @@ -1515,7 +1520,7 @@ static int __init reserve_setup(char *str) > > res->end = io_start + io_num - 1; > > res->flags |= IORESOURCE_BUSY; > > res->desc = IORES_DESC_NONE; > > - res->child = NULL; > > + INIT_LIST_HEAD(&res->child); > > if (request_resource(parent, res) == 0) > > reserved = x+1; > > } > > @@ -1535,7 +1540,7 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size) > > loff_t l; > > > > read_lock(&resource_lock); > > - for (p = p->child; p ; p = r_next(NULL, p, &l)) { > > + for (p = first_child(&p->child); p; p = r_next(NULL, p, &l)) { > > /* > > * We can probably skip the resources without > > * IORESOURCE_IO attribute? > > @@ -1591,7 +1596,7 @@ bool iomem_is_exclusive(u64 addr) > > addr = addr & PAGE_MASK; > > > > read_lock(&resource_lock); > > - for (p = p->child; p ; p = r_next(NULL, p, &l)) { > > + for (p = first_child(&p->child); p; p = r_next(NULL, p, &l)) { > > /* > > * We can probably skip the resources without > > * IORESOURCE_IO attribute? > > -- > > 2.13.6 > >