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> 91da177e4SLinus Torvalds #include <linux/node.h> 101da177e4SLinus Torvalds #include <linux/hugetlb.h> 111da177e4SLinus Torvalds #include <linux/cpumask.h> 121da177e4SLinus Torvalds #include <linux/topology.h> 131da177e4SLinus Torvalds #include <linux/nodemask.h> 1476b67ed9SKAMEZAWA Hiroyuki #include <linux/cpu.h> 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds static struct sysdev_class node_class = { 171da177e4SLinus Torvalds set_kset_name("node"), 181da177e4SLinus Torvalds }; 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds static ssize_t node_read_cpumap(struct sys_device * dev, char * buf) 221da177e4SLinus Torvalds { 231da177e4SLinus Torvalds struct node *node_dev = to_node(dev); 241da177e4SLinus Torvalds cpumask_t mask = node_to_cpumask(node_dev->sysdev.id); 251da177e4SLinus Torvalds int len; 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */ 281da177e4SLinus Torvalds BUILD_BUG_ON(MAX_NUMNODES/4 > PAGE_SIZE/2); 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask); 311da177e4SLinus Torvalds len += sprintf(buf + len, "\n"); 321da177e4SLinus Torvalds return len; 331da177e4SLinus Torvalds } 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #define K(x) ((x) << (PAGE_SHIFT - 10)) 381da177e4SLinus Torvalds static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) 391da177e4SLinus Torvalds { 401da177e4SLinus Torvalds int n; 411da177e4SLinus Torvalds int nid = dev->id; 421da177e4SLinus Torvalds struct sysinfo i; 43c07e02dbSMartin Hicks struct page_state ps; 441da177e4SLinus Torvalds unsigned long inactive; 451da177e4SLinus Torvalds unsigned long active; 461da177e4SLinus Torvalds unsigned long free; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds si_meminfo_node(&i, nid); 49c07e02dbSMartin Hicks get_page_state_node(&ps, nid); 501da177e4SLinus Torvalds __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); 511da177e4SLinus Torvalds 52c07e02dbSMartin Hicks /* Check for negative values in these approximate counters */ 53c07e02dbSMartin Hicks if ((long)ps.nr_writeback < 0) 54c07e02dbSMartin Hicks ps.nr_writeback = 0; 55c07e02dbSMartin Hicks 561da177e4SLinus Torvalds n = sprintf(buf, "\n" 571da177e4SLinus Torvalds "Node %d MemTotal: %8lu kB\n" 581da177e4SLinus Torvalds "Node %d MemFree: %8lu kB\n" 591da177e4SLinus Torvalds "Node %d MemUsed: %8lu kB\n" 601da177e4SLinus Torvalds "Node %d Active: %8lu kB\n" 611da177e4SLinus Torvalds "Node %d Inactive: %8lu kB\n" 621da177e4SLinus Torvalds "Node %d HighTotal: %8lu kB\n" 631da177e4SLinus Torvalds "Node %d HighFree: %8lu kB\n" 641da177e4SLinus Torvalds "Node %d LowTotal: %8lu kB\n" 65c07e02dbSMartin Hicks "Node %d LowFree: %8lu kB\n" 66c07e02dbSMartin Hicks "Node %d Dirty: %8lu kB\n" 67c07e02dbSMartin Hicks "Node %d Writeback: %8lu kB\n" 68347ce434SChristoph Lameter "Node %d FilePages: %8lu kB\n" 69c07e02dbSMartin Hicks "Node %d Mapped: %8lu kB\n" 70f3dbd344SChristoph Lameter "Node %d AnonPages: %8lu kB\n" 71df849a15SChristoph Lameter "Node %d PageTables: %8lu kB\n" 72c07e02dbSMartin Hicks "Node %d Slab: %8lu kB\n", 731da177e4SLinus Torvalds nid, K(i.totalram), 741da177e4SLinus Torvalds nid, K(i.freeram), 751da177e4SLinus Torvalds nid, K(i.totalram - i.freeram), 761da177e4SLinus Torvalds nid, K(active), 771da177e4SLinus Torvalds nid, K(inactive), 781da177e4SLinus Torvalds nid, K(i.totalhigh), 791da177e4SLinus Torvalds nid, K(i.freehigh), 801da177e4SLinus Torvalds nid, K(i.totalram - i.totalhigh), 81c07e02dbSMartin Hicks nid, K(i.freeram - i.freehigh), 82b1e7a8fdSChristoph Lameter nid, K(node_page_state(nid, NR_FILE_DIRTY)), 83c07e02dbSMartin Hicks nid, K(ps.nr_writeback), 84347ce434SChristoph Lameter nid, K(node_page_state(nid, NR_FILE_PAGES)), 8565ba55f5SChristoph Lameter nid, K(node_page_state(nid, NR_FILE_MAPPED)), 86f3dbd344SChristoph Lameter nid, K(node_page_state(nid, NR_ANON_PAGES)), 87df849a15SChristoph Lameter nid, K(node_page_state(nid, NR_PAGETABLE)), 889a865ffaSChristoph Lameter nid, K(node_page_state(nid, NR_SLAB))); 891da177e4SLinus Torvalds n += hugetlb_report_node_meminfo(nid, buf + n); 901da177e4SLinus Torvalds return n; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds #undef K 941da177e4SLinus Torvalds static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds static ssize_t node_read_numastat(struct sys_device * dev, char * buf) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds unsigned long numa_hit, numa_miss, interleave_hit, numa_foreign; 991da177e4SLinus Torvalds unsigned long local_node, other_node; 1001da177e4SLinus Torvalds int i, cpu; 1011da177e4SLinus Torvalds pg_data_t *pg = NODE_DATA(dev->id); 1021da177e4SLinus Torvalds numa_hit = 0; 1031da177e4SLinus Torvalds numa_miss = 0; 1041da177e4SLinus Torvalds interleave_hit = 0; 1051da177e4SLinus Torvalds numa_foreign = 0; 1061da177e4SLinus Torvalds local_node = 0; 1071da177e4SLinus Torvalds other_node = 0; 1081da177e4SLinus Torvalds for (i = 0; i < MAX_NR_ZONES; i++) { 1091da177e4SLinus Torvalds struct zone *z = &pg->node_zones[i]; 11054404e72SChristoph Lameter for_each_online_cpu(cpu) { 111e7c8d5c9SChristoph Lameter struct per_cpu_pageset *ps = zone_pcp(z,cpu); 1121da177e4SLinus Torvalds numa_hit += ps->numa_hit; 1131da177e4SLinus Torvalds numa_miss += ps->numa_miss; 1141da177e4SLinus Torvalds numa_foreign += ps->numa_foreign; 1151da177e4SLinus Torvalds interleave_hit += ps->interleave_hit; 1161da177e4SLinus Torvalds local_node += ps->local_node; 1171da177e4SLinus Torvalds other_node += ps->other_node; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds return sprintf(buf, 1211da177e4SLinus Torvalds "numa_hit %lu\n" 1221da177e4SLinus Torvalds "numa_miss %lu\n" 1231da177e4SLinus Torvalds "numa_foreign %lu\n" 1241da177e4SLinus Torvalds "interleave_hit %lu\n" 1251da177e4SLinus Torvalds "local_node %lu\n" 1261da177e4SLinus Torvalds "other_node %lu\n", 1271da177e4SLinus Torvalds numa_hit, 1281da177e4SLinus Torvalds numa_miss, 1291da177e4SLinus Torvalds numa_foreign, 1301da177e4SLinus Torvalds interleave_hit, 1311da177e4SLinus Torvalds local_node, 1321da177e4SLinus Torvalds other_node); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds static ssize_t node_read_distance(struct sys_device * dev, char * buf) 1371da177e4SLinus Torvalds { 1381da177e4SLinus Torvalds int nid = dev->id; 1391da177e4SLinus Torvalds int len = 0; 1401da177e4SLinus Torvalds int i; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /* buf currently PAGE_SIZE, need ~4 chars per node */ 1431da177e4SLinus Torvalds BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2); 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds for_each_online_node(i) 1461da177e4SLinus Torvalds len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i)); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds len += sprintf(buf + len, "\n"); 1491da177e4SLinus Torvalds return len; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* 1551da177e4SLinus Torvalds * register_node - Setup a driverfs device for a node. 1561da177e4SLinus Torvalds * @num - Node number to use when creating the device. 1571da177e4SLinus Torvalds * 1581da177e4SLinus Torvalds * Initialize and register the node device. 1591da177e4SLinus Torvalds */ 1604b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds int error; 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds node->sysdev.id = num; 1651da177e4SLinus Torvalds node->sysdev.cls = &node_class; 1661da177e4SLinus Torvalds error = sysdev_register(&node->sysdev); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds if (!error){ 1691da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_cpumap); 1701da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_meminfo); 1711da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_numastat); 1721da177e4SLinus Torvalds sysdev_create_file(&node->sysdev, &attr_distance); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds return error; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1774b45099bSKeiichiro Tokunaga /** 1784b45099bSKeiichiro Tokunaga * unregister_node - unregister a node device 1794b45099bSKeiichiro Tokunaga * @node: node going away 1804b45099bSKeiichiro Tokunaga * 1814b45099bSKeiichiro Tokunaga * Unregisters a node device @node. All the devices on the node must be 1824b45099bSKeiichiro Tokunaga * unregistered before calling this function. 1834b45099bSKeiichiro Tokunaga */ 1844b45099bSKeiichiro Tokunaga void unregister_node(struct node *node) 1854b45099bSKeiichiro Tokunaga { 1864b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_cpumap); 1874b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_meminfo); 1884b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_numastat); 1894b45099bSKeiichiro Tokunaga sysdev_remove_file(&node->sysdev, &attr_distance); 1901da177e4SLinus Torvalds 1914b45099bSKeiichiro Tokunaga sysdev_unregister(&node->sysdev); 1924b45099bSKeiichiro Tokunaga } 1934b45099bSKeiichiro Tokunaga 1940fc44159SYasunori Goto struct node node_devices[MAX_NUMNODES]; 1950fc44159SYasunori Goto 19676b67ed9SKAMEZAWA Hiroyuki /* 19776b67ed9SKAMEZAWA Hiroyuki * register cpu under node 19876b67ed9SKAMEZAWA Hiroyuki */ 19976b67ed9SKAMEZAWA Hiroyuki int register_cpu_under_node(unsigned int cpu, unsigned int nid) 20076b67ed9SKAMEZAWA Hiroyuki { 20176b67ed9SKAMEZAWA Hiroyuki if (node_online(nid)) { 20276b67ed9SKAMEZAWA Hiroyuki struct sys_device *obj = get_cpu_sysdev(cpu); 20376b67ed9SKAMEZAWA Hiroyuki if (!obj) 20476b67ed9SKAMEZAWA Hiroyuki return 0; 20576b67ed9SKAMEZAWA Hiroyuki return sysfs_create_link(&node_devices[nid].sysdev.kobj, 20676b67ed9SKAMEZAWA Hiroyuki &obj->kobj, 20776b67ed9SKAMEZAWA Hiroyuki kobject_name(&obj->kobj)); 20876b67ed9SKAMEZAWA Hiroyuki } 20976b67ed9SKAMEZAWA Hiroyuki 21076b67ed9SKAMEZAWA Hiroyuki return 0; 21176b67ed9SKAMEZAWA Hiroyuki } 21276b67ed9SKAMEZAWA Hiroyuki 21376b67ed9SKAMEZAWA Hiroyuki int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) 21476b67ed9SKAMEZAWA Hiroyuki { 21576b67ed9SKAMEZAWA Hiroyuki if (node_online(nid)) { 21676b67ed9SKAMEZAWA Hiroyuki struct sys_device *obj = get_cpu_sysdev(cpu); 21776b67ed9SKAMEZAWA Hiroyuki if (obj) 21876b67ed9SKAMEZAWA Hiroyuki sysfs_remove_link(&node_devices[nid].sysdev.kobj, 21976b67ed9SKAMEZAWA Hiroyuki kobject_name(&obj->kobj)); 22076b67ed9SKAMEZAWA Hiroyuki } 22176b67ed9SKAMEZAWA Hiroyuki return 0; 22276b67ed9SKAMEZAWA Hiroyuki } 22376b67ed9SKAMEZAWA Hiroyuki 2240fc44159SYasunori Goto int register_one_node(int nid) 2250fc44159SYasunori Goto { 2260fc44159SYasunori Goto int error = 0; 22776b67ed9SKAMEZAWA Hiroyuki int cpu; 2280fc44159SYasunori Goto 2290fc44159SYasunori Goto if (node_online(nid)) { 2300fc44159SYasunori Goto int p_node = parent_node(nid); 2310fc44159SYasunori Goto struct node *parent = NULL; 2320fc44159SYasunori Goto 2330fc44159SYasunori Goto if (p_node != nid) 2340fc44159SYasunori Goto parent = &node_devices[p_node]; 2350fc44159SYasunori Goto 2360fc44159SYasunori Goto error = register_node(&node_devices[nid], nid, parent); 23776b67ed9SKAMEZAWA Hiroyuki 23876b67ed9SKAMEZAWA Hiroyuki /* link cpu under this node */ 23976b67ed9SKAMEZAWA Hiroyuki for_each_present_cpu(cpu) { 24076b67ed9SKAMEZAWA Hiroyuki if (cpu_to_node(cpu) == nid) 24176b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(cpu, nid); 24276b67ed9SKAMEZAWA Hiroyuki } 2430fc44159SYasunori Goto } 2440fc44159SYasunori Goto 2450fc44159SYasunori Goto return error; 2460fc44159SYasunori Goto 2470fc44159SYasunori Goto } 2480fc44159SYasunori Goto 2490fc44159SYasunori Goto void unregister_one_node(int nid) 2500fc44159SYasunori Goto { 2510fc44159SYasunori Goto unregister_node(&node_devices[nid]); 2520fc44159SYasunori Goto } 2530fc44159SYasunori Goto 2544b45099bSKeiichiro Tokunaga static int __init register_node_type(void) 2551da177e4SLinus Torvalds { 2561da177e4SLinus Torvalds return sysdev_class_register(&node_class); 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds postcore_initcall(register_node_type); 259