From adb178037a763216bf25f0b69c02eb89f578db8c Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Thu, 10 May 2018 11:49:37 -0700 Subject: [PATCH] drivers: base: expose amount allocated per block Add a new sysfs node called allocated_bytes to each memory block which reports the amount of memory currently allocated from that block. Userspace can then use the allocated_byes node to better evaluate the potential cost of offlining an individual block since all the allocated memory in the block will need to be migrated when the block is offlined. Change-Id: I520de2dd56e4562a65c48e38edb1236a8cbce5fd Signed-off-by: Liam Mark Signed-off-by: Swathi Sridhar --- drivers/base/memory.c | 59 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index c10a9b122a41..0910d87afd74 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -109,7 +109,7 @@ static unsigned long get_memory_block_size(void) * uses. */ -static ssize_t show_mem_start_phys_index(struct device *dev, +static ssize_t phys_index_show(struct device *dev, struct device_attribute *attr, char *buf) { struct memory_block *mem = to_memory_block(dev); @@ -449,10 +449,62 @@ static ssize_t show_valid_zones(struct device *dev, static DEVICE_ATTR(valid_zones, 0444, show_valid_zones, NULL); #endif -static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); +#ifdef CONFIG_MEMORY_HOTPLUG +static int count_num_free_block_pages(struct zone *zone, int bid) +{ + int order, type; + unsigned long freecount = 0; + unsigned long flags; + + spin_lock_irqsave(&zone->lock, flags); + for (type = 0; type < MIGRATE_TYPES; type++) { + for (order = 0; order < MAX_ORDER; ++order) { + struct free_area *area; + struct page *page; + + area = &(zone->free_area[order]); + list_for_each_entry(page, &area->free_list[type], lru) { + unsigned long pfn = page_to_pfn(page); + int section_nr = pfn_to_section_nr(pfn); + + if (bid == base_memory_block_id(section_nr)) + freecount += (1 << order); + } + + } + } + spin_unlock_irqrestore(&zone->lock, flags); + + return freecount; +} + +static ssize_t allocated_bytes_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct memory_block *mem = to_memory_block(dev); + int block_id, free_pages; + struct zone *movable_zone = + &NODE_DATA(numa_node_id())->node_zones[ZONE_MOVABLE]; + unsigned long used, block_sz = get_memory_block_size(); + + if (mem->state != MEM_ONLINE) + return snprintf(buf, 100, "0\n"); + + block_id = base_memory_block_id(mem->start_section_nr); + free_pages = count_num_free_block_pages(movable_zone, block_id); + used = block_sz - (free_pages * PAGE_SIZE); + + return snprintf(buf, 100, "%lu\n", used); +} +#endif + +static DEVICE_ATTR_RO(phys_index, 0444, phys_index_show, NULL); static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state); static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL); static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL); +#ifdef CONFIG_MEMORY_HOTPLUG +static DEVICE_ATTR_RO(allocated_bytes, 0444, allocated_bytes_show, NULL); +#endif /* * Block size attribute stuff @@ -657,6 +709,9 @@ static struct attribute *memory_memblk_attrs[] = { &dev_attr_removable.attr, #ifdef CONFIG_MEMORY_HOTREMOVE &dev_attr_valid_zones.attr, +#endif +#ifdef CONFIG_MEMORY_HOTPLUG + &dev_attr_allocated_bytes.attr, #endif NULL };