summaryrefslogtreecommitdiffstats
path: root/kernel/resource.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2018-09-27 10:22:09 -0400
committerBorislav Petkov <bp@suse.de>2018-10-09 11:18:36 -0400
commit010a93bf97c72f43aac664d0a685942f83d1a103 (patch)
tree3fc4d3683d13c0bbd69f69ac461c928a54ecf6f7 /kernel/resource.c
parenta98959fdbda1849a01b2150bb635ed559ec06700 (diff)
resource: Fix find_next_iomem_res() iteration issue
Previously find_next_iomem_res() used "*res" as both an input parameter for the range to search and the type of resource to search for, and an output parameter for the resource we found, which makes the interface confusing. The current callers use find_next_iomem_res() incorrectly because they allocate a single struct resource and use it for repeated calls to find_next_iomem_res(). When find_next_iomem_res() returns a resource, it overwrites the start, end, flags, and desc members of the struct. If we call find_next_iomem_res() again, we must update or restore these fields. The previous code restored res.start and res.end, but not res.flags or res.desc. Since the callers did not restore res.flags, if they searched for flags IORESOURCE_MEM | IORESOURCE_BUSY and found a resource with flags IORESOURCE_MEM | IORESOURCE_BUSY | IORESOURCE_SYSRAM, the next search would incorrectly skip resources unless they were also marked as IORESOURCE_SYSRAM. Fix this by restructuring the interface so it takes explicit "start, end, flags" parameters and uses "*res" only as an output parameter. Based on a patch by Lianbo Jiang <lijiang@redhat.com>. [ bp: While at it: - make comments kernel-doc style. - Originally-by: http://lore.kernel.org/lkml/20180921073211.20097-2-lijiang@redhat.com Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Borislav Petkov <bp@suse.de> CC: Andrew Morton <akpm@linux-foundation.org> CC: Brijesh Singh <brijesh.singh@amd.com> CC: Dan Williams <dan.j.williams@intel.com> CC: H. Peter Anvin <hpa@zytor.com> CC: Lianbo Jiang <lijiang@redhat.com> CC: Takashi Iwai <tiwai@suse.de> CC: Thomas Gleixner <tglx@linutronix.de> CC: Tom Lendacky <thomas.lendacky@amd.com> CC: Vivek Goyal <vgoyal@redhat.com> CC: Yaowei Bai <baiyaowei@cmss.chinamobile.com> CC: bhe@redhat.com CC: dan.j.williams@intel.com CC: dyoung@redhat.com CC: kexec@lists.infradead.org CC: mingo@redhat.com CC: x86-ml <x86@kernel.org> Link: http://lkml.kernel.org/r/153805812916.1157.177580438135143788.stgit@bhelgaas-glaptop.roam.corp.google.com
Diffstat (limited to 'kernel/resource.c')
-rw-r--r--kernel/resource.c96
1 files changed, 42 insertions, 54 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index 155ec873ea4d..38b8d11c9eaf 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -318,24 +318,27 @@ int release_resource(struct resource *old)
318 318
319EXPORT_SYMBOL(release_resource); 319EXPORT_SYMBOL(release_resource);
320 320
321/* 321/**
322 * Finds the lowest iomem resource existing within [res->start..res->end]. 322 * Finds the lowest iomem resource that covers part of [start..end]. The
323 * The caller must specify res->start, res->end, res->flags, and optionally 323 * caller must specify start, end, flags, and desc (which may be
324 * desc. If found, returns 0, res is overwritten, if not found, returns -1. 324 * IORES_DESC_NONE).
325 * This function walks the whole tree and not just first level children until 325 *
326 * and unless first_level_children_only is true. 326 * If a resource is found, returns 0 and *res is overwritten with the part
327 * of the resource that's within [start..end]; if none is found, returns
328 * -1.
329 *
330 * This function walks the whole tree and not just first level children
331 * unless @first_level_children_only is true.
327 */ 332 */
328static int find_next_iomem_res(struct resource *res, unsigned long desc, 333static int find_next_iomem_res(resource_size_t start, resource_size_t end,
329 bool first_level_children_only) 334 unsigned long flags, unsigned long desc,
335 bool first_level_children_only,
336 struct resource *res)
330{ 337{
331 resource_size_t start, end;
332 struct resource *p; 338 struct resource *p;
333 bool sibling_only = false; 339 bool sibling_only = false;
334 340
335 BUG_ON(!res); 341 BUG_ON(!res);
336
337 start = res->start;
338 end = res->end;
339 BUG_ON(start >= end); 342 BUG_ON(start >= end);
340 343
341 if (first_level_children_only) 344 if (first_level_children_only)
@@ -344,7 +347,7 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
344 read_lock(&resource_lock); 347 read_lock(&resource_lock);
345 348
346 for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) { 349 for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) {
347 if ((p->flags & res->flags) != res->flags) 350 if ((p->flags & flags) != flags)
348 continue; 351 continue;
349 if ((desc != IORES_DESC_NONE) && (desc != p->desc)) 352 if ((desc != IORES_DESC_NONE) && (desc != p->desc))
350 continue; 353 continue;
@@ -359,32 +362,31 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
359 read_unlock(&resource_lock); 362 read_unlock(&resource_lock);
360 if (!p) 363 if (!p)
361 return -1; 364 return -1;
365
362 /* copy data */ 366 /* copy data */
363 if (res->start < p->start) 367 res->start = max(start, p->start);
364 res->start = p->start; 368 res->end = min(end, p->end);
365 if (res->end > p->end)
366 res->end = p->end;
367 res->flags = p->flags; 369 res->flags = p->flags;
368 res->desc = p->desc; 370 res->desc = p->desc;
369 return 0; 371 return 0;
370} 372}
371 373
372static int __walk_iomem_res_desc(struct resource *res, unsigned long desc, 374static int __walk_iomem_res_desc(resource_size_t start, resource_size_t end,
373 bool first_level_children_only, 375 unsigned long flags, unsigned long desc,
374 void *arg, 376 bool first_level_children_only, void *arg,
375 int (*func)(struct resource *, void *)) 377 int (*func)(struct resource *, void *))
376{ 378{
377 u64 orig_end = res->end; 379 struct resource res;
378 int ret = -1; 380 int ret = -1;
379 381
380 while ((res->start < res->end) && 382 while (start < end &&
381 !find_next_iomem_res(res, desc, first_level_children_only)) { 383 !find_next_iomem_res(start, end, flags, desc,
382 ret = (*func)(res, arg); 384 first_level_children_only, &res)) {
385 ret = (*func)(&res, arg);
383 if (ret) 386 if (ret)
384 break; 387 break;
385 388
386 res->start = res->end + 1; 389 start = res.end + 1;
387 res->end = orig_end;
388 } 390 }
389 391
390 return ret; 392 return ret;
@@ -407,13 +409,7 @@ static int __walk_iomem_res_desc(struct resource *res, unsigned long desc,
407int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, 409int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start,
408 u64 end, void *arg, int (*func)(struct resource *, void *)) 410 u64 end, void *arg, int (*func)(struct resource *, void *))
409{ 411{
410 struct resource res; 412 return __walk_iomem_res_desc(start, end, flags, desc, false, arg, func);
411
412 res.start = start;
413 res.end = end;
414 res.flags = flags;
415
416 return __walk_iomem_res_desc(&res, desc, false, arg, func);
417} 413}
418EXPORT_SYMBOL_GPL(walk_iomem_res_desc); 414EXPORT_SYMBOL_GPL(walk_iomem_res_desc);
419 415
@@ -427,13 +423,9 @@ EXPORT_SYMBOL_GPL(walk_iomem_res_desc);
427int walk_system_ram_res(u64 start, u64 end, void *arg, 423int walk_system_ram_res(u64 start, u64 end, void *arg,
428 int (*func)(struct resource *, void *)) 424 int (*func)(struct resource *, void *))
429{ 425{
430 struct resource res; 426 unsigned long flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
431 427
432 res.start = start; 428 return __walk_iomem_res_desc(start, end, flags, IORES_DESC_NONE, true,
433 res.end = end;
434 res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
435
436 return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true,
437 arg, func); 429 arg, func);
438} 430}
439 431
@@ -444,13 +436,9 @@ int walk_system_ram_res(u64 start, u64 end, void *arg,
444int walk_mem_res(u64 start, u64 end, void *arg, 436int walk_mem_res(u64 start, u64 end, void *arg,
445 int (*func)(struct resource *, void *)) 437 int (*func)(struct resource *, void *))
446{ 438{
447 struct resource res; 439 unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY;
448 440
449 res.start = start; 441 return __walk_iomem_res_desc(start, end, flags, IORES_DESC_NONE, true,
450 res.end = end;
451 res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
452
453 return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true,
454 arg, func); 442 arg, func);
455} 443}
456 444
@@ -464,25 +452,25 @@ int walk_mem_res(u64 start, u64 end, void *arg,
464int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, 452int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
465 void *arg, int (*func)(unsigned long, unsigned long, void *)) 453 void *arg, int (*func)(unsigned long, unsigned long, void *))
466{ 454{
455 resource_size_t start, end;
456 unsigned long flags;
467 struct resource res; 457 struct resource res;
468 unsigned long pfn, end_pfn; 458 unsigned long pfn, end_pfn;
469 u64 orig_end;
470 int ret = -1; 459 int ret = -1;
471 460
472 res.start = (u64) start_pfn << PAGE_SHIFT; 461 start = (u64) start_pfn << PAGE_SHIFT;
473 res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1; 462 end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1;
474 res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 463 flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
475 orig_end = res.end; 464 while (start < end &&
476 while ((res.start < res.end) && 465 !find_next_iomem_res(start, end, flags, IORES_DESC_NONE,
477 (find_next_iomem_res(&res, IORES_DESC_NONE, true) >= 0)) { 466 true, &res)) {
478 pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT; 467 pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT;
479 end_pfn = (res.end + 1) >> PAGE_SHIFT; 468 end_pfn = (res.end + 1) >> PAGE_SHIFT;
480 if (end_pfn > pfn) 469 if (end_pfn > pfn)
481 ret = (*func)(pfn, end_pfn - pfn, arg); 470 ret = (*func)(pfn, end_pfn - pfn, arg);
482 if (ret) 471 if (ret)
483 break; 472 break;
484 res.start = res.end + 1; 473 start = res.end + 1;
485 res.end = orig_end;
486 } 474 }
487 return ret; 475 return ret;
488} 476}