xref: /openbmc/linux/drivers/base/node.c (revision 10fbcf4c)
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