11da177e4SLinus Torvalds /* 210fbcf4cSKay Sievers * Basic Node interface support 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/module.h> 61da177e4SLinus Torvalds #include <linux/init.h> 71da177e4SLinus Torvalds #include <linux/mm.h> 8c04fc586SGary Hade #include <linux/memory.h> 9fa25c503SKOSAKI Motohiro #include <linux/vmstat.h> 101da177e4SLinus Torvalds #include <linux/node.h> 111da177e4SLinus Torvalds #include <linux/hugetlb.h> 12ed4a6d7fSMel Gorman #include <linux/compaction.h> 131da177e4SLinus Torvalds #include <linux/cpumask.h> 141da177e4SLinus Torvalds #include <linux/topology.h> 151da177e4SLinus Torvalds #include <linux/nodemask.h> 1676b67ed9SKAMEZAWA Hiroyuki #include <linux/cpu.h> 17bde631a5SLee Schermerhorn #include <linux/device.h> 18af936a16SLee Schermerhorn #include <linux/swap.h> 1918e5b539STejun Heo #include <linux/slab.h> 201da177e4SLinus Torvalds 2110fbcf4cSKay Sievers static struct bus_type node_subsys = { 22af5ca3f4SKay Sievers .name = "node", 2310fbcf4cSKay Sievers .dev_name = "node", 241da177e4SLinus Torvalds }; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds 2710fbcf4cSKay Sievers static ssize_t node_read_cpumap(struct device *dev, int type, char *buf) 281da177e4SLinus Torvalds { 291da177e4SLinus Torvalds struct node *node_dev = to_node(dev); 3010fbcf4cSKay Sievers const struct cpumask *mask = cpumask_of_node(node_dev->dev.id); 311da177e4SLinus Torvalds int len; 321da177e4SLinus Torvalds 3339106dcfSMike Travis /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */ 3439106dcfSMike Travis BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1)); 351da177e4SLinus Torvalds 3639106dcfSMike Travis len = type? 3729c0177eSRusty Russell cpulist_scnprintf(buf, PAGE_SIZE-2, mask) : 3829c0177eSRusty Russell cpumask_scnprintf(buf, PAGE_SIZE-2, mask); 39c5f59f08SMike Travis buf[len++] = '\n'; 40c5f59f08SMike Travis buf[len] = '\0'; 411da177e4SLinus Torvalds return len; 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 4410fbcf4cSKay Sievers static inline ssize_t node_read_cpumask(struct device *dev, 4510fbcf4cSKay Sievers struct device_attribute *attr, char *buf) 4639106dcfSMike Travis { 4739106dcfSMike Travis return node_read_cpumap(dev, 0, buf); 4839106dcfSMike Travis } 4910fbcf4cSKay Sievers static inline ssize_t node_read_cpulist(struct device *dev, 5010fbcf4cSKay Sievers struct device_attribute *attr, char *buf) 5139106dcfSMike Travis { 5239106dcfSMike Travis return node_read_cpumap(dev, 1, buf); 5339106dcfSMike Travis } 5439106dcfSMike Travis 5510fbcf4cSKay Sievers static DEVICE_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); 5610fbcf4cSKay Sievers static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds #define K(x) ((x) << (PAGE_SHIFT - 10)) 5910fbcf4cSKay Sievers static ssize_t node_read_meminfo(struct device *dev, 6010fbcf4cSKay Sievers struct device_attribute *attr, char *buf) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds int n; 631da177e4SLinus Torvalds int nid = dev->id; 641da177e4SLinus Torvalds struct sysinfo i; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds si_meminfo_node(&i, nid); 677ee92255SKOSAKI Motohiro n = sprintf(buf, 681da177e4SLinus Torvalds "Node %d MemTotal: %8lu kB\n" 691da177e4SLinus Torvalds "Node %d MemFree: %8lu kB\n" 701da177e4SLinus Torvalds "Node %d MemUsed: %8lu kB\n" 711da177e4SLinus Torvalds "Node %d Active: %8lu kB\n" 721da177e4SLinus Torvalds "Node %d Inactive: %8lu kB\n" 734f98a2feSRik van Riel "Node %d Active(anon): %8lu kB\n" 744f98a2feSRik van Riel "Node %d Inactive(anon): %8lu kB\n" 754f98a2feSRik van Riel "Node %d Active(file): %8lu kB\n" 764f98a2feSRik van Riel "Node %d Inactive(file): %8lu kB\n" 775344b7e6SNick Piggin "Node %d Unevictable: %8lu kB\n" 787ee92255SKOSAKI Motohiro "Node %d Mlocked: %8lu kB\n", 797ee92255SKOSAKI Motohiro nid, K(i.totalram), 807ee92255SKOSAKI Motohiro nid, K(i.freeram), 817ee92255SKOSAKI Motohiro nid, K(i.totalram - i.freeram), 827ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_ACTIVE_ANON) + 837ee92255SKOSAKI Motohiro node_page_state(nid, NR_ACTIVE_FILE)), 847ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_INACTIVE_ANON) + 857ee92255SKOSAKI Motohiro node_page_state(nid, NR_INACTIVE_FILE)), 867ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_ACTIVE_ANON)), 877ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_INACTIVE_ANON)), 887ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_ACTIVE_FILE)), 897ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_INACTIVE_FILE)), 907ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_UNEVICTABLE)), 917ee92255SKOSAKI Motohiro nid, K(node_page_state(nid, NR_MLOCK))); 927ee92255SKOSAKI Motohiro 93182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM 947ee92255SKOSAKI Motohiro n += sprintf(buf + n, 951da177e4SLinus Torvalds "Node %d HighTotal: %8lu kB\n" 961da177e4SLinus Torvalds "Node %d HighFree: %8lu kB\n" 971da177e4SLinus Torvalds "Node %d LowTotal: %8lu kB\n" 987ee92255SKOSAKI Motohiro "Node %d LowFree: %8lu kB\n", 997ee92255SKOSAKI Motohiro nid, K(i.totalhigh), 1007ee92255SKOSAKI Motohiro nid, K(i.freehigh), 1017ee92255SKOSAKI Motohiro nid, K(i.totalram - i.totalhigh), 1027ee92255SKOSAKI Motohiro nid, K(i.freeram - i.freehigh)); 103182e8e23SChristoph Lameter #endif 1047ee92255SKOSAKI Motohiro n += sprintf(buf + n, 105c07e02dbSMartin Hicks "Node %d Dirty: %8lu kB\n" 106c07e02dbSMartin Hicks "Node %d Writeback: %8lu kB\n" 107347ce434SChristoph Lameter "Node %d FilePages: %8lu kB\n" 108c07e02dbSMartin Hicks "Node %d Mapped: %8lu kB\n" 109f3dbd344SChristoph Lameter "Node %d AnonPages: %8lu kB\n" 1104b02108aSKOSAKI Motohiro "Node %d Shmem: %8lu kB\n" 111c6a7f572SKOSAKI Motohiro "Node %d KernelStack: %8lu kB\n" 112df849a15SChristoph Lameter "Node %d PageTables: %8lu kB\n" 113f5ef68daSAndrew Morton "Node %d NFS_Unstable: %8lu kB\n" 114d2c5e30cSChristoph Lameter "Node %d Bounce: %8lu kB\n" 115fc3ba692SMiklos Szeredi "Node %d WritebackTmp: %8lu kB\n" 116972d1a7bSChristoph Lameter "Node %d Slab: %8lu kB\n" 117972d1a7bSChristoph Lameter "Node %d SReclaimable: %8lu kB\n" 11805b258e9SDavid Rientjes "Node %d SUnreclaim: %8lu kB\n" 11905b258e9SDavid Rientjes #ifdef CONFIG_TRANSPARENT_HUGEPAGE 12005b258e9SDavid Rientjes "Node %d AnonHugePages: %8lu kB\n" 12105b258e9SDavid Rientjes #endif 12205b258e9SDavid Rientjes , 123b1e7a8fdSChristoph Lameter nid, K(node_page_state(nid, NR_FILE_DIRTY)), 124ce866b34SChristoph Lameter nid, K(node_page_state(nid, NR_WRITEBACK)), 125347ce434SChristoph Lameter nid, K(node_page_state(nid, NR_FILE_PAGES)), 12665ba55f5SChristoph Lameter nid, K(node_page_state(nid, NR_FILE_MAPPED)), 12705b258e9SDavid Rientjes nid, K(node_page_state(nid, NR_ANON_PAGES) 12805b258e9SDavid Rientjes #ifdef CONFIG_TRANSPARENT_HUGEPAGE 12905b258e9SDavid Rientjes + node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * 13005b258e9SDavid Rientjes HPAGE_PMD_NR 13105b258e9SDavid Rientjes #endif 13205b258e9SDavid Rientjes ), 1334b02108aSKOSAKI Motohiro nid, K(node_page_state(nid, NR_SHMEM)), 134c6a7f572SKOSAKI Motohiro nid, node_page_state(nid, NR_KERNEL_STACK) * 135c6a7f572SKOSAKI Motohiro THREAD_SIZE / 1024, 136df849a15SChristoph Lameter nid, K(node_page_state(nid, NR_PAGETABLE)), 137fd39fc85SChristoph Lameter nid, K(node_page_state(nid, NR_UNSTABLE_NFS)), 138d2c5e30cSChristoph Lameter nid, K(node_page_state(nid, NR_BOUNCE)), 139fc3ba692SMiklos Szeredi nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)), 140972d1a7bSChristoph Lameter nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) + 141972d1a7bSChristoph Lameter node_page_state(nid, NR_SLAB_UNRECLAIMABLE)), 142972d1a7bSChristoph Lameter nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)), 14305b258e9SDavid Rientjes nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)) 14405b258e9SDavid Rientjes #ifdef CONFIG_TRANSPARENT_HUGEPAGE 14505b258e9SDavid Rientjes , nid, 14605b258e9SDavid Rientjes K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * 14705b258e9SDavid Rientjes HPAGE_PMD_NR) 14805b258e9SDavid Rientjes #endif 14905b258e9SDavid Rientjes ); 1501da177e4SLinus Torvalds n += hugetlb_report_node_meminfo(nid, buf + n); 1511da177e4SLinus Torvalds return n; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds #undef K 15510fbcf4cSKay Sievers static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); 1561da177e4SLinus Torvalds 15710fbcf4cSKay Sievers static ssize_t node_read_numastat(struct device *dev, 15810fbcf4cSKay Sievers struct device_attribute *attr, char *buf) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds return sprintf(buf, 1611da177e4SLinus Torvalds "numa_hit %lu\n" 1621da177e4SLinus Torvalds "numa_miss %lu\n" 1631da177e4SLinus Torvalds "numa_foreign %lu\n" 1641da177e4SLinus Torvalds "interleave_hit %lu\n" 1651da177e4SLinus Torvalds "local_node %lu\n" 1661da177e4SLinus Torvalds "other_node %lu\n", 167ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_HIT), 168ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_MISS), 169ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_FOREIGN), 170ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_INTERLEAVE_HIT), 171ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_LOCAL), 172ca889e6cSChristoph Lameter node_page_state(dev->id, NUMA_OTHER)); 1731da177e4SLinus Torvalds } 17410fbcf4cSKay Sievers static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); 1751da177e4SLinus Torvalds 17610fbcf4cSKay Sievers static ssize_t node_read_vmstat(struct device *dev, 17710fbcf4cSKay Sievers struct device_attribute *attr, char *buf) 1782ac39037SMichael Rubin { 1792ac39037SMichael Rubin int nid = dev->id; 180fa25c503SKOSAKI Motohiro int i; 181fa25c503SKOSAKI Motohiro int n = 0; 182fa25c503SKOSAKI Motohiro 183fa25c503SKOSAKI Motohiro for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 184fa25c503SKOSAKI Motohiro n += sprintf(buf+n, "%s %lu\n", vmstat_text[i], 185fa25c503SKOSAKI Motohiro node_page_state(nid, i)); 186fa25c503SKOSAKI Motohiro 187fa25c503SKOSAKI Motohiro return n; 1882ac39037SMichael Rubin } 18910fbcf4cSKay Sievers static DEVICE_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL); 1902ac39037SMichael Rubin 19110fbcf4cSKay Sievers static ssize_t node_read_distance(struct device *dev, 19210fbcf4cSKay Sievers struct device_attribute *attr, char * buf) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds int nid = dev->id; 1951da177e4SLinus Torvalds int len = 0; 1961da177e4SLinus Torvalds int i; 1971da177e4SLinus Torvalds 19812ee3c0aSDavid Rientjes /* 19912ee3c0aSDavid Rientjes * buf is currently PAGE_SIZE in length and each node needs 4 chars 20012ee3c0aSDavid Rientjes * at the most (distance + space or newline). 20112ee3c0aSDavid Rientjes */ 20212ee3c0aSDavid Rientjes BUILD_BUG_ON(MAX_NUMNODES * 4 > PAGE_SIZE); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds for_each_online_node(i) 2051da177e4SLinus Torvalds len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i)); 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds len += sprintf(buf + len, "\n"); 2081da177e4SLinus Torvalds return len; 2091da177e4SLinus Torvalds } 21010fbcf4cSKay Sievers static DEVICE_ATTR(distance, S_IRUGO, node_read_distance, NULL); 2111da177e4SLinus Torvalds 2129a305230SLee Schermerhorn #ifdef CONFIG_HUGETLBFS 2139a305230SLee Schermerhorn /* 2149a305230SLee Schermerhorn * hugetlbfs per node attributes registration interface: 2159a305230SLee Schermerhorn * When/if hugetlb[fs] subsystem initializes [sometime after this module], 2164faf8d95SLee Schermerhorn * it will register its per node attributes for all online nodes with 2174faf8d95SLee Schermerhorn * memory. It will also call register_hugetlbfs_with_node(), below, to 2189a305230SLee Schermerhorn * register its attribute registration functions with this node driver. 2199a305230SLee Schermerhorn * Once these hooks have been initialized, the node driver will call into 2209a305230SLee Schermerhorn * the hugetlb module to [un]register attributes for hot-plugged nodes. 2219a305230SLee Schermerhorn */ 2229a305230SLee Schermerhorn static node_registration_func_t __hugetlb_register_node; 2239a305230SLee Schermerhorn static node_registration_func_t __hugetlb_unregister_node; 2249a305230SLee Schermerhorn 22539da08cbSLee Schermerhorn static inline bool hugetlb_register_node(struct node *node) 2269a305230SLee Schermerhorn { 2274faf8d95SLee Schermerhorn if (__hugetlb_register_node && 22810fbcf4cSKay Sievers node_state(node->dev.id, N_HIGH_MEMORY)) { 2299a305230SLee Schermerhorn __hugetlb_register_node(node); 23039da08cbSLee Schermerhorn return true; 23139da08cbSLee Schermerhorn } 23239da08cbSLee Schermerhorn return false; 2339a305230SLee Schermerhorn } 2349a305230SLee Schermerhorn 2359a305230SLee Schermerhorn static inline void hugetlb_unregister_node(struct node *node) 2369a305230SLee Schermerhorn { 2379a305230SLee Schermerhorn if (__hugetlb_unregister_node) 2389a305230SLee Schermerhorn __hugetlb_unregister_node(node); 2399a305230SLee Schermerhorn } 2409a305230SLee Schermerhorn 2419a305230SLee Schermerhorn void register_hugetlbfs_with_node(node_registration_func_t doregister, 2429a305230SLee Schermerhorn node_registration_func_t unregister) 2439a305230SLee Schermerhorn { 2449a305230SLee Schermerhorn __hugetlb_register_node = doregister; 2459a305230SLee Schermerhorn __hugetlb_unregister_node = unregister; 2469a305230SLee Schermerhorn } 2479a305230SLee Schermerhorn #else 2489a305230SLee Schermerhorn static inline void hugetlb_register_node(struct node *node) {} 2499a305230SLee Schermerhorn 2509a305230SLee Schermerhorn static inline void hugetlb_unregister_node(struct node *node) {} 2519a305230SLee Schermerhorn #endif 2529a305230SLee Schermerhorn 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /* 255405ae7d3SRobert P. J. Day * register_node - Setup a sysfs device for a node. 2561da177e4SLinus Torvalds * @num - Node number to use when creating the device. 2571da177e4SLinus Torvalds * 2581da177e4SLinus Torvalds * Initialize and register the node device. 2591da177e4SLinus Torvalds */ 2604b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds int error; 2631da177e4SLinus Torvalds 26410fbcf4cSKay Sievers node->dev.id = num; 26510fbcf4cSKay Sievers node->dev.bus = &node_subsys; 26610fbcf4cSKay Sievers error = device_register(&node->dev); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds if (!error){ 26910fbcf4cSKay Sievers device_create_file(&node->dev, &dev_attr_cpumap); 27010fbcf4cSKay Sievers device_create_file(&node->dev, &dev_attr_cpulist); 27110fbcf4cSKay Sievers device_create_file(&node->dev, &dev_attr_meminfo); 27210fbcf4cSKay Sievers device_create_file(&node->dev, &dev_attr_numastat); 27310fbcf4cSKay Sievers device_create_file(&node->dev, &dev_attr_distance); 27410fbcf4cSKay Sievers device_create_file(&node->dev, &dev_attr_vmstat); 275af936a16SLee Schermerhorn 276af936a16SLee Schermerhorn scan_unevictable_register_node(node); 2774faf8d95SLee Schermerhorn 2789a305230SLee Schermerhorn hugetlb_register_node(node); 279ed4a6d7fSMel Gorman 280ed4a6d7fSMel Gorman compaction_register_node(node); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds return error; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds 2854b45099bSKeiichiro Tokunaga /** 2864b45099bSKeiichiro Tokunaga * unregister_node - unregister a node device 2874b45099bSKeiichiro Tokunaga * @node: node going away 2884b45099bSKeiichiro Tokunaga * 2894b45099bSKeiichiro Tokunaga * Unregisters a node device @node. All the devices on the node must be 2904b45099bSKeiichiro Tokunaga * unregistered before calling this function. 2914b45099bSKeiichiro Tokunaga */ 2924b45099bSKeiichiro Tokunaga void unregister_node(struct node *node) 2934b45099bSKeiichiro Tokunaga { 29410fbcf4cSKay Sievers device_remove_file(&node->dev, &dev_attr_cpumap); 29510fbcf4cSKay Sievers device_remove_file(&node->dev, &dev_attr_cpulist); 29610fbcf4cSKay Sievers device_remove_file(&node->dev, &dev_attr_meminfo); 29710fbcf4cSKay Sievers device_remove_file(&node->dev, &dev_attr_numastat); 29810fbcf4cSKay Sievers device_remove_file(&node->dev, &dev_attr_distance); 29910fbcf4cSKay Sievers device_remove_file(&node->dev, &dev_attr_vmstat); 3001da177e4SLinus Torvalds 301af936a16SLee Schermerhorn scan_unevictable_unregister_node(node); 3024faf8d95SLee Schermerhorn hugetlb_unregister_node(node); /* no-op, if memoryless node */ 303af936a16SLee Schermerhorn 30410fbcf4cSKay Sievers device_unregister(&node->dev); 3054b45099bSKeiichiro Tokunaga } 3064b45099bSKeiichiro Tokunaga 3070fc44159SYasunori Goto struct node node_devices[MAX_NUMNODES]; 3080fc44159SYasunori Goto 30976b67ed9SKAMEZAWA Hiroyuki /* 31076b67ed9SKAMEZAWA Hiroyuki * register cpu under node 31176b67ed9SKAMEZAWA Hiroyuki */ 31276b67ed9SKAMEZAWA Hiroyuki int register_cpu_under_node(unsigned int cpu, unsigned int nid) 31376b67ed9SKAMEZAWA Hiroyuki { 3141830794aSAlex Chiang int ret; 3158a25a2fdSKay Sievers struct device *obj; 316f8246f31SAlex Chiang 317f8246f31SAlex Chiang if (!node_online(nid)) 318f8246f31SAlex Chiang return 0; 319f8246f31SAlex Chiang 3208a25a2fdSKay Sievers obj = get_cpu_device(cpu); 32176b67ed9SKAMEZAWA Hiroyuki if (!obj) 32276b67ed9SKAMEZAWA Hiroyuki return 0; 323f8246f31SAlex Chiang 32410fbcf4cSKay Sievers ret = sysfs_create_link(&node_devices[nid].dev.kobj, 32576b67ed9SKAMEZAWA Hiroyuki &obj->kobj, 32676b67ed9SKAMEZAWA Hiroyuki kobject_name(&obj->kobj)); 3271830794aSAlex Chiang if (ret) 3281830794aSAlex Chiang return ret; 3291830794aSAlex Chiang 3301830794aSAlex Chiang return sysfs_create_link(&obj->kobj, 33110fbcf4cSKay Sievers &node_devices[nid].dev.kobj, 33210fbcf4cSKay Sievers kobject_name(&node_devices[nid].dev.kobj)); 33376b67ed9SKAMEZAWA Hiroyuki } 33476b67ed9SKAMEZAWA Hiroyuki 33576b67ed9SKAMEZAWA Hiroyuki int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) 33676b67ed9SKAMEZAWA Hiroyuki { 3378a25a2fdSKay Sievers struct device *obj; 338b9d52dadSAlex Chiang 339b9d52dadSAlex Chiang if (!node_online(nid)) 340b9d52dadSAlex Chiang return 0; 341b9d52dadSAlex Chiang 3428a25a2fdSKay Sievers obj = get_cpu_device(cpu); 343b9d52dadSAlex Chiang if (!obj) 344b9d52dadSAlex Chiang return 0; 345b9d52dadSAlex Chiang 34610fbcf4cSKay Sievers sysfs_remove_link(&node_devices[nid].dev.kobj, 34776b67ed9SKAMEZAWA Hiroyuki kobject_name(&obj->kobj)); 3481830794aSAlex Chiang sysfs_remove_link(&obj->kobj, 34910fbcf4cSKay Sievers kobject_name(&node_devices[nid].dev.kobj)); 350b9d52dadSAlex Chiang 35176b67ed9SKAMEZAWA Hiroyuki return 0; 35276b67ed9SKAMEZAWA Hiroyuki } 35376b67ed9SKAMEZAWA Hiroyuki 354c04fc586SGary Hade #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE 355c04fc586SGary Hade #define page_initialized(page) (page->lru.next) 356c04fc586SGary Hade 357c04fc586SGary Hade static int get_nid_for_pfn(unsigned long pfn) 358c04fc586SGary Hade { 359c04fc586SGary Hade struct page *page; 360c04fc586SGary Hade 361c04fc586SGary Hade if (!pfn_valid_within(pfn)) 362c04fc586SGary Hade return -1; 363c04fc586SGary Hade page = pfn_to_page(pfn); 364c04fc586SGary Hade if (!page_initialized(page)) 365c04fc586SGary Hade return -1; 366c04fc586SGary Hade return pfn_to_nid(pfn); 367c04fc586SGary Hade } 368c04fc586SGary Hade 369c04fc586SGary Hade /* register memory section under specified node if it spans that node */ 370c04fc586SGary Hade int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) 371c04fc586SGary Hade { 372dee5d0d5SAlex Chiang int ret; 373c04fc586SGary Hade unsigned long pfn, sect_start_pfn, sect_end_pfn; 374c04fc586SGary Hade 375c04fc586SGary Hade if (!mem_blk) 376c04fc586SGary Hade return -EFAULT; 377c04fc586SGary Hade if (!node_online(nid)) 378c04fc586SGary Hade return 0; 379d3360164SNathan Fontenot 380d3360164SNathan Fontenot sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr); 381d3360164SNathan Fontenot sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr); 382d3360164SNathan Fontenot sect_end_pfn += PAGES_PER_SECTION - 1; 383c04fc586SGary Hade for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { 384c04fc586SGary Hade int page_nid; 385c04fc586SGary Hade 386c04fc586SGary Hade page_nid = get_nid_for_pfn(pfn); 387c04fc586SGary Hade if (page_nid < 0) 388c04fc586SGary Hade continue; 389c04fc586SGary Hade if (page_nid != nid) 390c04fc586SGary Hade continue; 39110fbcf4cSKay Sievers ret = sysfs_create_link_nowarn(&node_devices[nid].dev.kobj, 39210fbcf4cSKay Sievers &mem_blk->dev.kobj, 39310fbcf4cSKay Sievers kobject_name(&mem_blk->dev.kobj)); 394dee5d0d5SAlex Chiang if (ret) 395dee5d0d5SAlex Chiang return ret; 396dee5d0d5SAlex Chiang 39710fbcf4cSKay Sievers return sysfs_create_link_nowarn(&mem_blk->dev.kobj, 39810fbcf4cSKay Sievers &node_devices[nid].dev.kobj, 39910fbcf4cSKay Sievers kobject_name(&node_devices[nid].dev.kobj)); 400c04fc586SGary Hade } 401c04fc586SGary Hade /* mem section does not span the specified node */ 402c04fc586SGary Hade return 0; 403c04fc586SGary Hade } 404c04fc586SGary Hade 405c04fc586SGary Hade /* unregister memory section under all nodes that it spans */ 406d3360164SNathan Fontenot int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, 407d3360164SNathan Fontenot unsigned long phys_index) 408c04fc586SGary Hade { 4099ae49fabSDavid Rientjes NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL); 410c04fc586SGary Hade unsigned long pfn, sect_start_pfn, sect_end_pfn; 411c04fc586SGary Hade 4129ae49fabSDavid Rientjes if (!mem_blk) { 4139ae49fabSDavid Rientjes NODEMASK_FREE(unlinked_nodes); 414c04fc586SGary Hade return -EFAULT; 4159ae49fabSDavid Rientjes } 4169ae49fabSDavid Rientjes if (!unlinked_nodes) 4179ae49fabSDavid Rientjes return -ENOMEM; 4189ae49fabSDavid Rientjes nodes_clear(*unlinked_nodes); 419d3360164SNathan Fontenot 420d3360164SNathan Fontenot sect_start_pfn = section_nr_to_pfn(phys_index); 421c04fc586SGary Hade sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; 422c04fc586SGary Hade for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { 42347504980SRoel Kluin int nid; 424c04fc586SGary Hade 425c04fc586SGary Hade nid = get_nid_for_pfn(pfn); 426c04fc586SGary Hade if (nid < 0) 427c04fc586SGary Hade continue; 428c04fc586SGary Hade if (!node_online(nid)) 429c04fc586SGary Hade continue; 4309ae49fabSDavid Rientjes if (node_test_and_set(nid, *unlinked_nodes)) 431c04fc586SGary Hade continue; 43210fbcf4cSKay Sievers sysfs_remove_link(&node_devices[nid].dev.kobj, 43310fbcf4cSKay Sievers kobject_name(&mem_blk->dev.kobj)); 43410fbcf4cSKay Sievers sysfs_remove_link(&mem_blk->dev.kobj, 43510fbcf4cSKay Sievers kobject_name(&node_devices[nid].dev.kobj)); 436c04fc586SGary Hade } 4379ae49fabSDavid Rientjes NODEMASK_FREE(unlinked_nodes); 438c04fc586SGary Hade return 0; 439c04fc586SGary Hade } 440c04fc586SGary Hade 441c04fc586SGary Hade static int link_mem_sections(int nid) 442c04fc586SGary Hade { 443c04fc586SGary Hade unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; 444c04fc586SGary Hade unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; 445c04fc586SGary Hade unsigned long pfn; 44663d027a6SRobin Holt struct memory_block *mem_blk = NULL; 447c04fc586SGary Hade int err = 0; 448c04fc586SGary Hade 449c04fc586SGary Hade for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { 450c04fc586SGary Hade unsigned long section_nr = pfn_to_section_nr(pfn); 451c04fc586SGary Hade struct mem_section *mem_sect; 452c04fc586SGary Hade int ret; 453c04fc586SGary Hade 454c04fc586SGary Hade if (!present_section_nr(section_nr)) 455c04fc586SGary Hade continue; 456c04fc586SGary Hade mem_sect = __nr_to_section(section_nr); 45763d027a6SRobin Holt mem_blk = find_memory_block_hinted(mem_sect, mem_blk); 458c04fc586SGary Hade ret = register_mem_sect_under_node(mem_blk, nid); 459c04fc586SGary Hade if (!err) 460c04fc586SGary Hade err = ret; 461c04fc586SGary Hade 462c04fc586SGary Hade /* discard ref obtained in find_memory_block() */ 463c04fc586SGary Hade } 46463d027a6SRobin Holt 46563d027a6SRobin Holt if (mem_blk) 46610fbcf4cSKay Sievers kobject_put(&mem_blk->dev.kobj); 467c04fc586SGary Hade return err; 468c04fc586SGary Hade } 4694faf8d95SLee Schermerhorn 47039da08cbSLee Schermerhorn #ifdef CONFIG_HUGETLBFS 4714faf8d95SLee Schermerhorn /* 4724faf8d95SLee Schermerhorn * Handle per node hstate attribute [un]registration on transistions 4734faf8d95SLee Schermerhorn * to/from memoryless state. 4744faf8d95SLee Schermerhorn */ 47539da08cbSLee Schermerhorn static void node_hugetlb_work(struct work_struct *work) 47639da08cbSLee Schermerhorn { 47739da08cbSLee Schermerhorn struct node *node = container_of(work, struct node, node_work); 47839da08cbSLee Schermerhorn 47939da08cbSLee Schermerhorn /* 48039da08cbSLee Schermerhorn * We only get here when a node transitions to/from memoryless state. 48139da08cbSLee Schermerhorn * We can detect which transition occurred by examining whether the 48239da08cbSLee Schermerhorn * node has memory now. hugetlb_register_node() already check this 48339da08cbSLee Schermerhorn * so we try to register the attributes. If that fails, then the 48439da08cbSLee Schermerhorn * node has transitioned to memoryless, try to unregister the 48539da08cbSLee Schermerhorn * attributes. 48639da08cbSLee Schermerhorn */ 48739da08cbSLee Schermerhorn if (!hugetlb_register_node(node)) 48839da08cbSLee Schermerhorn hugetlb_unregister_node(node); 48939da08cbSLee Schermerhorn } 49039da08cbSLee Schermerhorn 49139da08cbSLee Schermerhorn static void init_node_hugetlb_work(int nid) 49239da08cbSLee Schermerhorn { 49339da08cbSLee Schermerhorn INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work); 49439da08cbSLee Schermerhorn } 4954faf8d95SLee Schermerhorn 4964faf8d95SLee Schermerhorn static int node_memory_callback(struct notifier_block *self, 4974faf8d95SLee Schermerhorn unsigned long action, void *arg) 4984faf8d95SLee Schermerhorn { 4994faf8d95SLee Schermerhorn struct memory_notify *mnb = arg; 5004faf8d95SLee Schermerhorn int nid = mnb->status_change_nid; 5014faf8d95SLee Schermerhorn 5024faf8d95SLee Schermerhorn switch (action) { 50339da08cbSLee Schermerhorn case MEM_ONLINE: 50439da08cbSLee Schermerhorn case MEM_OFFLINE: 50539da08cbSLee Schermerhorn /* 50639da08cbSLee Schermerhorn * offload per node hstate [un]registration to a work thread 50739da08cbSLee Schermerhorn * when transitioning to/from memoryless state. 50839da08cbSLee Schermerhorn */ 5094faf8d95SLee Schermerhorn if (nid != NUMA_NO_NODE) 51039da08cbSLee Schermerhorn schedule_work(&node_devices[nid].node_work); 5114faf8d95SLee Schermerhorn break; 51239da08cbSLee Schermerhorn 5134faf8d95SLee Schermerhorn case MEM_GOING_ONLINE: 5144faf8d95SLee Schermerhorn case MEM_GOING_OFFLINE: 5154faf8d95SLee Schermerhorn case MEM_CANCEL_ONLINE: 5164faf8d95SLee Schermerhorn case MEM_CANCEL_OFFLINE: 5174faf8d95SLee Schermerhorn default: 5184faf8d95SLee Schermerhorn break; 5194faf8d95SLee Schermerhorn } 5204faf8d95SLee Schermerhorn 5214faf8d95SLee Schermerhorn return NOTIFY_OK; 5224faf8d95SLee Schermerhorn } 52339da08cbSLee Schermerhorn #endif /* CONFIG_HUGETLBFS */ 52439da08cbSLee Schermerhorn #else /* !CONFIG_MEMORY_HOTPLUG_SPARSE */ 5254faf8d95SLee Schermerhorn 52639da08cbSLee Schermerhorn static int link_mem_sections(int nid) { return 0; } 52739da08cbSLee Schermerhorn #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ 52839da08cbSLee Schermerhorn 52939da08cbSLee Schermerhorn #if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \ 53039da08cbSLee Schermerhorn !defined(CONFIG_HUGETLBFS) 5314faf8d95SLee Schermerhorn static inline int node_memory_callback(struct notifier_block *self, 5324faf8d95SLee Schermerhorn unsigned long action, void *arg) 5334faf8d95SLee Schermerhorn { 5344faf8d95SLee Schermerhorn return NOTIFY_OK; 5354faf8d95SLee Schermerhorn } 53639da08cbSLee Schermerhorn 53739da08cbSLee Schermerhorn static void init_node_hugetlb_work(int nid) { } 53839da08cbSLee Schermerhorn 53939da08cbSLee Schermerhorn #endif 540c04fc586SGary Hade 5410fc44159SYasunori Goto int register_one_node(int nid) 5420fc44159SYasunori Goto { 5430fc44159SYasunori Goto int error = 0; 54476b67ed9SKAMEZAWA Hiroyuki int cpu; 5450fc44159SYasunori Goto 5460fc44159SYasunori Goto if (node_online(nid)) { 5470fc44159SYasunori Goto int p_node = parent_node(nid); 5480fc44159SYasunori Goto struct node *parent = NULL; 5490fc44159SYasunori Goto 5500fc44159SYasunori Goto if (p_node != nid) 5510fc44159SYasunori Goto parent = &node_devices[p_node]; 5520fc44159SYasunori Goto 5530fc44159SYasunori Goto error = register_node(&node_devices[nid], nid, parent); 55476b67ed9SKAMEZAWA Hiroyuki 55576b67ed9SKAMEZAWA Hiroyuki /* link cpu under this node */ 55676b67ed9SKAMEZAWA Hiroyuki for_each_present_cpu(cpu) { 55776b67ed9SKAMEZAWA Hiroyuki if (cpu_to_node(cpu) == nid) 55876b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(cpu, nid); 55976b67ed9SKAMEZAWA Hiroyuki } 560c04fc586SGary Hade 561c04fc586SGary Hade /* link memory sections under this node */ 562c04fc586SGary Hade error = link_mem_sections(nid); 56339da08cbSLee Schermerhorn 56439da08cbSLee Schermerhorn /* initialize work queue for memory hot plug */ 56539da08cbSLee Schermerhorn init_node_hugetlb_work(nid); 5660fc44159SYasunori Goto } 5670fc44159SYasunori Goto 5680fc44159SYasunori Goto return error; 5690fc44159SYasunori Goto 5700fc44159SYasunori Goto } 5710fc44159SYasunori Goto 5720fc44159SYasunori Goto void unregister_one_node(int nid) 5730fc44159SYasunori Goto { 5740fc44159SYasunori Goto unregister_node(&node_devices[nid]); 5750fc44159SYasunori Goto } 5760fc44159SYasunori Goto 577bde631a5SLee Schermerhorn /* 578bde631a5SLee Schermerhorn * node states attributes 579bde631a5SLee Schermerhorn */ 580bde631a5SLee Schermerhorn 581bde631a5SLee Schermerhorn static ssize_t print_nodes_state(enum node_states state, char *buf) 582bde631a5SLee Schermerhorn { 583bde631a5SLee Schermerhorn int n; 584bde631a5SLee Schermerhorn 585bde631a5SLee Schermerhorn n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]); 586bde631a5SLee Schermerhorn if (n > 0 && PAGE_SIZE > n + 1) { 587bde631a5SLee Schermerhorn *(buf + n++) = '\n'; 588bde631a5SLee Schermerhorn *(buf + n++) = '\0'; 589bde631a5SLee Schermerhorn } 590bde631a5SLee Schermerhorn return n; 591bde631a5SLee Schermerhorn } 592bde631a5SLee Schermerhorn 593b15f562fSAndi Kleen struct node_attr { 59410fbcf4cSKay Sievers struct device_attribute attr; 595b15f562fSAndi Kleen enum node_states state; 596b15f562fSAndi Kleen }; 597b15f562fSAndi Kleen 59810fbcf4cSKay Sievers static ssize_t show_node_state(struct device *dev, 59910fbcf4cSKay Sievers struct device_attribute *attr, char *buf) 600bde631a5SLee Schermerhorn { 601b15f562fSAndi Kleen struct node_attr *na = container_of(attr, struct node_attr, attr); 602b15f562fSAndi Kleen return print_nodes_state(na->state, buf); 603bde631a5SLee Schermerhorn } 604bde631a5SLee Schermerhorn 605b15f562fSAndi Kleen #define _NODE_ATTR(name, state) \ 60610fbcf4cSKay Sievers { __ATTR(name, 0444, show_node_state, NULL), state } 607bde631a5SLee Schermerhorn 608b15f562fSAndi Kleen static struct node_attr node_state_attr[] = { 609b15f562fSAndi Kleen _NODE_ATTR(possible, N_POSSIBLE), 610b15f562fSAndi Kleen _NODE_ATTR(online, N_ONLINE), 611b15f562fSAndi Kleen _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY), 612b15f562fSAndi Kleen _NODE_ATTR(has_cpu, N_CPU), 613bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM 614b15f562fSAndi Kleen _NODE_ATTR(has_high_memory, N_HIGH_MEMORY), 615bde631a5SLee Schermerhorn #endif 616bde631a5SLee Schermerhorn }; 617bde631a5SLee Schermerhorn 61810fbcf4cSKay Sievers static struct attribute *node_state_attrs[] = { 61910fbcf4cSKay Sievers &node_state_attr[0].attr.attr, 62010fbcf4cSKay Sievers &node_state_attr[1].attr.attr, 62110fbcf4cSKay Sievers &node_state_attr[2].attr.attr, 62210fbcf4cSKay Sievers &node_state_attr[3].attr.attr, 6233701cde6SAndi Kleen #ifdef CONFIG_HIGHMEM 62410fbcf4cSKay Sievers &node_state_attr[4].attr.attr, 6253701cde6SAndi Kleen #endif 6263701cde6SAndi Kleen NULL 6273701cde6SAndi Kleen }; 628bde631a5SLee Schermerhorn 62910fbcf4cSKay Sievers static struct attribute_group memory_root_attr_group = { 63010fbcf4cSKay Sievers .attrs = node_state_attrs, 63110fbcf4cSKay Sievers }; 63210fbcf4cSKay Sievers 63310fbcf4cSKay Sievers static const struct attribute_group *cpu_root_attr_groups[] = { 63410fbcf4cSKay Sievers &memory_root_attr_group, 63510fbcf4cSKay Sievers NULL, 63610fbcf4cSKay Sievers }; 63710fbcf4cSKay Sievers 6384faf8d95SLee Schermerhorn #define NODE_CALLBACK_PRI 2 /* lower than SLAB */ 6394b45099bSKeiichiro Tokunaga static int __init register_node_type(void) 6401da177e4SLinus Torvalds { 641bde631a5SLee Schermerhorn int ret; 642bde631a5SLee Schermerhorn 6433701cde6SAndi Kleen BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES); 6443701cde6SAndi Kleen BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES); 6453701cde6SAndi Kleen 64610fbcf4cSKay Sievers ret = subsys_system_register(&node_subsys, cpu_root_attr_groups); 6474faf8d95SLee Schermerhorn if (!ret) { 6484faf8d95SLee Schermerhorn hotplug_memory_notifier(node_memory_callback, 6494faf8d95SLee Schermerhorn NODE_CALLBACK_PRI); 6504faf8d95SLee Schermerhorn } 651bde631a5SLee Schermerhorn 652bde631a5SLee Schermerhorn /* 653bde631a5SLee Schermerhorn * Note: we're not going to unregister the node class if we fail 654bde631a5SLee Schermerhorn * to register the node state class attribute files. 655bde631a5SLee Schermerhorn */ 656bde631a5SLee Schermerhorn return ret; 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds postcore_initcall(register_node_type); 659