Let's move walk_memory_blocks() to the place where memory block logic resides and simplify it. While at it, add a type for the callback function.
Unified · Split
| @@ -44,6 +44,11 @@ static inline unsigned long pfn_to_block_id(unsigned long pfn) · 43 unmodified lines | ||
| 44 | 44 | return base_memory_block_id(pfn_to_section_nr(pfn)); |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | +static inline unsigned long phys_to_block_id(unsigned long phys) | |
| 48 | +{ | |
| 49 | + return pfn_to_block_id(PFN_DOWN(phys)); | |
| 50 | +} | |
| 51 | + | |
| 47 | 52 | static int memory_subsys_online(struct device *dev); |
| 48 | 53 | static int memory_subsys_offline(struct device *dev); |
| 49 | 54 | |
| @@ -851,3 +856,40 @@ out: · 801 unmodified lines | ||
| 851 | 856 | printk(KERN_ERR "%s() failed: %d\n", __func__, ret); |
| 852 | 857 | return ret; |
| 853 | 858 | } |
| 859 | + | |
| 860 | +/** | |
| 861 | + * walk_memory_blocks - walk through all present memory blocks overlapped | |
| 862 | + * by the range [start, start + size) | |
| 863 | + * | |
| 864 | + * @start: start address of the memory range | |
| 865 | + * @size: size of the memory range | |
| 866 | + * @arg: argument passed to func | |
| 867 | + * @func: callback for each memory section walked | |
| 868 | + * | |
| 869 | + * This function walks through all present memory blocks overlapped by the | |
| 870 | + * range [start, start + size), calling func on each memory block. | |
| 871 | + * | |
| 872 | + * In case func() returns an error, walking is aborted and the error is | |
| 873 | + * returned. | |
| 874 | + */ | |
| 875 | +int walk_memory_blocks(unsigned long start, unsigned long size, | |
| 876 | + void *arg, walk_memory_blocks_func_t func) | |
| 877 | +{ | |
| 878 | + const unsigned long start_block_id = phys_to_block_id(start); | |
| 879 | + const unsigned long end_block_id = phys_to_block_id(start + size - 1); | |
| 880 | + struct memory_block *mem; | |
| 881 | + unsigned long block_id; | |
| 882 | + int ret = 0; | |
| 883 | + | |
| 884 | + for (block_id = start_block_id; block_id <= end_block_id; block_id++) { | |
| 885 | + mem = find_memory_block_by_id(block_id, NULL); | |
| 886 | + if (!mem) | |
| 887 | + continue; | |
| 888 | + | |
| 889 | + ret = func(mem, arg); | |
| 890 | + put_device(&mem->dev); | |
| 891 | + if (ret) | |
| 892 | + break; | |
| 893 | + } | |
| 894 | + return ret; | |
| 895 | +} | |
| @@ -119,6 +119,9 @@ extern int memory_isolate_notify(unsigned long val, void *v); · 118 unmodified lines | ||
| 119 | 119 | extern struct memory_block *find_memory_block_hinted(struct mem_section *, |
| 120 | 120 | struct memory_block *); |
| 121 | 121 | extern struct memory_block *find_memory_block(struct mem_section *); |
| 122 | +typedef int (*walk_memory_blocks_func_t)(struct memory_block *, void *); | |
| 123 | +extern int walk_memory_blocks(unsigned long start, unsigned long size, | |
| 124 | + void *arg, walk_memory_blocks_func_t func); | |
| 122 | 125 | #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT) |
| 123 | 126 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ |
| 124 | 127 | |
| @@ -340,8 +340,6 @@ static inline void __remove_memory(int nid, u64 start, u64 size) {} · 339 unmodified lines | ||
| 340 | 340 | #endif /* CONFIG_MEMORY_HOTREMOVE */ |
| 341 | 341 | |
| 342 | 342 | extern void __ref free_area_init_core_hotplug(int nid); |
| 343 | −extern int walk_memory_blocks(unsigned long start, unsigned long size, | |
| 344 | − void *arg, int (*func)(struct memory_block *, void *)); | |
| 345 | 343 | extern int __add_memory(int nid, u64 start, u64 size); |
| 346 | 344 | extern int add_memory(int nid, u64 start, u64 size); |
| 347 | 345 | extern int add_memory_resource(int nid, struct resource *resource); |
| @@ -1659,62 +1659,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages) · 1658 unmodified lines | ||
| 1659 | 1659 | { |
| 1660 | 1660 | return __offline_pages(start_pfn, start_pfn + nr_pages); |
| 1661 | 1661 | } |
| 1662 | −#endif /* CONFIG_MEMORY_HOTREMOVE */ | |
| 1663 | 1662 | |
| 1664 | −/** | |
| 1665 | − * walk_memory_blocks - walk through all present memory blocks overlapped | |
| 1666 | − * by the range [start, start + size) | |
| 1667 | − * | |
| 1668 | − * @start: start address of the memory range | |
| 1669 | − * @size: size of the memory range | |
| 1670 | − * @arg: argument passed to func | |
| 1671 | − * @func: callback for each memory block walked | |
| 1672 | − * | |
| 1673 | − * This function walks through all present memory blocks overlapped by the | |
| 1674 | − * range [start, start + size), calling func on each memory block. | |
| 1675 | − * | |
| 1676 | − * Returns the return value of func. | |
| 1677 | − */ | |
| 1678 | −int walk_memory_blocks(unsigned long start, unsigned long size, | |
| 1679 | − void *arg, int (*func)(struct memory_block *, void *)) | |
| 1680 | −{ | |
| 1681 | − const unsigned long start_pfn = PFN_DOWN(start); | |
| 1682 | − const unsigned long end_pfn = PFN_UP(start + size - 1); | |
| 1683 | − struct memory_block *mem = NULL; | |
| 1684 | − struct mem_section *section; | |
| 1685 | − unsigned long pfn, section_nr; | |
| 1686 | − int ret; | |
| 1687 | − | |
| 1688 | − for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { | |
| 1689 | − section_nr = pfn_to_section_nr(pfn); | |
| 1690 | − if (!present_section_nr(section_nr)) | |
| 1691 | − continue; | |
| 1692 | − | |
| 1693 | − section = __nr_to_section(section_nr); | |
| 1694 | − /* same memblock? */ | |
| 1695 | − if (mem) | |
| 1696 | − if ((section_nr >= mem->start_section_nr) && | |
| 1697 | − (section_nr <= mem->end_section_nr)) | |
| 1698 | − continue; | |
| 1699 | − | |
| 1700 | − mem = find_memory_block_hinted(section, mem); | |
| 1701 | − if (!mem) | |
| 1702 | − continue; | |
| 1703 | − | |
| 1704 | − ret = func(mem, arg); | |
| 1705 | − if (ret) { | |
| 1706 | − kobject_put(&mem->dev.kobj); | |
| 1707 | − return ret; | |
| 1708 | − } | |
| 1709 | − } | |
| 1710 | − | |
| 1711 | − if (mem) | |
| 1712 | − kobject_put(&mem->dev.kobj); | |
| 1713 | − | |
| 1714 | − return 0; | |
| 1715 | −} | |
| 1716 | − | |
| 1717 | −#ifdef CONFIG_MEMORY_HOTREMOVE | |
| 1718 | 1663 | static int check_memblock_offlined_cb(struct memory_block *mem, void *arg) |
| 1719 | 1664 | { |
| 1720 | 1665 | int ret = !is_memblock_offlined(mem); |