11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * drivers/base/node.c - basic Node class support 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/sysdev.h> 61da177e4SLinus Torvalds #include <linux/module.h> 71da177e4SLinus Torvalds #include <linux/init.h> 81da177e4SLinus Torvalds #include <linux/mm.h> 9c04fc586SGary Hade #include <linux/memory.h> 101da177e4SLinus Torvalds #include <linux/node.h> 111da177e4SLinus Torvalds #include <linux/hugetlb.h> 121da177e4SLinus Torvalds #include <linux/cpumask.h> 131da177e4SLinus Torvalds #include <linux/topology.h> 141da177e4SLinus Torvalds #include <linux/nodemask.h> 1576b67ed9SKAMEZAWA Hiroyuki #include <linux/cpu.h> 16bde631a5SLee Schermerhorn #include <linux/device.h> 17af936a16SLee Schermerhorn #include <linux/swap.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds static struct sysdev_class node_class = { 20af5ca3f4SKay Sievers .name = "node", 211da177e4SLinus Torvalds }; 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds 2439106dcfSMike Travis static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf) 251da177e4SLinus Torvalds { 261da177e4SLinus Torvalds struct node *node_dev = to_node(dev); 27a70f7302SRusty Russell const struct cpumask *mask = cpumask_of_node(node_dev->sysdev.id); 281da177e4SLinus Torvalds int len; 291da177e4SLinus Torvalds 3039106dcfSMike Travis /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */ 3139106dcfSMike Travis BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1)); 321da177e4SLinus Torvalds 3339106dcfSMike Travis len = type? 3429c0177eSRusty Russell cpulist_scnprintf(buf, PAGE_SIZE-2, mask) : 3529c0177eSRusty Russell cpumask_scnprintf(buf, PAGE_SIZE-2, mask); 36c5f59f08SMike Travis buf[len++] = '\n'; 37c5f59f08SMike Travis buf[len] = '\0'; 381da177e4SLinus Torvalds return len; 391da177e4SLinus Torvalds } 401da177e4SLinus Torvalds 414a0b2b4dSAndi Kleen static inline ssize_t node_read_cpumask(struct sys_device *dev, 424a0b2b4dSAndi Kleen struct sysdev_attribute *attr, char *buf) 4339106dcfSMike Travis { 4439106dcfSMike Travis return node_read_cpumap(dev, 0, buf); 4539106dcfSMike Travis } 464a0b2b4dSAndi Kleen static inline ssize_t node_read_cpulist(struct sys_device *dev, 474a0b2b4dSAndi Kleen struct sysdev_attribute *attr, char *buf) 4839106dcfSMike Travis { 4939106dcfSMike Travis return node_read_cpumap(dev, 1, buf); 5039106dcfSMike Travis } 5139106dcfSMike Travis 5239106dcfSMike Travis static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); 5339106dcfSMike Travis static SYSDEV_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds #define K(x) ((x) << (PAGE_SHIFT - 10)) 564a0b2b4dSAndi Kleen static ssize_t node_read_meminfo(struct sys_device * dev, 574a0b2b4dSAndi Kleen struct sysdev_attribute *attr, char * buf) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds int n; 601da177e4SLinus Torvalds int nid = dev->id; 611da177e4SLinus Torvalds struct sysinfo i; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds si_meminfo_node(&i, nid); 64c07e02dbSMartin Hicks 651da177e4SLinus Torvalds n = sprintf(buf, "\n" 661da177e4SLinus Torvalds "Node %d MemTotal: %8lu kB\n" 671da177e4SLinus Torvalds "Node %d MemFree: %8lu kB\n" 681da177e4SLinus Torvalds "Node %d MemUsed: %8lu kB\n" 691da177e4SLinus Torvalds "Node %d Active: %8lu kB\n" 701da177e4SLinus Torvalds "Node %d Inactive: %8lu kB\n" 714f98a2feSRik van Riel "Node %d Active(anon): %8lu kB\n" 724f98a2feSRik van Riel "Node %d Inactive(anon): %8lu kB\n" 734f98a2feSRik van Riel "Node %d Active(file): %8lu kB\n" 744f98a2feSRik van Riel "Node %d Inactive(file): %8lu kB\n" 755344b7e6SNick Piggin "Node %d Unevictable: %8lu kB\n" 765344b7e6SNick Piggin "Node %d Mlocked: %8lu kB\n" 77182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM 781da177e4SLinus Torvalds "Node %d HighTotal: %8lu kB\n" 791da177e4SLinus Torvalds "Node %d HighFree: %8lu kB\n" 801da177e4SLinus Torvalds "Node %d LowTotal: %8lu kB\n" 81c07e02dbSMartin Hicks "Node %d LowFree: %8lu kB\n" 82182e8e23SChristoph Lameter #endif 83c07e02dbSMartin Hicks "Node %d Dirty: %8lu kB\n" 84c07e02dbSMartin Hicks "Node %d Writeback: %8lu kB\n" 85347ce434SChristoph Lameter "Node %d FilePages: %8lu kB\n" 86c07e02dbSMartin Hicks "Node %d Mapped: %8lu kB\n" 87f3dbd344SChristoph Lameter "Node %d AnonPages: %8lu kB\n" 884b02108aSKOSAKI Motohiro "Node %d Shmem: %8lu kB\n" 89c6a7f572SKOSAKI Motohiro "Node %d KernelStack: %8lu kB\n" 90df849a15SChristoph Lameter "Node %d PageTables: %8lu kB\n" 91f5ef68daSAndrew Morton "Node %d NFS_Unstable: %8lu kB\n" 92d2c5e30cSChristoph Lameter "Node %d Bounce: %8lu kB\n" 93fc3ba692SMiklos Szeredi "Node %d WritebackTmp: %8lu kB\n" 94972d1a7bSChristoph Lameter "Node %d Slab: %8lu kB\n" 95972d1a7bSChristoph Lameter "Node %d SReclaimable: %8lu kB\n" 96972d1a7bSChristoph Lameter "Node %d SUnreclaim: %8lu kB\n", 971da177e4SLinus Torvalds nid, K(i.totalram), 981da177e4SLinus Torvalds nid, K(i.freeram), 991da177e4SLinus Torvalds nid, K(i.totalram - i.freeram), 1004f98a2feSRik van Riel nid, K(node_page_state(nid, NR_ACTIVE_ANON) + 1014f98a2feSRik van Riel node_page_state(nid, NR_ACTIVE_FILE)), 1024f98a2feSRik van Riel nid, K(node_page_state(nid, NR_INACTIVE_ANON) + 1034f98a2feSRik van Riel node_page_state(nid, NR_INACTIVE_FILE)), 1044f98a2feSRik van Riel nid, K(node_page_state(nid, NR_ACTIVE_ANON)), 1054f98a2feSRik van Riel nid, K(node_page_state(nid, NR_INACTIVE_ANON)), 1064f98a2feSRik van Riel nid, K(node_page_state(nid, NR_ACTIVE_FILE)), 1074f98a2feSRik van Riel nid, K(node_page_state(nid, NR_INACTIVE_FILE)), 1087b854121SLee Schermerhorn nid, K(node_page_state(nid, NR_UNEVICTABLE)), 1095344b7e6SNick Piggin nid, K(node_page_state(nid, NR_MLOCK)), 110182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM 1111da177e4SLinus Torvalds nid, K(i.totalhigh), 1121da177e4SLinus Torvalds nid, K(i.freehigh), 1131da177e4SLinus Torvalds nid, K(i.totalram - i.totalhigh), 114c07e02dbSMartin Hicks nid, K(i.freeram - i.freehigh), 115182e8e23SChristoph Lameter #endif 116b1e7a8fdSChristoph Lameter nid, K(node_page_state(nid, NR_FILE_DIRTY)), 117ce866b34SChristoph Lameter nid, K(node_page_state(nid, NR_WRITEBACK)), 118347ce434SChristoph Lameter nid, K(node_page_state(nid, NR_FILE_PAGES)), 11965ba55f5SChristoph Lameter nid, K(node_page_state(nid, NR_FILE_MAPPED)), 120f3dbd344SChristoph Lameter nid, K(node_page_state(nid, NR_ANON_PAGES)), 1214b02108aSKOSAKI Motohiro nid, K(node_page_state(nid, NR_SHMEM)), 122c6a7f572SKOSAKI Motohiro nid, node_page_state(nid, NR_KERNEL_STACK) * 123c6a7f572SKOSAKI Motohiro THREAD_SIZE / 1024, 124df849a15SChristoph Lameter nid, K(node_page_state(nid, NR_PAGETABLE)), 125fd39fc85SChristoph Lameter nid, K(node_page_state(nid, NR_UNSTABLE_NFS)), 126d2c5e30cSChristoph Lameter nid, K(node_page_state(nid, NR_BOUNCE)), 127fc3ba692SMiklos Szeredi nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)), 128972d1a7bSChristoph Lameter nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) + 129972d1a7bSChristoph Lameter node_page_state(nid, NR_SLAB_UNRECLAIMABLE)), 130972d1a7bSChristoph Lameter nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)), 131972d1a7bSChristoph Lameter nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))); 1321da177e4SLinus Torvalds n += hugetlb_report_node_meminfo(nid, buf + n); 1331da177e4SLinus Torvalds return n; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds #undef K 1371da177e4SLinus Torvalds static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); 1381da177e4SLinus Torvalds 1394a0b2b4dSAndi Kleen static ssize_t node_read_numastat(struct sys_device * dev, 1404a0b2b4dSAndi Kleen struct sysdev_attribute *attr, char * buf) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds return sprintf(buf, 1431da177e4SLinus Torvalds "numa_hit %lu\n" 1441da177e4SLinus Torvalds "numa_miss %lu\n" 1451da177e4SLinus Torvalds "numa_foreign %lu\n" 1461da177e4SLinus Torvalds "interleave_hit %lu\n" 1471da177e4SLinus Torvalds "local_node %lu\n" 1481da177e4SLinus Torvalds "other_node %lu\n", 149ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_HIT), 150ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_MISS), 151ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_FOREIGN), 152ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_INTERLEAVE_HIT), 153ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_LOCAL), 154ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_OTHER)); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); 1571da177e4SLinus Torvalds 1584a0b2b4dSAndi Kleen static ssize_t node_read_distance(struct sys_device * dev, 1594a0b2b4dSAndi Kleen struct sysdev_attribute *attr, char * buf) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds int nid = dev->id; 1621da177e4SLinus Torvalds int len = 0; 1631da177e4SLinus Torvalds int i; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds /* buf currently PAGE_SIZE, need ~4 chars per node */ 1661da177e4SLinus Torvalds BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds for_each_online_node(i) 1691da177e4SLinus Torvalds len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i)); 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds len += sprintf(buf + len, "\n"); 1721da177e4SLinus Torvalds return len; 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); 1751da177e4SLinus Torvalds 1769a305230SLee Schermerhorn #ifdef CONFIG_HUGETLBFS 1779a305230SLee Schermerhorn /* 1789a305230SLee Schermerhorn * hugetlbfs per node attributes registration interface: 1799a305230SLee Schermerhorn * When/if hugetlb[fs] subsystem initializes [sometime after this module], 1804faf8d95SLee Schermerhorn * it will register its per node attributes for all online nodes with 1814faf8d95SLee Schermerhorn * memory. It will also call register_hugetlbfs_with_node(), below, to 1829a305230SLee Schermerhorn * register its attribute registration functions with this node driver. 1839a305230SLee Schermerhorn * Once these hooks have been initialized, the node driver will call into 1849a305230SLee Schermerhorn * the hugetlb module to [un]register attributes for hot-plugged nodes. 1859a305230SLee Schermerhorn */ 1869a305230SLee Schermerhorn static node_registration_func_t __hugetlb_register_node; 1879a305230SLee Schermerhorn static node_registration_func_t __hugetlb_unregister_node; 1889a305230SLee Schermerhorn 18939da08cbSLee Schermerhorn static inline bool hugetlb_register_node(struct node *node) 1909a305230SLee Schermerhorn { 1914faf8d95SLee Schermerhorn if (__hugetlb_register_node && 19239da08cbSLee Schermerhorn node_state(node->sysdev.id, N_HIGH_MEMORY)) { 1939a305230SLee Schermerhorn __hugetlb_register_node(node); 19439da08cbSLee Schermerhorn return true; 19539da08cbSLee Schermerhorn } 19639da08cbSLee Schermerhorn return false; 1979a305230SLee Schermerhorn } 1989a305230SLee Schermerhorn 1999a305230SLee Schermerhorn static inline void hugetlb_unregister_node(struct node *node) 2009a305230SLee Schermerhorn { 2019a305230SLee Schermerhorn if (__hugetlb_unregister_node) 2029a305230SLee Schermerhorn __hugetlb_unregister_node(node); 2039a305230SLee Schermerhorn } 2049a305230SLee Schermerhorn 2059a305230SLee Schermerhorn void register_hugetlbfs_with_node(node_registration_func_t doregister, 2069a305230SLee Schermerhorn node_registration_func_t unregister) 2079a305230SLee Schermerhorn { 2089a305230SLee Schermerhorn __hugetlb_register_node = doregister; 2099a305230SLee Schermerhorn __hugetlb_unregister_node = unregister; 2109a305230SLee Schermerhorn } 2119a305230SLee Schermerhorn #else 2129a305230SLee Schermerhorn static inline void hugetlb_register_node(struct node *node) {} 2139a305230SLee Schermerhorn 2149a305230SLee Schermerhorn static inline void hugetlb_unregister_node(struct node *node) {} 2159a305230SLee Schermerhorn #endif 2169a305230SLee Schermerhorn 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* 219405ae7d3SRobert P. J. Day * register_node - Setup a sysfs device for a node. 2201da177e4SLinus Torvalds * @num - Node number to use when creating the device. 2211da177e4SLinus Torvalds * 2221da177e4SLinus Torvalds * Initialize and register the node device. 2231da177e4SLinus Torvalds */ 2244b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds int error; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds node->sysdev.id = num; 2291da177e4SLinus Torvalds node->sysdev.cls = &node_class; 2301da177e4SLinus Torvalds error = sysdev_register(&node->sysdev); 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds if (!error){ 2331da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_cpumap); 23439106dcfSMike Travis sysdev_create_file(&node->sysdev, &attr_cpulist); 2351da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_meminfo); 2361da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_numastat); 2371da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_distance); 238af936a16SLee Schermerhorn 239af936a16SLee Schermerhorn scan_unevictable_register_node(node); 2404faf8d95SLee Schermerhorn 2419a305230SLee Schermerhorn hugetlb_register_node(node); 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds return error; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds 2464b45099bSKeiichiro Tokunaga /** 2474b45099bSKeiichiro Tokunaga * unregister_node - unregister a node device 2484b45099bSKeiichiro Tokunaga * @node: node going away 2494b45099bSKeiichiro Tokunaga * 2504b45099bSKeiichiro Tokunaga * Unregisters a node device @node. All the devices on the node must be 2514b45099bSKeiichiro Tokunaga * unregistered before calling this function. 2524b45099bSKeiichiro Tokunaga */ 2534b45099bSKeiichiro Tokunaga void unregister_node(struct node *node) 2544b45099bSKeiichiro Tokunaga { 2554b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_cpumap); 25639106dcfSMike Travis sysdev_remove_file(&node->sysdev, &attr_cpulist); 2574b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_meminfo); 2584b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_numastat); 2594b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_distance); 2601da177e4SLinus Torvalds 261af936a16SLee Schermerhorn scan_unevictable_unregister_node(node); 2624faf8d95SLee Schermerhorn hugetlb_unregister_node(node); /* no-op, if memoryless node */ 263af936a16SLee Schermerhorn 2644b45099bSKeiichiro Tokunaga sysdev_unregister(&node->sysdev); 2654b45099bSKeiichiro Tokunaga } 2664b45099bSKeiichiro Tokunaga 2670fc44159SYasunori Goto struct node node_devices[MAX_NUMNODES]; 2680fc44159SYasunori Goto 26976b67ed9SKAMEZAWA Hiroyuki /* 27076b67ed9SKAMEZAWA Hiroyuki * register cpu under node 27176b67ed9SKAMEZAWA Hiroyuki */ 27276b67ed9SKAMEZAWA Hiroyuki int register_cpu_under_node(unsigned int cpu, unsigned int nid) 27376b67ed9SKAMEZAWA Hiroyuki { 27476b67ed9SKAMEZAWA Hiroyuki if (node_online(nid)) { 27576b67ed9SKAMEZAWA Hiroyuki struct sys_device *obj = get_cpu_sysdev(cpu); 27676b67ed9SKAMEZAWA Hiroyuki if (!obj) 27776b67ed9SKAMEZAWA Hiroyuki return 0; 27876b67ed9SKAMEZAWA Hiroyuki return sysfs_create_link(&node_devices[nid].sysdev.kobj, 27976b67ed9SKAMEZAWA Hiroyuki &obj->kobj, 28076b67ed9SKAMEZAWA Hiroyuki kobject_name(&obj->kobj)); 28176b67ed9SKAMEZAWA Hiroyuki } 28276b67ed9SKAMEZAWA Hiroyuki 28376b67ed9SKAMEZAWA Hiroyuki return 0; 28476b67ed9SKAMEZAWA Hiroyuki } 28576b67ed9SKAMEZAWA Hiroyuki 28676b67ed9SKAMEZAWA Hiroyuki int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) 28776b67ed9SKAMEZAWA Hiroyuki { 28876b67ed9SKAMEZAWA Hiroyuki if (node_online(nid)) { 28976b67ed9SKAMEZAWA Hiroyuki struct sys_device *obj = get_cpu_sysdev(cpu); 29076b67ed9SKAMEZAWA Hiroyuki if (obj) 29176b67ed9SKAMEZAWA Hiroyuki sysfs_remove_link(&node_devices[nid].sysdev.kobj, 29276b67ed9SKAMEZAWA Hiroyuki kobject_name(&obj->kobj)); 29376b67ed9SKAMEZAWA Hiroyuki } 29476b67ed9SKAMEZAWA Hiroyuki return 0; 29576b67ed9SKAMEZAWA Hiroyuki } 29676b67ed9SKAMEZAWA Hiroyuki 297c04fc586SGary Hade #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE 298c04fc586SGary Hade #define page_initialized(page) (page->lru.next) 299c04fc586SGary Hade 300c04fc586SGary Hade static int get_nid_for_pfn(unsigned long pfn) 301c04fc586SGary Hade { 302c04fc586SGary Hade struct page *page; 303c04fc586SGary Hade 304c04fc586SGary Hade if (!pfn_valid_within(pfn)) 305c04fc586SGary Hade return -1; 306c04fc586SGary Hade page = pfn_to_page(pfn); 307c04fc586SGary Hade if (!page_initialized(page)) 308c04fc586SGary Hade return -1; 309c04fc586SGary Hade return pfn_to_nid(pfn); 310c04fc586SGary Hade } 311c04fc586SGary Hade 312c04fc586SGary Hade /* register memory section under specified node if it spans that node */ 313c04fc586SGary Hade int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) 314c04fc586SGary Hade { 315dee5d0d5SAlex Chiang int ret; 316c04fc586SGary Hade unsigned long pfn, sect_start_pfn, sect_end_pfn; 317c04fc586SGary Hade 318c04fc586SGary Hade if (!mem_blk) 319c04fc586SGary Hade return -EFAULT; 320c04fc586SGary Hade if (!node_online(nid)) 321c04fc586SGary Hade return 0; 322c04fc586SGary Hade sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); 323c04fc586SGary Hade sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; 324c04fc586SGary Hade for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { 325c04fc586SGary Hade int page_nid; 326c04fc586SGary Hade 327c04fc586SGary Hade page_nid = get_nid_for_pfn(pfn); 328c04fc586SGary Hade if (page_nid < 0) 329c04fc586SGary Hade continue; 330c04fc586SGary Hade if (page_nid != nid) 331c04fc586SGary Hade continue; 332dee5d0d5SAlex Chiang ret = sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj, 333c04fc586SGary Hade &mem_blk->sysdev.kobj, 334c04fc586SGary Hade kobject_name(&mem_blk->sysdev.kobj)); 335dee5d0d5SAlex Chiang if (ret) 336dee5d0d5SAlex Chiang return ret; 337dee5d0d5SAlex Chiang 338dee5d0d5SAlex Chiang return sysfs_create_link_nowarn(&mem_blk->sysdev.kobj, 339dee5d0d5SAlex Chiang &node_devices[nid].sysdev.kobj, 340dee5d0d5SAlex Chiang kobject_name(&node_devices[nid].sysdev.kobj)); 341c04fc586SGary Hade } 342c04fc586SGary Hade /* mem section does not span the specified node */ 343c04fc586SGary Hade return 0; 344c04fc586SGary Hade } 345c04fc586SGary Hade 346c04fc586SGary Hade /* unregister memory section under all nodes that it spans */ 347c04fc586SGary Hade int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) 348c04fc586SGary Hade { 349c04fc586SGary Hade nodemask_t unlinked_nodes; 350c04fc586SGary Hade unsigned long pfn, sect_start_pfn, sect_end_pfn; 351c04fc586SGary Hade 352c04fc586SGary Hade if (!mem_blk) 353c04fc586SGary Hade return -EFAULT; 354c04fc586SGary Hade nodes_clear(unlinked_nodes); 355c04fc586SGary Hade sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); 356c04fc586SGary Hade sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; 357c04fc586SGary Hade for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { 35847504980SRoel Kluin int nid; 359c04fc586SGary Hade 360c04fc586SGary Hade nid = get_nid_for_pfn(pfn); 361c04fc586SGary Hade if (nid < 0) 362c04fc586SGary Hade continue; 363c04fc586SGary Hade if (!node_online(nid)) 364c04fc586SGary Hade continue; 365c04fc586SGary Hade if (node_test_and_set(nid, unlinked_nodes)) 366c04fc586SGary Hade continue; 367c04fc586SGary Hade sysfs_remove_link(&node_devices[nid].sysdev.kobj, 368c04fc586SGary Hade kobject_name(&mem_blk->sysdev.kobj)); 369dee5d0d5SAlex Chiang sysfs_remove_link(&mem_blk->sysdev.kobj, 370dee5d0d5SAlex Chiang kobject_name(&node_devices[nid].sysdev.kobj)); 371c04fc586SGary Hade } 372c04fc586SGary Hade return 0; 373c04fc586SGary Hade } 374c04fc586SGary Hade 375c04fc586SGary Hade static int link_mem_sections(int nid) 376c04fc586SGary Hade { 377c04fc586SGary Hade unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; 378c04fc586SGary Hade unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; 379c04fc586SGary Hade unsigned long pfn; 380c04fc586SGary Hade int err = 0; 381c04fc586SGary Hade 382c04fc586SGary Hade for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { 383c04fc586SGary Hade unsigned long section_nr = pfn_to_section_nr(pfn); 384c04fc586SGary Hade struct mem_section *mem_sect; 385c04fc586SGary Hade struct memory_block *mem_blk; 386c04fc586SGary Hade int ret; 387c04fc586SGary Hade 388c04fc586SGary Hade if (!present_section_nr(section_nr)) 389c04fc586SGary Hade continue; 390c04fc586SGary Hade mem_sect = __nr_to_section(section_nr); 391c04fc586SGary Hade mem_blk = find_memory_block(mem_sect); 392c04fc586SGary Hade ret = register_mem_sect_under_node(mem_blk, nid); 393c04fc586SGary Hade if (!err) 394c04fc586SGary Hade err = ret; 395c04fc586SGary Hade 396c04fc586SGary Hade /* discard ref obtained in find_memory_block() */ 397c04fc586SGary Hade kobject_put(&mem_blk->sysdev.kobj); 398c04fc586SGary Hade } 399c04fc586SGary Hade return err; 400c04fc586SGary Hade } 4014faf8d95SLee Schermerhorn 40239da08cbSLee Schermerhorn #ifdef CONFIG_HUGETLBFS 4034faf8d95SLee Schermerhorn /* 4044faf8d95SLee Schermerhorn * Handle per node hstate attribute [un]registration on transistions 4054faf8d95SLee Schermerhorn * to/from memoryless state. 4064faf8d95SLee Schermerhorn */ 40739da08cbSLee Schermerhorn static void node_hugetlb_work(struct work_struct *work) 40839da08cbSLee Schermerhorn { 40939da08cbSLee Schermerhorn struct node *node = container_of(work, struct node, node_work); 41039da08cbSLee Schermerhorn 41139da08cbSLee Schermerhorn /* 41239da08cbSLee Schermerhorn * We only get here when a node transitions to/from memoryless state. 41339da08cbSLee Schermerhorn * We can detect which transition occurred by examining whether the 41439da08cbSLee Schermerhorn * node has memory now. hugetlb_register_node() already check this 41539da08cbSLee Schermerhorn * so we try to register the attributes. If that fails, then the 41639da08cbSLee Schermerhorn * node has transitioned to memoryless, try to unregister the 41739da08cbSLee Schermerhorn * attributes. 41839da08cbSLee Schermerhorn */ 41939da08cbSLee Schermerhorn if (!hugetlb_register_node(node)) 42039da08cbSLee Schermerhorn hugetlb_unregister_node(node); 42139da08cbSLee Schermerhorn } 42239da08cbSLee Schermerhorn 42339da08cbSLee Schermerhorn static void init_node_hugetlb_work(int nid) 42439da08cbSLee Schermerhorn { 42539da08cbSLee Schermerhorn INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work); 42639da08cbSLee Schermerhorn } 4274faf8d95SLee Schermerhorn 4284faf8d95SLee Schermerhorn static int node_memory_callback(struct notifier_block *self, 4294faf8d95SLee Schermerhorn unsigned long action, void *arg) 4304faf8d95SLee Schermerhorn { 4314faf8d95SLee Schermerhorn struct memory_notify *mnb = arg; 4324faf8d95SLee Schermerhorn int nid = mnb->status_change_nid; 4334faf8d95SLee Schermerhorn 4344faf8d95SLee Schermerhorn switch (action) { 43539da08cbSLee Schermerhorn case MEM_ONLINE: 43639da08cbSLee Schermerhorn case MEM_OFFLINE: 43739da08cbSLee Schermerhorn /* 43839da08cbSLee Schermerhorn * offload per node hstate [un]registration to a work thread 43939da08cbSLee Schermerhorn * when transitioning to/from memoryless state. 44039da08cbSLee Schermerhorn */ 4414faf8d95SLee Schermerhorn if (nid != NUMA_NO_NODE) 44239da08cbSLee Schermerhorn schedule_work(&node_devices[nid].node_work); 4434faf8d95SLee Schermerhorn break; 44439da08cbSLee Schermerhorn 4454faf8d95SLee Schermerhorn case MEM_GOING_ONLINE: 4464faf8d95SLee Schermerhorn case MEM_GOING_OFFLINE: 4474faf8d95SLee Schermerhorn case MEM_CANCEL_ONLINE: 4484faf8d95SLee Schermerhorn case MEM_CANCEL_OFFLINE: 4494faf8d95SLee Schermerhorn default: 4504faf8d95SLee Schermerhorn break; 4514faf8d95SLee Schermerhorn } 4524faf8d95SLee Schermerhorn 4534faf8d95SLee Schermerhorn return NOTIFY_OK; 4544faf8d95SLee Schermerhorn } 45539da08cbSLee Schermerhorn #endif /* CONFIG_HUGETLBFS */ 45639da08cbSLee Schermerhorn #else /* !CONFIG_MEMORY_HOTPLUG_SPARSE */ 4574faf8d95SLee Schermerhorn 45839da08cbSLee Schermerhorn static int link_mem_sections(int nid) { return 0; } 45939da08cbSLee Schermerhorn #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ 46039da08cbSLee Schermerhorn 46139da08cbSLee Schermerhorn #if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \ 46239da08cbSLee Schermerhorn !defined(CONFIG_HUGETLBFS) 4634faf8d95SLee Schermerhorn static inline int node_memory_callback(struct notifier_block *self, 4644faf8d95SLee Schermerhorn unsigned long action, void *arg) 4654faf8d95SLee Schermerhorn { 4664faf8d95SLee Schermerhorn return NOTIFY_OK; 4674faf8d95SLee Schermerhorn } 46839da08cbSLee Schermerhorn 46939da08cbSLee Schermerhorn static void init_node_hugetlb_work(int nid) { } 47039da08cbSLee Schermerhorn 47139da08cbSLee Schermerhorn #endif 472c04fc586SGary Hade 4730fc44159SYasunori Goto int register_one_node(int nid) 4740fc44159SYasunori Goto { 4750fc44159SYasunori Goto int error = 0; 47676b67ed9SKAMEZAWA Hiroyuki int cpu; 4770fc44159SYasunori Goto 4780fc44159SYasunori Goto if (node_online(nid)) { 4790fc44159SYasunori Goto int p_node = parent_node(nid); 4800fc44159SYasunori Goto struct node *parent = NULL; 4810fc44159SYasunori Goto 4820fc44159SYasunori Goto if (p_node != nid) 4830fc44159SYasunori Goto parent = &node_devices[p_node]; 4840fc44159SYasunori Goto 4850fc44159SYasunori Goto error = register_node(&node_devices[nid], nid, parent); 48676b67ed9SKAMEZAWA Hiroyuki 48776b67ed9SKAMEZAWA Hiroyuki /* link cpu under this node */ 48876b67ed9SKAMEZAWA Hiroyuki for_each_present_cpu(cpu) { 48976b67ed9SKAMEZAWA Hiroyuki if (cpu_to_node(cpu) == nid) 49076b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(cpu, nid); 49176b67ed9SKAMEZAWA Hiroyuki } 492c04fc586SGary Hade 493c04fc586SGary Hade /* link memory sections under this node */ 494c04fc586SGary Hade error = link_mem_sections(nid); 49539da08cbSLee Schermerhorn 49639da08cbSLee Schermerhorn /* initialize work queue for memory hot plug */ 49739da08cbSLee Schermerhorn init_node_hugetlb_work(nid); 4980fc44159SYasunori Goto } 4990fc44159SYasunori Goto 5000fc44159SYasunori Goto return error; 5010fc44159SYasunori Goto 5020fc44159SYasunori Goto } 5030fc44159SYasunori Goto 5040fc44159SYasunori Goto void unregister_one_node(int nid) 5050fc44159SYasunori Goto { 5060fc44159SYasunori Goto unregister_node(&node_devices[nid]); 5070fc44159SYasunori Goto } 5080fc44159SYasunori Goto 509bde631a5SLee Schermerhorn /* 510bde631a5SLee Schermerhorn * node states attributes 511bde631a5SLee Schermerhorn */ 512bde631a5SLee Schermerhorn 513bde631a5SLee Schermerhorn static ssize_t print_nodes_state(enum node_states state, char *buf) 514bde631a5SLee Schermerhorn { 515bde631a5SLee Schermerhorn int n; 516bde631a5SLee Schermerhorn 517bde631a5SLee Schermerhorn n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]); 518bde631a5SLee Schermerhorn if (n > 0 && PAGE_SIZE > n + 1) { 519bde631a5SLee Schermerhorn *(buf + n++) = '\n'; 520bde631a5SLee Schermerhorn *(buf + n++) = '\0'; 521bde631a5SLee Schermerhorn } 522bde631a5SLee Schermerhorn return n; 523bde631a5SLee Schermerhorn } 524bde631a5SLee Schermerhorn 525bde631a5SLee Schermerhorn static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf) 526bde631a5SLee Schermerhorn { 527bde631a5SLee Schermerhorn return print_nodes_state(N_POSSIBLE, buf); 528bde631a5SLee Schermerhorn } 529bde631a5SLee Schermerhorn 530bde631a5SLee Schermerhorn static ssize_t print_nodes_online(struct sysdev_class *class, char *buf) 531bde631a5SLee Schermerhorn { 532bde631a5SLee Schermerhorn return print_nodes_state(N_ONLINE, buf); 533bde631a5SLee Schermerhorn } 534bde631a5SLee Schermerhorn 535bde631a5SLee Schermerhorn static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class, 536bde631a5SLee Schermerhorn char *buf) 537bde631a5SLee Schermerhorn { 538bde631a5SLee Schermerhorn return print_nodes_state(N_NORMAL_MEMORY, buf); 539bde631a5SLee Schermerhorn } 540bde631a5SLee Schermerhorn 541bde631a5SLee Schermerhorn static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf) 542bde631a5SLee Schermerhorn { 543bde631a5SLee Schermerhorn return print_nodes_state(N_CPU, buf); 544bde631a5SLee Schermerhorn } 545bde631a5SLee Schermerhorn 546bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL); 547bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL); 548bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory, 549bde631a5SLee Schermerhorn NULL); 550bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL); 551bde631a5SLee Schermerhorn 552bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM 553bde631a5SLee Schermerhorn static ssize_t print_nodes_has_high_memory(struct sysdev_class *class, 554bde631a5SLee Schermerhorn char *buf) 555bde631a5SLee Schermerhorn { 556bde631a5SLee Schermerhorn return print_nodes_state(N_HIGH_MEMORY, buf); 557bde631a5SLee Schermerhorn } 558bde631a5SLee Schermerhorn 559bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory, 560bde631a5SLee Schermerhorn NULL); 561bde631a5SLee Schermerhorn #endif 562bde631a5SLee Schermerhorn 563bde631a5SLee Schermerhorn struct sysdev_class_attribute *node_state_attr[] = { 564bde631a5SLee Schermerhorn &attr_possible, 565bde631a5SLee Schermerhorn &attr_online, 566bde631a5SLee Schermerhorn &attr_has_normal_memory, 567bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM 568bde631a5SLee Schermerhorn &attr_has_high_memory, 569bde631a5SLee Schermerhorn #endif 570bde631a5SLee Schermerhorn &attr_has_cpu, 571bde631a5SLee Schermerhorn }; 572bde631a5SLee Schermerhorn 573bde631a5SLee Schermerhorn static int node_states_init(void) 574bde631a5SLee Schermerhorn { 575bde631a5SLee Schermerhorn int i; 576bde631a5SLee Schermerhorn int err = 0; 577bde631a5SLee Schermerhorn 578bde631a5SLee Schermerhorn for (i = 0; i < NR_NODE_STATES; i++) { 579bde631a5SLee Schermerhorn int ret; 580bde631a5SLee Schermerhorn ret = sysdev_class_create_file(&node_class, node_state_attr[i]); 581bde631a5SLee Schermerhorn if (!err) 582bde631a5SLee Schermerhorn err = ret; 583bde631a5SLee Schermerhorn } 584bde631a5SLee Schermerhorn return err; 585bde631a5SLee Schermerhorn } 586bde631a5SLee Schermerhorn 5874faf8d95SLee Schermerhorn #define NODE_CALLBACK_PRI 2 /* lower than SLAB */ 5884b45099bSKeiichiro Tokunaga static int __init register_node_type(void) 5891da177e4SLinus Torvalds { 590bde631a5SLee Schermerhorn int ret; 591bde631a5SLee Schermerhorn 592bde631a5SLee Schermerhorn ret = sysdev_class_register(&node_class); 5934faf8d95SLee Schermerhorn if (!ret) { 594bde631a5SLee Schermerhorn ret = node_states_init(); 5954faf8d95SLee Schermerhorn hotplug_memory_notifier(node_memory_callback, 5964faf8d95SLee Schermerhorn NODE_CALLBACK_PRI); 5974faf8d95SLee Schermerhorn } 598bde631a5SLee Schermerhorn 599bde631a5SLee Schermerhorn /* 600bde631a5SLee Schermerhorn * Note: we're not going to unregister the node class if we fail 601bde631a5SLee Schermerhorn * to register the node state class attribute files. 602bde631a5SLee Schermerhorn */ 603bde631a5SLee Schermerhorn return ret; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds postcore_initcall(register_node_type); 606