blob: 2de546a040a5c949fce04fc3548d72ac1bd7158a [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Kay Sievers10fbcf42011-12-21 14:48:43 -08003 * Basic Node interface support
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 */
5
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <linux/module.h>
7#include <linux/init.h>
8#include <linux/mm.h>
Gary Hadec04fc582009-01-06 14:39:14 -08009#include <linux/memory.h>
KOSAKI Motohirofa25c502011-05-24 17:11:28 -070010#include <linux/vmstat.h>
Andrew Morton6e259e72013-04-29 15:08:07 -070011#include <linux/notifier.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/node.h>
13#include <linux/hugetlb.h>
Mel Gormaned4a6d72010-05-24 14:32:29 -070014#include <linux/compaction.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/cpumask.h>
16#include <linux/topology.h>
17#include <linux/nodemask.h>
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -070018#include <linux/cpu.h>
Lee Schermerhornbde631a2007-10-16 01:26:27 -070019#include <linux/device.h>
Keith Busch08d9dbe2019-03-11 14:56:00 -060020#include <linux/pm_runtime.h>
Lee Schermerhornaf936a12008-10-18 20:26:53 -070021#include <linux/swap.h>
Tejun Heo18e5b532010-04-06 19:23:33 +090022#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Kay Sievers10fbcf42011-12-21 14:48:43 -080024static struct bus_type node_subsys = {
Kay Sieversaf5ca3f42007-12-20 02:09:39 +010025 .name = "node",
Kay Sievers10fbcf42011-12-21 14:48:43 -080026 .dev_name = "node",
Linus Torvalds1da177e2005-04-16 15:20:36 -070027};
28
29
Sudeep Holla5aaba362014-09-30 14:48:22 +010030static ssize_t node_read_cpumap(struct device *dev, bool list, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070031{
Zhen Lei064f0e92017-10-13 15:57:50 -070032 ssize_t n;
33 cpumask_var_t mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 struct node *node_dev = to_node(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Mike Travis39106dc2008-04-08 11:43:03 -070036 /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */
37 BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1));
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Zhen Lei064f0e92017-10-13 15:57:50 -070039 if (!alloc_cpumask_var(&mask, GFP_KERNEL))
40 return 0;
41
42 cpumask_and(mask, cpumask_of_node(node_dev->dev.id), cpu_online_mask);
43 n = cpumap_print_to_pagebuf(list, buf, mask);
44 free_cpumask_var(mask);
45
46 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047}
48
Kay Sievers10fbcf42011-12-21 14:48:43 -080049static inline ssize_t node_read_cpumask(struct device *dev,
50 struct device_attribute *attr, char *buf)
Mike Travis39106dc2008-04-08 11:43:03 -070051{
Sudeep Holla5aaba362014-09-30 14:48:22 +010052 return node_read_cpumap(dev, false, buf);
Mike Travis39106dc2008-04-08 11:43:03 -070053}
Kay Sievers10fbcf42011-12-21 14:48:43 -080054static inline ssize_t node_read_cpulist(struct device *dev,
55 struct device_attribute *attr, char *buf)
Mike Travis39106dc2008-04-08 11:43:03 -070056{
Sudeep Holla5aaba362014-09-30 14:48:22 +010057 return node_read_cpumap(dev, true, buf);
Mike Travis39106dc2008-04-08 11:43:03 -070058}
59
Kay Sievers10fbcf42011-12-21 14:48:43 -080060static DEVICE_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL);
61static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Keith Busch08d9dbe2019-03-11 14:56:00 -060063/**
64 * struct node_access_nodes - Access class device to hold user visible
65 * relationships to other nodes.
66 * @dev: Device for this memory access class
67 * @list_node: List element in the node's access list
68 * @access: The access class rank
69 */
70struct node_access_nodes {
71 struct device dev;
72 struct list_head list_node;
73 unsigned access;
Keith Busche1cf33a2019-03-11 14:56:01 -060074#ifdef CONFIG_HMEM_REPORTING
75 struct node_hmem_attrs hmem_attrs;
76#endif
Keith Busch08d9dbe2019-03-11 14:56:00 -060077};
78#define to_access_nodes(dev) container_of(dev, struct node_access_nodes, dev)
79
80static struct attribute *node_init_access_node_attrs[] = {
81 NULL,
82};
83
84static struct attribute *node_targ_access_node_attrs[] = {
85 NULL,
86};
87
88static const struct attribute_group initiators = {
89 .name = "initiators",
90 .attrs = node_init_access_node_attrs,
91};
92
93static const struct attribute_group targets = {
94 .name = "targets",
95 .attrs = node_targ_access_node_attrs,
96};
97
98static const struct attribute_group *node_access_node_groups[] = {
99 &initiators,
100 &targets,
101 NULL,
102};
103
104static void node_remove_accesses(struct node *node)
105{
106 struct node_access_nodes *c, *cnext;
107
108 list_for_each_entry_safe(c, cnext, &node->access_list, list_node) {
109 list_del(&c->list_node);
110 device_unregister(&c->dev);
111 }
112}
113
114static void node_access_release(struct device *dev)
115{
116 kfree(to_access_nodes(dev));
117}
118
119static struct node_access_nodes *node_init_node_access(struct node *node,
120 unsigned access)
121{
122 struct node_access_nodes *access_node;
123 struct device *dev;
124
125 list_for_each_entry(access_node, &node->access_list, list_node)
126 if (access_node->access == access)
127 return access_node;
128
129 access_node = kzalloc(sizeof(*access_node), GFP_KERNEL);
130 if (!access_node)
131 return NULL;
132
133 access_node->access = access;
134 dev = &access_node->dev;
135 dev->parent = &node->dev;
136 dev->release = node_access_release;
137 dev->groups = node_access_node_groups;
138 if (dev_set_name(dev, "access%u", access))
139 goto free;
140
141 if (device_register(dev))
142 goto free_name;
143
144 pm_runtime_no_callbacks(dev);
145 list_add_tail(&access_node->list_node, &node->access_list);
146 return access_node;
147free_name:
148 kfree_const(dev->kobj.name);
149free:
150 kfree(access_node);
151 return NULL;
152}
153
Keith Busche1cf33a2019-03-11 14:56:01 -0600154#ifdef CONFIG_HMEM_REPORTING
155#define ACCESS_ATTR(name) \
156static ssize_t name##_show(struct device *dev, \
157 struct device_attribute *attr, \
158 char *buf) \
159{ \
160 return sprintf(buf, "%u\n", to_access_nodes(dev)->hmem_attrs.name); \
161} \
162static DEVICE_ATTR_RO(name);
163
164ACCESS_ATTR(read_bandwidth)
165ACCESS_ATTR(read_latency)
166ACCESS_ATTR(write_bandwidth)
167ACCESS_ATTR(write_latency)
168
169static struct attribute *access_attrs[] = {
170 &dev_attr_read_bandwidth.attr,
171 &dev_attr_read_latency.attr,
172 &dev_attr_write_bandwidth.attr,
173 &dev_attr_write_latency.attr,
174 NULL,
175};
176
177/**
178 * node_set_perf_attrs - Set the performance values for given access class
179 * @nid: Node identifier to be set
180 * @hmem_attrs: Heterogeneous memory performance attributes
181 * @access: The access class the for the given attributes
182 */
183void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs,
184 unsigned access)
185{
186 struct node_access_nodes *c;
187 struct node *node;
188 int i;
189
190 if (WARN_ON_ONCE(!node_online(nid)))
191 return;
192
193 node = node_devices[nid];
194 c = node_init_node_access(node, access);
195 if (!c)
196 return;
197
198 c->hmem_attrs = *hmem_attrs;
199 for (i = 0; access_attrs[i] != NULL; i++) {
200 if (sysfs_add_file_to_group(&c->dev.kobj, access_attrs[i],
201 "initiators")) {
202 pr_info("failed to add performance attribute to node %d\n",
203 nid);
204 break;
205 }
206 }
207}
208#endif
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210#define K(x) ((x) << (PAGE_SHIFT - 10))
Kay Sievers10fbcf42011-12-21 14:48:43 -0800211static ssize_t node_read_meminfo(struct device *dev,
212 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
214 int n;
215 int nid = dev->id;
Mel Gorman599d0c92016-07-28 15:45:31 -0700216 struct pglist_data *pgdat = NODE_DATA(nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 struct sysinfo i;
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700218 unsigned long sreclaimable, sunreclaimable;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220 si_meminfo_node(&i, nid);
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700221 sreclaimable = node_page_state(pgdat, NR_SLAB_RECLAIMABLE);
222 sunreclaimable = node_page_state(pgdat, NR_SLAB_UNRECLAIMABLE);
KOSAKI Motohiro7ee92252010-08-09 17:19:50 -0700223 n = sprintf(buf,
Rik van Riel4f98a2f2008-10-18 20:26:32 -0700224 "Node %d MemTotal: %8lu kB\n"
225 "Node %d MemFree: %8lu kB\n"
226 "Node %d MemUsed: %8lu kB\n"
227 "Node %d Active: %8lu kB\n"
228 "Node %d Inactive: %8lu kB\n"
229 "Node %d Active(anon): %8lu kB\n"
230 "Node %d Inactive(anon): %8lu kB\n"
231 "Node %d Active(file): %8lu kB\n"
232 "Node %d Inactive(file): %8lu kB\n"
Nick Piggin5344b7e2008-10-18 20:26:51 -0700233 "Node %d Unevictable: %8lu kB\n"
KOSAKI Motohiro7ee92252010-08-09 17:19:50 -0700234 "Node %d Mlocked: %8lu kB\n",
235 nid, K(i.totalram),
236 nid, K(i.freeram),
237 nid, K(i.totalram - i.freeram),
Mel Gorman599d0c92016-07-28 15:45:31 -0700238 nid, K(node_page_state(pgdat, NR_ACTIVE_ANON) +
239 node_page_state(pgdat, NR_ACTIVE_FILE)),
240 nid, K(node_page_state(pgdat, NR_INACTIVE_ANON) +
241 node_page_state(pgdat, NR_INACTIVE_FILE)),
242 nid, K(node_page_state(pgdat, NR_ACTIVE_ANON)),
243 nid, K(node_page_state(pgdat, NR_INACTIVE_ANON)),
244 nid, K(node_page_state(pgdat, NR_ACTIVE_FILE)),
245 nid, K(node_page_state(pgdat, NR_INACTIVE_FILE)),
246 nid, K(node_page_state(pgdat, NR_UNEVICTABLE)),
Mel Gorman75ef7182016-07-28 15:45:24 -0700247 nid, K(sum_zone_node_page_state(nid, NR_MLOCK)));
KOSAKI Motohiro7ee92252010-08-09 17:19:50 -0700248
Christoph Lameter182e8e22006-09-25 23:31:10 -0700249#ifdef CONFIG_HIGHMEM
KOSAKI Motohiro7ee92252010-08-09 17:19:50 -0700250 n += sprintf(buf + n,
Rik van Riel4f98a2f2008-10-18 20:26:32 -0700251 "Node %d HighTotal: %8lu kB\n"
252 "Node %d HighFree: %8lu kB\n"
253 "Node %d LowTotal: %8lu kB\n"
KOSAKI Motohiro7ee92252010-08-09 17:19:50 -0700254 "Node %d LowFree: %8lu kB\n",
255 nid, K(i.totalhigh),
256 nid, K(i.freehigh),
257 nid, K(i.totalram - i.totalhigh),
258 nid, K(i.freeram - i.freehigh));
Christoph Lameter182e8e22006-09-25 23:31:10 -0700259#endif
KOSAKI Motohiro7ee92252010-08-09 17:19:50 -0700260 n += sprintf(buf + n,
Rik van Riel4f98a2f2008-10-18 20:26:32 -0700261 "Node %d Dirty: %8lu kB\n"
262 "Node %d Writeback: %8lu kB\n"
263 "Node %d FilePages: %8lu kB\n"
264 "Node %d Mapped: %8lu kB\n"
265 "Node %d AnonPages: %8lu kB\n"
KOSAKI Motohiro4b021082009-09-21 17:01:33 -0700266 "Node %d Shmem: %8lu kB\n"
KOSAKI Motohiroc6a7f572009-09-21 17:01:32 -0700267 "Node %d KernelStack: %8lu kB\n"
Rik van Riel4f98a2f2008-10-18 20:26:32 -0700268 "Node %d PageTables: %8lu kB\n"
269 "Node %d NFS_Unstable: %8lu kB\n"
270 "Node %d Bounce: %8lu kB\n"
271 "Node %d WritebackTmp: %8lu kB\n"
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700272 "Node %d KReclaimable: %8lu kB\n"
Rik van Riel4f98a2f2008-10-18 20:26:32 -0700273 "Node %d Slab: %8lu kB\n"
274 "Node %d SReclaimable: %8lu kB\n"
David Rientjes05b258e2011-01-13 15:47:14 -0800275 "Node %d SUnreclaim: %8lu kB\n"
276#ifdef CONFIG_TRANSPARENT_HUGEPAGE
277 "Node %d AnonHugePages: %8lu kB\n"
Kirill A. Shutemov65c45372016-07-26 15:26:10 -0700278 "Node %d ShmemHugePages: %8lu kB\n"
279 "Node %d ShmemPmdMapped: %8lu kB\n"
David Rientjes05b258e2011-01-13 15:47:14 -0800280#endif
281 ,
Mel Gorman11fb9982016-07-28 15:46:20 -0700282 nid, K(node_page_state(pgdat, NR_FILE_DIRTY)),
283 nid, K(node_page_state(pgdat, NR_WRITEBACK)),
284 nid, K(node_page_state(pgdat, NR_FILE_PAGES)),
Mel Gorman50658e22016-07-28 15:46:14 -0700285 nid, K(node_page_state(pgdat, NR_FILE_MAPPED)),
Mel Gorman4b9d0fa2016-07-28 15:46:17 -0700286 nid, K(node_page_state(pgdat, NR_ANON_MAPPED)),
Rafael Aquinicc7452b2014-08-06 16:06:38 -0700287 nid, K(i.sharedram),
Andy Lutomirskid30dd8b2016-07-28 15:48:14 -0700288 nid, sum_zone_node_page_state(nid, NR_KERNEL_STACK_KB),
Mel Gorman75ef7182016-07-28 15:45:24 -0700289 nid, K(sum_zone_node_page_state(nid, NR_PAGETABLE)),
Mel Gorman11fb9982016-07-28 15:46:20 -0700290 nid, K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
Mel Gorman75ef7182016-07-28 15:45:24 -0700291 nid, K(sum_zone_node_page_state(nid, NR_BOUNCE)),
Mel Gorman11fb9982016-07-28 15:46:20 -0700292 nid, K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700293 nid, K(sreclaimable +
294 node_page_state(pgdat, NR_KERNEL_MISC_RECLAIMABLE)),
295 nid, K(sreclaimable + sunreclaimable),
296 nid, K(sreclaimable),
297 nid, K(sunreclaimable)
David Rientjes05b258e2011-01-13 15:47:14 -0800298#ifdef CONFIG_TRANSPARENT_HUGEPAGE
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700299 ,
Mel Gorman11fb9982016-07-28 15:46:20 -0700300 nid, K(node_page_state(pgdat, NR_ANON_THPS) *
Kirill A. Shutemov65c45372016-07-26 15:26:10 -0700301 HPAGE_PMD_NR),
Mel Gorman11fb9982016-07-28 15:46:20 -0700302 nid, K(node_page_state(pgdat, NR_SHMEM_THPS) *
Kirill A. Shutemov65c45372016-07-26 15:26:10 -0700303 HPAGE_PMD_NR),
Mel Gorman11fb9982016-07-28 15:46:20 -0700304 nid, K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) *
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700305 HPAGE_PMD_NR)
David Rientjes05b258e2011-01-13 15:47:14 -0800306#endif
Vlastimil Babka61f94e12018-10-26 15:05:50 -0700307 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 n += hugetlb_report_node_meminfo(nid, buf + n);
309 return n;
310}
311
312#undef K
Kay Sievers10fbcf42011-12-21 14:48:43 -0800313static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Kay Sievers10fbcf42011-12-21 14:48:43 -0800315static ssize_t node_read_numastat(struct device *dev,
316 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 return sprintf(buf,
319 "numa_hit %lu\n"
320 "numa_miss %lu\n"
321 "numa_foreign %lu\n"
322 "interleave_hit %lu\n"
323 "local_node %lu\n"
324 "other_node %lu\n",
Kemi Wang3a321d22017-09-08 16:12:48 -0700325 sum_zone_numa_state(dev->id, NUMA_HIT),
326 sum_zone_numa_state(dev->id, NUMA_MISS),
327 sum_zone_numa_state(dev->id, NUMA_FOREIGN),
328 sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT),
329 sum_zone_numa_state(dev->id, NUMA_LOCAL),
330 sum_zone_numa_state(dev->id, NUMA_OTHER));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
Kay Sievers10fbcf42011-12-21 14:48:43 -0800332static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Kay Sievers10fbcf42011-12-21 14:48:43 -0800334static ssize_t node_read_vmstat(struct device *dev,
335 struct device_attribute *attr, char *buf)
Michael Rubin2ac39032010-10-26 14:21:35 -0700336{
337 int nid = dev->id;
Mel Gorman75ef7182016-07-28 15:45:24 -0700338 struct pglist_data *pgdat = NODE_DATA(nid);
KOSAKI Motohirofa25c502011-05-24 17:11:28 -0700339 int i;
340 int n = 0;
341
342 for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
343 n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
Mel Gorman75ef7182016-07-28 15:45:24 -0700344 sum_zone_node_page_state(nid, i));
345
Kemi Wang3a321d22017-09-08 16:12:48 -0700346#ifdef CONFIG_NUMA
347 for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
Mel Gorman75ef7182016-07-28 15:45:24 -0700348 n += sprintf(buf+n, "%s %lu\n",
349 vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
Kemi Wang3a321d22017-09-08 16:12:48 -0700350 sum_zone_numa_state(nid, i));
351#endif
352
353 for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
354 n += sprintf(buf+n, "%s %lu\n",
355 vmstat_text[i + NR_VM_ZONE_STAT_ITEMS +
356 NR_VM_NUMA_STAT_ITEMS],
Mel Gorman75ef7182016-07-28 15:45:24 -0700357 node_page_state(pgdat, i));
KOSAKI Motohirofa25c502011-05-24 17:11:28 -0700358
359 return n;
Michael Rubin2ac39032010-10-26 14:21:35 -0700360}
Kay Sievers10fbcf42011-12-21 14:48:43 -0800361static DEVICE_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
Michael Rubin2ac39032010-10-26 14:21:35 -0700362
Kay Sievers10fbcf42011-12-21 14:48:43 -0800363static ssize_t node_read_distance(struct device *dev,
Ana Nedelcu518d3f32015-03-08 12:48:48 +0200364 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
366 int nid = dev->id;
367 int len = 0;
368 int i;
369
David Rientjes12ee3c02010-03-10 14:50:21 -0800370 /*
371 * buf is currently PAGE_SIZE in length and each node needs 4 chars
372 * at the most (distance + space or newline).
373 */
374 BUILD_BUG_ON(MAX_NUMNODES * 4 > PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 for_each_online_node(i)
377 len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
378
379 len += sprintf(buf + len, "\n");
380 return len;
381}
Kay Sievers10fbcf42011-12-21 14:48:43 -0800382static DEVICE_ATTR(distance, S_IRUGO, node_read_distance, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Takashi Iwai3c9b8aa2015-01-29 12:29:22 +0100384static struct attribute *node_dev_attrs[] = {
385 &dev_attr_cpumap.attr,
386 &dev_attr_cpulist.attr,
387 &dev_attr_meminfo.attr,
388 &dev_attr_numastat.attr,
389 &dev_attr_distance.attr,
390 &dev_attr_vmstat.attr,
391 NULL
392};
Greg Kroah-Hartman7ca7ec42015-03-25 13:47:17 +0100393ATTRIBUTE_GROUPS(node_dev);
Takashi Iwai3c9b8aa2015-01-29 12:29:22 +0100394
Lee Schermerhorn9a3052302009-12-14 17:58:25 -0800395#ifdef CONFIG_HUGETLBFS
396/*
397 * hugetlbfs per node attributes registration interface:
398 * When/if hugetlb[fs] subsystem initializes [sometime after this module],
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800399 * it will register its per node attributes for all online nodes with
400 * memory. It will also call register_hugetlbfs_with_node(), below, to
Lee Schermerhorn9a3052302009-12-14 17:58:25 -0800401 * register its attribute registration functions with this node driver.
402 * Once these hooks have been initialized, the node driver will call into
403 * the hugetlb module to [un]register attributes for hot-plugged nodes.
404 */
405static node_registration_func_t __hugetlb_register_node;
406static node_registration_func_t __hugetlb_unregister_node;
407
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800408static inline bool hugetlb_register_node(struct node *node)
Lee Schermerhorn9a3052302009-12-14 17:58:25 -0800409{
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800410 if (__hugetlb_register_node &&
Lai Jiangshan8cebfcd2012-12-12 13:51:36 -0800411 node_state(node->dev.id, N_MEMORY)) {
Lee Schermerhorn9a3052302009-12-14 17:58:25 -0800412 __hugetlb_register_node(node);
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800413 return true;
414 }
415 return false;
Lee Schermerhorn9a3052302009-12-14 17:58:25 -0800416}
417
418static inline void hugetlb_unregister_node(struct node *node)
419{
420 if (__hugetlb_unregister_node)
421 __hugetlb_unregister_node(node);
422}
423
424void register_hugetlbfs_with_node(node_registration_func_t doregister,
425 node_registration_func_t unregister)
426{
427 __hugetlb_register_node = doregister;
428 __hugetlb_unregister_node = unregister;
429}
430#else
431static inline void hugetlb_register_node(struct node *node) {}
432
433static inline void hugetlb_unregister_node(struct node *node) {}
434#endif
435
Yasuaki Ishimatsu8c7b5b42012-12-11 16:00:57 -0800436static void node_device_release(struct device *dev)
437{
438 struct node *node = to_node(dev);
439
440#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS)
441 /*
442 * We schedule the work only when a memory section is
443 * onlined/offlined on this node. When we come here,
444 * all the memory on this node has been offlined,
445 * so we won't enqueue new work to this work.
446 *
447 * The work is using node->node_work, so we should
448 * flush work before freeing the memory.
449 */
450 flush_work(&node->node_work);
451#endif
452 kfree(node);
453}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455/*
Robert P. J. Day405ae7d2007-02-17 19:13:42 +0100456 * register_node - Setup a sysfs device for a node.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 * @num - Node number to use when creating the device.
458 *
459 * Initialize and register the node device.
460 */
Dou Liyanga7be6e52017-07-10 15:49:20 -0700461static int register_node(struct node *node, int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
463 int error;
464
Kay Sievers10fbcf42011-12-21 14:48:43 -0800465 node->dev.id = num;
466 node->dev.bus = &node_subsys;
Yasuaki Ishimatsu8c7b5b42012-12-11 16:00:57 -0800467 node->dev.release = node_device_release;
Greg Kroah-Hartman7ca7ec42015-03-25 13:47:17 +0100468 node->dev.groups = node_dev_groups;
Kay Sievers10fbcf42011-12-21 14:48:43 -0800469 error = device_register(&node->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Arvind Yadavc1cc0d52018-03-11 11:25:50 +0530471 if (error)
472 put_device(&node->dev);
473 else {
Lee Schermerhorn9a3052302009-12-14 17:58:25 -0800474 hugetlb_register_node(node);
Mel Gormaned4a6d72010-05-24 14:32:29 -0700475
476 compaction_register_node(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 }
478 return error;
479}
480
Keiichiro Tokunaga4b450992005-05-08 21:28:53 +0900481/**
482 * unregister_node - unregister a node device
483 * @node: node going away
484 *
485 * Unregisters a node device @node. All the devices on the node must be
486 * unregistered before calling this function.
487 */
488void unregister_node(struct node *node)
489{
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800490 hugetlb_unregister_node(node); /* no-op, if memoryless node */
Keith Busch08d9dbe2019-03-11 14:56:00 -0600491 node_remove_accesses(node);
Kay Sievers10fbcf42011-12-21 14:48:43 -0800492 device_unregister(&node->dev);
Keiichiro Tokunaga4b450992005-05-08 21:28:53 +0900493}
494
Wen Congyang87327942012-12-11 16:00:56 -0800495struct node *node_devices[MAX_NUMNODES];
Yasunori Goto0fc44152006-06-27 02:53:38 -0700496
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -0700497/*
498 * register cpu under node
499 */
500int register_cpu_under_node(unsigned int cpu, unsigned int nid)
501{
Alex Chiang18307942009-12-14 17:59:08 -0800502 int ret;
Kay Sievers8a25a2f2011-12-21 14:29:42 -0800503 struct device *obj;
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -0700504
Alex Chiangf8246f32009-12-14 17:59:06 -0800505 if (!node_online(nid))
506 return 0;
507
Kay Sievers8a25a2f2011-12-21 14:29:42 -0800508 obj = get_cpu_device(cpu);
Alex Chiangf8246f32009-12-14 17:59:06 -0800509 if (!obj)
510 return 0;
511
Wen Congyang87327942012-12-11 16:00:56 -0800512 ret = sysfs_create_link(&node_devices[nid]->dev.kobj,
Alex Chiangf8246f32009-12-14 17:59:06 -0800513 &obj->kobj,
514 kobject_name(&obj->kobj));
Alex Chiang18307942009-12-14 17:59:08 -0800515 if (ret)
516 return ret;
517
518 return sysfs_create_link(&obj->kobj,
Wen Congyang87327942012-12-11 16:00:56 -0800519 &node_devices[nid]->dev.kobj,
520 kobject_name(&node_devices[nid]->dev.kobj));
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -0700521}
522
Keith Busch08d9dbe2019-03-11 14:56:00 -0600523/**
524 * register_memory_node_under_compute_node - link memory node to its compute
525 * node for a given access class.
526 * @mem_node: Memory node number
527 * @cpu_node: Cpu node number
528 * @access: Access class to register
529 *
530 * Description:
531 * For use with platforms that may have separate memory and compute nodes.
532 * This function will export node relationships linking which memory
533 * initiator nodes can access memory targets at a given ranked access
534 * class.
535 */
536int register_memory_node_under_compute_node(unsigned int mem_nid,
537 unsigned int cpu_nid,
538 unsigned access)
539{
540 struct node *init_node, *targ_node;
541 struct node_access_nodes *initiator, *target;
542 int ret;
543
544 if (!node_online(cpu_nid) || !node_online(mem_nid))
545 return -ENODEV;
546
547 init_node = node_devices[cpu_nid];
548 targ_node = node_devices[mem_nid];
549 initiator = node_init_node_access(init_node, access);
550 target = node_init_node_access(targ_node, access);
551 if (!initiator || !target)
552 return -ENOMEM;
553
554 ret = sysfs_add_link_to_group(&initiator->dev.kobj, "targets",
555 &targ_node->dev.kobj,
556 dev_name(&targ_node->dev));
557 if (ret)
558 return ret;
559
560 ret = sysfs_add_link_to_group(&target->dev.kobj, "initiators",
561 &init_node->dev.kobj,
562 dev_name(&init_node->dev));
563 if (ret)
564 goto err;
565
566 return 0;
567 err:
568 sysfs_remove_link_from_group(&initiator->dev.kobj, "targets",
569 dev_name(&targ_node->dev));
570 return ret;
571}
572
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -0700573int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
574{
Kay Sievers8a25a2f2011-12-21 14:29:42 -0800575 struct device *obj;
Alex Chiangb9d52da2009-12-14 17:59:07 -0800576
577 if (!node_online(nid))
578 return 0;
579
Kay Sievers8a25a2f2011-12-21 14:29:42 -0800580 obj = get_cpu_device(cpu);
Alex Chiangb9d52da2009-12-14 17:59:07 -0800581 if (!obj)
582 return 0;
583
Wen Congyang87327942012-12-11 16:00:56 -0800584 sysfs_remove_link(&node_devices[nid]->dev.kobj,
Alex Chiangb9d52da2009-12-14 17:59:07 -0800585 kobject_name(&obj->kobj));
Alex Chiang18307942009-12-14 17:59:08 -0800586 sysfs_remove_link(&obj->kobj,
Wen Congyang87327942012-12-11 16:00:56 -0800587 kobject_name(&node_devices[nid]->dev.kobj));
Alex Chiangb9d52da2009-12-14 17:59:07 -0800588
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -0700589 return 0;
590}
591
Gary Hadec04fc582009-01-06 14:39:14 -0800592#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
Fabian Frederickbd721ea2016-08-02 14:03:33 -0700593static int __ref get_nid_for_pfn(unsigned long pfn)
Gary Hadec04fc582009-01-06 14:39:14 -0800594{
Gary Hadec04fc582009-01-06 14:39:14 -0800595 if (!pfn_valid_within(pfn))
596 return -1;
Mel Gorman3a80a7f2015-06-30 14:57:02 -0700597#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
Thomas Gleixner8cdde382017-05-16 20:42:39 +0200598 if (system_state < SYSTEM_RUNNING)
Mel Gorman3a80a7f2015-06-30 14:57:02 -0700599 return early_pfn_to_nid(pfn);
600#endif
Gary Hadec04fc582009-01-06 14:39:14 -0800601 return pfn_to_nid(pfn);
602}
603
604/* register memory section under specified node if it spans that node */
Oscar Salvador4fbce632018-08-17 15:46:22 -0700605int register_mem_sect_under_node(struct memory_block *mem_blk, void *arg)
Gary Hadec04fc582009-01-06 14:39:14 -0800606{
Oscar Salvador4fbce632018-08-17 15:46:22 -0700607 int ret, nid = *(int *)arg;
Gary Hadec04fc582009-01-06 14:39:14 -0800608 unsigned long pfn, sect_start_pfn, sect_end_pfn;
609
Pavel Tatashind0dc12e2018-04-05 16:23:00 -0700610 mem_blk->nid = nid;
Nathan Fontenotd3360162011-01-20 10:44:29 -0600611
612 sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
613 sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr);
614 sect_end_pfn += PAGES_PER_SECTION - 1;
Gary Hadec04fc582009-01-06 14:39:14 -0800615 for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
616 int page_nid;
617
Yinghai Lu04697852015-09-04 15:42:39 -0700618 /*
619 * memory block could have several absent sections from start.
620 * skip pfn range from absent section
621 */
622 if (!pfn_present(pfn)) {
623 pfn = round_down(pfn + PAGES_PER_SECTION,
624 PAGES_PER_SECTION) - 1;
625 continue;
626 }
627
Pavel Tatashinfc44f7f2018-04-05 16:22:56 -0700628 /*
629 * We need to check if page belongs to nid only for the boot
630 * case, during hotplug we know that all pages in the memory
631 * block belong to the same node.
632 */
Oscar Salvador4fbce632018-08-17 15:46:22 -0700633 if (system_state == SYSTEM_BOOTING) {
Pavel Tatashinfc44f7f2018-04-05 16:22:56 -0700634 page_nid = get_nid_for_pfn(pfn);
635 if (page_nid < 0)
636 continue;
637 if (page_nid != nid)
638 continue;
639 }
Wen Congyang87327942012-12-11 16:00:56 -0800640 ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj,
Kay Sievers10fbcf42011-12-21 14:48:43 -0800641 &mem_blk->dev.kobj,
642 kobject_name(&mem_blk->dev.kobj));
Alex Chiangdee5d0d2009-12-14 17:59:05 -0800643 if (ret)
644 return ret;
645
Kay Sievers10fbcf42011-12-21 14:48:43 -0800646 return sysfs_create_link_nowarn(&mem_blk->dev.kobj,
Wen Congyang87327942012-12-11 16:00:56 -0800647 &node_devices[nid]->dev.kobj,
648 kobject_name(&node_devices[nid]->dev.kobj));
Gary Hadec04fc582009-01-06 14:39:14 -0800649 }
650 /* mem section does not span the specified node */
651 return 0;
652}
653
654/* unregister memory section under all nodes that it spans */
Nathan Fontenotd3360162011-01-20 10:44:29 -0600655int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
656 unsigned long phys_index)
Gary Hadec04fc582009-01-06 14:39:14 -0800657{
David Rientjes9ae49fa2009-12-14 17:59:46 -0800658 NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
Gary Hadec04fc582009-01-06 14:39:14 -0800659 unsigned long pfn, sect_start_pfn, sect_end_pfn;
660
David Rientjes9ae49fa2009-12-14 17:59:46 -0800661 if (!mem_blk) {
662 NODEMASK_FREE(unlinked_nodes);
Gary Hadec04fc582009-01-06 14:39:14 -0800663 return -EFAULT;
David Rientjes9ae49fa2009-12-14 17:59:46 -0800664 }
665 if (!unlinked_nodes)
666 return -ENOMEM;
667 nodes_clear(*unlinked_nodes);
Nathan Fontenotd3360162011-01-20 10:44:29 -0600668
669 sect_start_pfn = section_nr_to_pfn(phys_index);
Gary Hadec04fc582009-01-06 14:39:14 -0800670 sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
671 for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
Roel Kluin47504982009-03-10 12:55:45 -0700672 int nid;
Gary Hadec04fc582009-01-06 14:39:14 -0800673
674 nid = get_nid_for_pfn(pfn);
675 if (nid < 0)
676 continue;
677 if (!node_online(nid))
678 continue;
David Rientjes9ae49fa2009-12-14 17:59:46 -0800679 if (node_test_and_set(nid, *unlinked_nodes))
Gary Hadec04fc582009-01-06 14:39:14 -0800680 continue;
Wen Congyang87327942012-12-11 16:00:56 -0800681 sysfs_remove_link(&node_devices[nid]->dev.kobj,
Kay Sievers10fbcf42011-12-21 14:48:43 -0800682 kobject_name(&mem_blk->dev.kobj));
683 sysfs_remove_link(&mem_blk->dev.kobj,
Wen Congyang87327942012-12-11 16:00:56 -0800684 kobject_name(&node_devices[nid]->dev.kobj));
Gary Hadec04fc582009-01-06 14:39:14 -0800685 }
David Rientjes9ae49fa2009-12-14 17:59:46 -0800686 NODEMASK_FREE(unlinked_nodes);
Gary Hadec04fc582009-01-06 14:39:14 -0800687 return 0;
688}
689
Oscar Salvador4fbce632018-08-17 15:46:22 -0700690int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn)
Gary Hadec04fc582009-01-06 14:39:14 -0800691{
Oscar Salvador4fbce632018-08-17 15:46:22 -0700692 return walk_memory_range(start_pfn, end_pfn, (void *)&nid,
693 register_mem_sect_under_node);
Gary Hadec04fc582009-01-06 14:39:14 -0800694}
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800695
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800696#ifdef CONFIG_HUGETLBFS
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800697/*
698 * Handle per node hstate attribute [un]registration on transistions
699 * to/from memoryless state.
700 */
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800701static void node_hugetlb_work(struct work_struct *work)
702{
703 struct node *node = container_of(work, struct node, node_work);
704
705 /*
706 * We only get here when a node transitions to/from memoryless state.
707 * We can detect which transition occurred by examining whether the
708 * node has memory now. hugetlb_register_node() already check this
709 * so we try to register the attributes. If that fails, then the
710 * node has transitioned to memoryless, try to unregister the
711 * attributes.
712 */
713 if (!hugetlb_register_node(node))
714 hugetlb_unregister_node(node);
715}
716
717static void init_node_hugetlb_work(int nid)
718{
Wen Congyang87327942012-12-11 16:00:56 -0800719 INIT_WORK(&node_devices[nid]->node_work, node_hugetlb_work);
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800720}
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800721
722static int node_memory_callback(struct notifier_block *self,
723 unsigned long action, void *arg)
724{
725 struct memory_notify *mnb = arg;
726 int nid = mnb->status_change_nid;
727
728 switch (action) {
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800729 case MEM_ONLINE:
730 case MEM_OFFLINE:
731 /*
732 * offload per node hstate [un]registration to a work thread
733 * when transitioning to/from memoryless state.
734 */
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800735 if (nid != NUMA_NO_NODE)
Wen Congyang87327942012-12-11 16:00:56 -0800736 schedule_work(&node_devices[nid]->node_work);
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800737 break;
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800738
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800739 case MEM_GOING_ONLINE:
740 case MEM_GOING_OFFLINE:
741 case MEM_CANCEL_ONLINE:
742 case MEM_CANCEL_OFFLINE:
743 default:
744 break;
745 }
746
747 return NOTIFY_OK;
748}
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800749#endif /* CONFIG_HUGETLBFS */
Michal Hocko9037a992017-07-06 15:37:49 -0700750#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800751
752#if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \
753 !defined(CONFIG_HUGETLBFS)
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800754static inline int node_memory_callback(struct notifier_block *self,
755 unsigned long action, void *arg)
756{
757 return NOTIFY_OK;
758}
Lee Schermerhorn39da08c2009-12-14 17:58:36 -0800759
760static void init_node_hugetlb_work(int nid) { }
761
762#endif
Gary Hadec04fc582009-01-06 14:39:14 -0800763
Michal Hocko9037a992017-07-06 15:37:49 -0700764int __register_one_node(int nid)
Yasunori Goto0fc44152006-06-27 02:53:38 -0700765{
Michal Hocko9037a992017-07-06 15:37:49 -0700766 int error;
KAMEZAWA Hiroyuki76b67ed2006-06-27 02:53:41 -0700767 int cpu;
Yasunori Goto0fc44152006-06-27 02:53:38 -0700768
Michal Hocko9037a992017-07-06 15:37:49 -0700769 node_devices[nid] = kzalloc(sizeof(struct node), GFP_KERNEL);
770 if (!node_devices[nid])
771 return -ENOMEM;
Yasunori Goto0fc44152006-06-27 02:53:38 -0700772
Dou Liyanga7be6e52017-07-10 15:49:20 -0700773 error = register_node(node_devices[nid], nid);
Wen Congyang87327942012-12-11 16:00:56 -0800774
Michal Hocko9037a992017-07-06 15:37:49 -0700775 /* link cpu under this node */
776 for_each_present_cpu(cpu) {
777 if (cpu_to_node(cpu) == nid)
778 register_cpu_under_node(cpu, nid);
Yasunori Goto0fc44152006-06-27 02:53:38 -0700779 }
780
Keith Busch08d9dbe2019-03-11 14:56:00 -0600781 INIT_LIST_HEAD(&node_devices[nid]->access_list);
Michal Hocko9037a992017-07-06 15:37:49 -0700782 /* initialize work queue for memory hot plug */
783 init_node_hugetlb_work(nid);
Yasunori Goto0fc44152006-06-27 02:53:38 -0700784
Michal Hocko9037a992017-07-06 15:37:49 -0700785 return error;
Yasunori Goto0fc44152006-06-27 02:53:38 -0700786}
787
788void unregister_one_node(int nid)
789{
Xishi Qiu92d585e2014-03-06 17:18:21 +0800790 if (!node_devices[nid])
791 return;
792
Wen Congyang87327942012-12-11 16:00:56 -0800793 unregister_node(node_devices[nid]);
Wen Congyang87327942012-12-11 16:00:56 -0800794 node_devices[nid] = NULL;
Yasunori Goto0fc44152006-06-27 02:53:38 -0700795}
796
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700797/*
798 * node states attributes
799 */
800
801static ssize_t print_nodes_state(enum node_states state, char *buf)
802{
803 int n;
804
Tejun Heof799b1a2015-02-13 14:37:56 -0800805 n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
806 nodemask_pr_args(&node_states[state]));
Ryota Ozakif6238812012-05-29 15:06:20 -0700807 buf[n++] = '\n';
808 buf[n] = '\0';
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700809 return n;
810}
811
Andi Kleenb15f5622010-01-05 12:47:59 +0100812struct node_attr {
Kay Sievers10fbcf42011-12-21 14:48:43 -0800813 struct device_attribute attr;
Andi Kleenb15f5622010-01-05 12:47:59 +0100814 enum node_states state;
815};
816
Kay Sievers10fbcf42011-12-21 14:48:43 -0800817static ssize_t show_node_state(struct device *dev,
818 struct device_attribute *attr, char *buf)
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700819{
Andi Kleenb15f5622010-01-05 12:47:59 +0100820 struct node_attr *na = container_of(attr, struct node_attr, attr);
821 return print_nodes_state(na->state, buf);
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700822}
823
Andi Kleenb15f5622010-01-05 12:47:59 +0100824#define _NODE_ATTR(name, state) \
Kay Sievers10fbcf42011-12-21 14:48:43 -0800825 { __ATTR(name, 0444, show_node_state, NULL), state }
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700826
Andi Kleenb15f5622010-01-05 12:47:59 +0100827static struct node_attr node_state_attr[] = {
Lai Jiangshanfcf07d22012-12-11 16:03:13 -0800828 [N_POSSIBLE] = _NODE_ATTR(possible, N_POSSIBLE),
829 [N_ONLINE] = _NODE_ATTR(online, N_ONLINE),
830 [N_NORMAL_MEMORY] = _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY),
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700831#ifdef CONFIG_HIGHMEM
Lai Jiangshanfcf07d22012-12-11 16:03:13 -0800832 [N_HIGH_MEMORY] = _NODE_ATTR(has_high_memory, N_HIGH_MEMORY),
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700833#endif
Lai Jiangshan20b2f522012-12-12 13:52:00 -0800834 [N_MEMORY] = _NODE_ATTR(has_memory, N_MEMORY),
Lai Jiangshanfcf07d22012-12-11 16:03:13 -0800835 [N_CPU] = _NODE_ATTR(has_cpu, N_CPU),
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700836};
837
Kay Sievers10fbcf42011-12-21 14:48:43 -0800838static struct attribute *node_state_attrs[] = {
Lai Jiangshanfcf07d22012-12-11 16:03:13 -0800839 &node_state_attr[N_POSSIBLE].attr.attr,
840 &node_state_attr[N_ONLINE].attr.attr,
841 &node_state_attr[N_NORMAL_MEMORY].attr.attr,
Andi Kleen3701cde2010-01-05 12:48:04 +0100842#ifdef CONFIG_HIGHMEM
Lai Jiangshanfcf07d22012-12-11 16:03:13 -0800843 &node_state_attr[N_HIGH_MEMORY].attr.attr,
Andi Kleen3701cde2010-01-05 12:48:04 +0100844#endif
Lai Jiangshan20b2f522012-12-12 13:52:00 -0800845 &node_state_attr[N_MEMORY].attr.attr,
Lai Jiangshanfcf07d22012-12-11 16:03:13 -0800846 &node_state_attr[N_CPU].attr.attr,
Andi Kleen3701cde2010-01-05 12:48:04 +0100847 NULL
848};
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700849
Kay Sievers10fbcf42011-12-21 14:48:43 -0800850static struct attribute_group memory_root_attr_group = {
851 .attrs = node_state_attrs,
852};
853
854static const struct attribute_group *cpu_root_attr_groups[] = {
855 &memory_root_attr_group,
856 NULL,
857};
858
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800859#define NODE_CALLBACK_PRI 2 /* lower than SLAB */
Keiichiro Tokunaga4b450992005-05-08 21:28:53 +0900860static int __init register_node_type(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700862 int ret;
863
Andi Kleen3701cde2010-01-05 12:48:04 +0100864 BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES);
865 BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES);
866
Kay Sievers10fbcf42011-12-21 14:48:43 -0800867 ret = subsys_system_register(&node_subsys, cpu_root_attr_groups);
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800868 if (!ret) {
Andrew Morton6e259e72013-04-29 15:08:07 -0700869 static struct notifier_block node_memory_callback_nb = {
870 .notifier_call = node_memory_callback,
871 .priority = NODE_CALLBACK_PRI,
872 };
873 register_hotmemory_notifier(&node_memory_callback_nb);
Lee Schermerhorn4faf8d92009-12-14 17:58:35 -0800874 }
Lee Schermerhornbde631a2007-10-16 01:26:27 -0700875
876 /*
877 * Note: we're not going to unregister the node class if we fail
878 * to register the node state class attribute files.
879 */
880 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882postcore_initcall(register_node_type);