Blame view

drivers/base/node.c 17.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   * drivers/base/node.c - basic Node class support
   */
  
  #include <linux/sysdev.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/mm.h>
c04fc586c   Gary Hade   mm: show node to ...
9
  #include <linux/memory.h>
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
10
  #include <linux/vmstat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
  #include <linux/node.h>
  #include <linux/hugetlb.h>
ed4a6d7f0   Mel Gorman   mm: compaction: a...
13
  #include <linux/compaction.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
  #include <linux/cpumask.h>
  #include <linux/topology.h>
  #include <linux/nodemask.h>
76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
17
  #include <linux/cpu.h>
bde631a51   Lee Schermerhorn   mm: add node stat...
18
  #include <linux/device.h>
af936a160   Lee Schermerhorn   vmscan: unevictab...
19
  #include <linux/swap.h>
18e5b539b   Tejun Heo   nodemask: include...
20
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

3701cde6e   Andi Kleen   sysdev: Use sysde...
22
  static struct sysdev_class_attribute *node_state_attrs[];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  static struct sysdev_class node_class = {
af5ca3f4e   Kay Sievers   Driver core: chan...
24
  	.name = "node",
3701cde6e   Andi Kleen   sysdev: Use sysde...
25
  	.attrs = node_state_attrs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  };
39106dcf8   Mike Travis   cpumask: use new ...
27
  static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  {
  	struct node *node_dev = to_node(dev);
a70f73028   Rusty Russell   cpumask: replace ...
30
  	const struct cpumask *mask = cpumask_of_node(node_dev->sysdev.id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  	int len;
39106dcf8   Mike Travis   cpumask: use new ...
32
33
  	/* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */
  	BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

39106dcf8   Mike Travis   cpumask: use new ...
35
  	len = type?
29c0177e6   Rusty Russell   cpumask: change c...
36
37
  		cpulist_scnprintf(buf, PAGE_SIZE-2, mask) :
  		cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
c5f59f083   Mike Travis   nodemask: use new...
38
39
40
   	buf[len++] = '
  ';
   	buf[len] = '\0';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  	return len;
  }
4a0b2b4db   Andi Kleen   sysdev: Pass the ...
43
44
  static inline ssize_t node_read_cpumask(struct sys_device *dev,
  				struct sysdev_attribute *attr, char *buf)
39106dcf8   Mike Travis   cpumask: use new ...
45
46
47
  {
  	return node_read_cpumap(dev, 0, buf);
  }
4a0b2b4db   Andi Kleen   sysdev: Pass the ...
48
49
  static inline ssize_t node_read_cpulist(struct sys_device *dev,
  				struct sysdev_attribute *attr, char *buf)
39106dcf8   Mike Travis   cpumask: use new ...
50
51
52
53
54
55
  {
  	return node_read_cpumap(dev, 1, buf);
  }
  
  static SYSDEV_ATTR(cpumap,  S_IRUGO, node_read_cpumask, NULL);
  static SYSDEV_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  
  #define K(x) ((x) << (PAGE_SHIFT - 10))
4a0b2b4db   Andi Kleen   sysdev: Pass the ...
58
59
  static ssize_t node_read_meminfo(struct sys_device * dev,
  			struct sysdev_attribute *attr, char * buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
  {
  	int n;
  	int nid = dev->id;
  	struct sysinfo i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  
  	si_meminfo_node(&i, nid);
7ee922554   KOSAKI Motohiro   drivers/base/node...
66
  	n = sprintf(buf,
4f98a2fee   Rik van Riel   vmscan: split LRU...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  		       "Node %d MemTotal:       %8lu kB
  "
  		       "Node %d MemFree:        %8lu kB
  "
  		       "Node %d MemUsed:        %8lu kB
  "
  		       "Node %d Active:         %8lu kB
  "
  		       "Node %d Inactive:       %8lu kB
  "
  		       "Node %d Active(anon):   %8lu kB
  "
  		       "Node %d Inactive(anon): %8lu kB
  "
  		       "Node %d Active(file):   %8lu kB
  "
  		       "Node %d Inactive(file): %8lu kB
  "
5344b7e64   Nick Piggin   vmstat: mlocked p...
85
86
  		       "Node %d Unevictable:    %8lu kB
  "
7ee922554   KOSAKI Motohiro   drivers/base/node...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  		       "Node %d Mlocked:        %8lu kB
  ",
  		       nid, K(i.totalram),
  		       nid, K(i.freeram),
  		       nid, K(i.totalram - i.freeram),
  		       nid, K(node_page_state(nid, NR_ACTIVE_ANON) +
  				node_page_state(nid, NR_ACTIVE_FILE)),
  		       nid, K(node_page_state(nid, NR_INACTIVE_ANON) +
  				node_page_state(nid, NR_INACTIVE_FILE)),
  		       nid, K(node_page_state(nid, NR_ACTIVE_ANON)),
  		       nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
  		       nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
  		       nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
  		       nid, K(node_page_state(nid, NR_UNEVICTABLE)),
  		       nid, K(node_page_state(nid, NR_MLOCK)));
182e8e237   Christoph Lameter   [PATCH] reduce MA...
102
  #ifdef CONFIG_HIGHMEM
7ee922554   KOSAKI Motohiro   drivers/base/node...
103
  	n += sprintf(buf + n,
4f98a2fee   Rik van Riel   vmscan: split LRU...
104
105
106
107
108
109
  		       "Node %d HighTotal:      %8lu kB
  "
  		       "Node %d HighFree:       %8lu kB
  "
  		       "Node %d LowTotal:       %8lu kB
  "
7ee922554   KOSAKI Motohiro   drivers/base/node...
110
111
112
113
114
115
  		       "Node %d LowFree:        %8lu kB
  ",
  		       nid, K(i.totalhigh),
  		       nid, K(i.freehigh),
  		       nid, K(i.totalram - i.totalhigh),
  		       nid, K(i.freeram - i.freehigh));
182e8e237   Christoph Lameter   [PATCH] reduce MA...
116
  #endif
7ee922554   KOSAKI Motohiro   drivers/base/node...
117
  	n += sprintf(buf + n,
4f98a2fee   Rik van Riel   vmscan: split LRU...
118
119
120
121
122
123
124
125
126
127
  		       "Node %d Dirty:          %8lu kB
  "
  		       "Node %d Writeback:      %8lu kB
  "
  		       "Node %d FilePages:      %8lu kB
  "
  		       "Node %d Mapped:         %8lu kB
  "
  		       "Node %d AnonPages:      %8lu kB
  "
4b02108ac   KOSAKI Motohiro   mm: oom analysis:...
128
129
  		       "Node %d Shmem:          %8lu kB
  "
c6a7f5728   KOSAKI Motohiro   mm: oom analysis:...
130
131
  		       "Node %d KernelStack:    %8lu kB
  "
4f98a2fee   Rik van Riel   vmscan: split LRU...
132
133
134
135
136
137
138
139
140
141
142
143
  		       "Node %d PageTables:     %8lu kB
  "
  		       "Node %d NFS_Unstable:   %8lu kB
  "
  		       "Node %d Bounce:         %8lu kB
  "
  		       "Node %d WritebackTmp:   %8lu kB
  "
  		       "Node %d Slab:           %8lu kB
  "
  		       "Node %d SReclaimable:   %8lu kB
  "
05b258e99   David Rientjes   thp: transparent ...
144
145
146
147
148
149
150
  		       "Node %d SUnreclaim:     %8lu kB
  "
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  		       "Node %d AnonHugePages:  %8lu kB
  "
  #endif
  			,
b1e7a8fd8   Christoph Lameter   [PATCH] zoned vm ...
151
  		       nid, K(node_page_state(nid, NR_FILE_DIRTY)),
ce866b34a   Christoph Lameter   [PATCH] zoned vm ...
152
  		       nid, K(node_page_state(nid, NR_WRITEBACK)),
347ce434d   Christoph Lameter   [PATCH] zoned vm ...
153
  		       nid, K(node_page_state(nid, NR_FILE_PAGES)),
65ba55f50   Christoph Lameter   [PATCH] zoned vm ...
154
  		       nid, K(node_page_state(nid, NR_FILE_MAPPED)),
05b258e99   David Rientjes   thp: transparent ...
155
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
91a13c281   Claudio Scordino   drivers/base/node...
156
  		       nid, K(node_page_state(nid, NR_ANON_PAGES)
05b258e99   David Rientjes   thp: transparent ...
157
  			+ node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
91a13c281   Claudio Scordino   drivers/base/node...
158
159
160
  			HPAGE_PMD_NR),
  #else
  		       nid, K(node_page_state(nid, NR_ANON_PAGES)),
05b258e99   David Rientjes   thp: transparent ...
161
  #endif
4b02108ac   KOSAKI Motohiro   mm: oom analysis:...
162
  		       nid, K(node_page_state(nid, NR_SHMEM)),
c6a7f5728   KOSAKI Motohiro   mm: oom analysis:...
163
164
  		       nid, node_page_state(nid, NR_KERNEL_STACK) *
  				THREAD_SIZE / 1024,
df849a152   Christoph Lameter   [PATCH] zoned vm ...
165
  		       nid, K(node_page_state(nid, NR_PAGETABLE)),
fd39fc856   Christoph Lameter   [PATCH] zoned vm ...
166
  		       nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
d2c5e30c9   Christoph Lameter   [PATCH] zoned vm ...
167
  		       nid, K(node_page_state(nid, NR_BOUNCE)),
fc3ba692a   Miklos Szeredi   mm: Add NR_WRITEB...
168
  		       nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
972d1a7b1   Christoph Lameter   [PATCH] ZVC: Supp...
169
170
171
  		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
  				node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
  		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
05b258e99   David Rientjes   thp: transparent ...
172
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
91a13c281   Claudio Scordino   drivers/base/node...
173
  		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))
05b258e99   David Rientjes   thp: transparent ...
174
175
  			, nid,
  			K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
91a13c281   Claudio Scordino   drivers/base/node...
176
177
178
  			HPAGE_PMD_NR));
  #else
  		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
05b258e99   David Rientjes   thp: transparent ...
179
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
  	n += hugetlb_report_node_meminfo(nid, buf + n);
  	return n;
  }
  
  #undef K
  static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
4a0b2b4db   Andi Kleen   sysdev: Pass the ...
186
187
  static ssize_t node_read_numastat(struct sys_device * dev,
  				struct sysdev_attribute *attr, char * buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
198
199
200
201
  	return sprintf(buf,
  		       "numa_hit %lu
  "
  		       "numa_miss %lu
  "
  		       "numa_foreign %lu
  "
  		       "interleave_hit %lu
  "
  		       "local_node %lu
  "
  		       "other_node %lu
  ",
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
202
203
204
205
206
207
  		       node_page_state(dev->id, NUMA_HIT),
  		       node_page_state(dev->id, NUMA_MISS),
  		       node_page_state(dev->id, NUMA_FOREIGN),
  		       node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
  		       node_page_state(dev->id, NUMA_LOCAL),
  		       node_page_state(dev->id, NUMA_OTHER));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  }
  static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
2ac390370   Michael Rubin   writeback: add /s...
210
211
212
213
  static ssize_t node_read_vmstat(struct sys_device *dev,
  				struct sysdev_attribute *attr, char *buf)
  {
  	int nid = dev->id;
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
214
215
216
217
218
219
220
221
222
  	int i;
  	int n = 0;
  
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
  		n += sprintf(buf+n, "%s %lu
  ", vmstat_text[i],
  			     node_page_state(nid, i));
  
  	return n;
2ac390370   Michael Rubin   writeback: add /s...
223
224
  }
  static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
4a0b2b4db   Andi Kleen   sysdev: Pass the ...
225
226
  static ssize_t node_read_distance(struct sys_device * dev,
  			struct sysdev_attribute *attr, char * buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  {
  	int nid = dev->id;
  	int len = 0;
  	int i;
12ee3c0a0   David Rientjes   driver core: numa...
231
232
233
234
235
  	/*
  	 * buf is currently PAGE_SIZE in length and each node needs 4 chars
  	 * at the most (distance + space or newline).
  	 */
  	BUILD_BUG_ON(MAX_NUMNODES * 4 > PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
240
241
242
243
244
  
  	for_each_online_node(i)
  		len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
  
  	len += sprintf(buf + len, "
  ");
  	return len;
  }
  static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
9a3052306   Lee Schermerhorn   hugetlb: add per ...
245
246
247
248
  #ifdef CONFIG_HUGETLBFS
  /*
   * hugetlbfs per node attributes registration interface:
   * When/if hugetlb[fs] subsystem initializes [sometime after this module],
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
249
250
   * it will register its per node attributes for all online nodes with
   * memory.  It will also call register_hugetlbfs_with_node(), below, to
9a3052306   Lee Schermerhorn   hugetlb: add per ...
251
252
253
254
255
256
   * register its attribute registration functions with this node driver.
   * Once these hooks have been initialized, the node driver will call into
   * the hugetlb module to [un]register attributes for hot-plugged nodes.
   */
  static node_registration_func_t __hugetlb_register_node;
  static node_registration_func_t __hugetlb_unregister_node;
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
257
  static inline bool hugetlb_register_node(struct node *node)
9a3052306   Lee Schermerhorn   hugetlb: add per ...
258
  {
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
259
  	if (__hugetlb_register_node &&
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
260
  			node_state(node->sysdev.id, N_HIGH_MEMORY)) {
9a3052306   Lee Schermerhorn   hugetlb: add per ...
261
  		__hugetlb_register_node(node);
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
262
263
264
  		return true;
  	}
  	return false;
9a3052306   Lee Schermerhorn   hugetlb: add per ...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  }
  
  static inline void hugetlb_unregister_node(struct node *node)
  {
  	if (__hugetlb_unregister_node)
  		__hugetlb_unregister_node(node);
  }
  
  void register_hugetlbfs_with_node(node_registration_func_t doregister,
  				  node_registration_func_t unregister)
  {
  	__hugetlb_register_node   = doregister;
  	__hugetlb_unregister_node = unregister;
  }
  #else
  static inline void hugetlb_register_node(struct node *node) {}
  
  static inline void hugetlb_unregister_node(struct node *node) {}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  
  /*
405ae7d38   Robert P. J. Day   Replace remaining...
286
   * register_node - Setup a sysfs device for a node.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
   * @num - Node number to use when creating the device.
   *
   * Initialize and register the node device.
   */
4b45099b7   Keiichiro Tokunaga   [PATCH] Driver co...
291
  int register_node(struct node *node, int num, struct node *parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
  {
  	int error;
  
  	node->sysdev.id = num;
  	node->sysdev.cls = &node_class;
  	error = sysdev_register(&node->sysdev);
  
  	if (!error){
  		sysdev_create_file(&node->sysdev, &attr_cpumap);
39106dcf8   Mike Travis   cpumask: use new ...
301
  		sysdev_create_file(&node->sysdev, &attr_cpulist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
  		sysdev_create_file(&node->sysdev, &attr_meminfo);
  		sysdev_create_file(&node->sysdev, &attr_numastat);
  		sysdev_create_file(&node->sysdev, &attr_distance);
2ac390370   Michael Rubin   writeback: add /s...
305
  		sysdev_create_file(&node->sysdev, &attr_vmstat);
af936a160   Lee Schermerhorn   vmscan: unevictab...
306
307
  
  		scan_unevictable_register_node(node);
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
308

9a3052306   Lee Schermerhorn   hugetlb: add per ...
309
  		hugetlb_register_node(node);
ed4a6d7f0   Mel Gorman   mm: compaction: a...
310
311
  
  		compaction_register_node(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
  	}
  	return error;
  }
4b45099b7   Keiichiro Tokunaga   [PATCH] Driver co...
315
316
317
318
319
320
321
322
323
324
  /**
   * unregister_node - unregister a node device
   * @node: node going away
   *
   * Unregisters a node device @node.  All the devices on the node must be
   * unregistered before calling this function.
   */
  void unregister_node(struct node *node)
  {
  	sysdev_remove_file(&node->sysdev, &attr_cpumap);
39106dcf8   Mike Travis   cpumask: use new ...
325
  	sysdev_remove_file(&node->sysdev, &attr_cpulist);
4b45099b7   Keiichiro Tokunaga   [PATCH] Driver co...
326
327
328
  	sysdev_remove_file(&node->sysdev, &attr_meminfo);
  	sysdev_remove_file(&node->sysdev, &attr_numastat);
  	sysdev_remove_file(&node->sysdev, &attr_distance);
2ac390370   Michael Rubin   writeback: add /s...
329
  	sysdev_remove_file(&node->sysdev, &attr_vmstat);
4b45099b7   Keiichiro Tokunaga   [PATCH] Driver co...
330

af936a160   Lee Schermerhorn   vmscan: unevictab...
331
  	scan_unevictable_unregister_node(node);
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
332
  	hugetlb_unregister_node(node);		/* no-op, if memoryless node */
af936a160   Lee Schermerhorn   vmscan: unevictab...
333

4b45099b7   Keiichiro Tokunaga   [PATCH] Driver co...
334
335
  	sysdev_unregister(&node->sysdev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336

0fc44159b   Yasunori Goto   [PATCH] Register ...
337
  struct node node_devices[MAX_NUMNODES];
76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
338
339
340
341
342
  /*
   * register cpu under node
   */
  int register_cpu_under_node(unsigned int cpu, unsigned int nid)
  {
1830794ae   Alex Chiang   mm: add numa node...
343
  	int ret;
f8246f315   Alex Chiang   mm: refactor regi...
344
  	struct sys_device *obj;
76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
345

f8246f315   Alex Chiang   mm: refactor regi...
346
347
348
349
350
351
  	if (!node_online(nid))
  		return 0;
  
  	obj = get_cpu_sysdev(cpu);
  	if (!obj)
  		return 0;
1830794ae   Alex Chiang   mm: add numa node...
352
  	ret = sysfs_create_link(&node_devices[nid].sysdev.kobj,
f8246f315   Alex Chiang   mm: refactor regi...
353
354
  				&obj->kobj,
  				kobject_name(&obj->kobj));
1830794ae   Alex Chiang   mm: add numa node...
355
356
357
358
359
360
  	if (ret)
  		return ret;
  
  	return sysfs_create_link(&obj->kobj,
  				 &node_devices[nid].sysdev.kobj,
  				 kobject_name(&node_devices[nid].sysdev.kobj));
76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
361
362
363
364
  }
  
  int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
  {
b9d52dad9   Alex Chiang   mm: refactor unre...
365
366
367
368
369
370
371
372
373
374
375
  	struct sys_device *obj;
  
  	if (!node_online(nid))
  		return 0;
  
  	obj = get_cpu_sysdev(cpu);
  	if (!obj)
  		return 0;
  
  	sysfs_remove_link(&node_devices[nid].sysdev.kobj,
  			  kobject_name(&obj->kobj));
1830794ae   Alex Chiang   mm: add numa node...
376
377
  	sysfs_remove_link(&obj->kobj,
  			  kobject_name(&node_devices[nid].sysdev.kobj));
b9d52dad9   Alex Chiang   mm: refactor unre...
378

76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
379
380
  	return 0;
  }
c04fc586c   Gary Hade   mm: show node to ...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
  #define page_initialized(page)  (page->lru.next)
  
  static int get_nid_for_pfn(unsigned long pfn)
  {
  	struct page *page;
  
  	if (!pfn_valid_within(pfn))
  		return -1;
  	page = pfn_to_page(pfn);
  	if (!page_initialized(page))
  		return -1;
  	return pfn_to_nid(pfn);
  }
  
  /* register memory section under specified node if it spans that node */
  int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
  {
dee5d0d51   Alex Chiang   mm: add numa node...
399
  	int ret;
c04fc586c   Gary Hade   mm: show node to ...
400
401
402
403
404
405
  	unsigned long pfn, sect_start_pfn, sect_end_pfn;
  
  	if (!mem_blk)
  		return -EFAULT;
  	if (!node_online(nid))
  		return 0;
d33601644   Nathan Fontenot   memory hotplug: U...
406
407
408
409
  
  	sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
  	sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr);
  	sect_end_pfn += PAGES_PER_SECTION - 1;
c04fc586c   Gary Hade   mm: show node to ...
410
411
412
413
414
415
416
417
  	for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
  		int page_nid;
  
  		page_nid = get_nid_for_pfn(pfn);
  		if (page_nid < 0)
  			continue;
  		if (page_nid != nid)
  			continue;
dee5d0d51   Alex Chiang   mm: add numa node...
418
  		ret = sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj,
c04fc586c   Gary Hade   mm: show node to ...
419
420
  					&mem_blk->sysdev.kobj,
  					kobject_name(&mem_blk->sysdev.kobj));
dee5d0d51   Alex Chiang   mm: add numa node...
421
422
423
424
425
426
  		if (ret)
  			return ret;
  
  		return sysfs_create_link_nowarn(&mem_blk->sysdev.kobj,
  				&node_devices[nid].sysdev.kobj,
  				kobject_name(&node_devices[nid].sysdev.kobj));
c04fc586c   Gary Hade   mm: show node to ...
427
428
429
430
431
432
  	}
  	/* mem section does not span the specified node */
  	return 0;
  }
  
  /* unregister memory section under all nodes that it spans */
d33601644   Nathan Fontenot   memory hotplug: U...
433
434
  int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
  				    unsigned long phys_index)
c04fc586c   Gary Hade   mm: show node to ...
435
  {
9ae49fab2   David Rientjes   mm: slab-allocate...
436
  	NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
c04fc586c   Gary Hade   mm: show node to ...
437
  	unsigned long pfn, sect_start_pfn, sect_end_pfn;
9ae49fab2   David Rientjes   mm: slab-allocate...
438
439
  	if (!mem_blk) {
  		NODEMASK_FREE(unlinked_nodes);
c04fc586c   Gary Hade   mm: show node to ...
440
  		return -EFAULT;
9ae49fab2   David Rientjes   mm: slab-allocate...
441
442
443
444
  	}
  	if (!unlinked_nodes)
  		return -ENOMEM;
  	nodes_clear(*unlinked_nodes);
d33601644   Nathan Fontenot   memory hotplug: U...
445
446
  
  	sect_start_pfn = section_nr_to_pfn(phys_index);
c04fc586c   Gary Hade   mm: show node to ...
447
448
  	sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
  	for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
475049809   Roel Kluin   mm: get_nid_for_p...
449
  		int nid;
c04fc586c   Gary Hade   mm: show node to ...
450
451
452
453
454
455
  
  		nid = get_nid_for_pfn(pfn);
  		if (nid < 0)
  			continue;
  		if (!node_online(nid))
  			continue;
9ae49fab2   David Rientjes   mm: slab-allocate...
456
  		if (node_test_and_set(nid, *unlinked_nodes))
c04fc586c   Gary Hade   mm: show node to ...
457
458
459
  			continue;
  		sysfs_remove_link(&node_devices[nid].sysdev.kobj,
  			 kobject_name(&mem_blk->sysdev.kobj));
dee5d0d51   Alex Chiang   mm: add numa node...
460
461
  		sysfs_remove_link(&mem_blk->sysdev.kobj,
  			 kobject_name(&node_devices[nid].sysdev.kobj));
c04fc586c   Gary Hade   mm: show node to ...
462
  	}
9ae49fab2   David Rientjes   mm: slab-allocate...
463
  	NODEMASK_FREE(unlinked_nodes);
c04fc586c   Gary Hade   mm: show node to ...
464
465
466
467
468
469
470
471
  	return 0;
  }
  
  static int link_mem_sections(int nid)
  {
  	unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
  	unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
  	unsigned long pfn;
63d027a63   Robin Holt   driver core: Conv...
472
  	struct memory_block *mem_blk = NULL;
c04fc586c   Gary Hade   mm: show node to ...
473
474
475
476
477
  	int err = 0;
  
  	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
  		unsigned long section_nr = pfn_to_section_nr(pfn);
  		struct mem_section *mem_sect;
c04fc586c   Gary Hade   mm: show node to ...
478
479
480
481
482
  		int ret;
  
  		if (!present_section_nr(section_nr))
  			continue;
  		mem_sect = __nr_to_section(section_nr);
63d027a63   Robin Holt   driver core: Conv...
483
  		mem_blk = find_memory_block_hinted(mem_sect, mem_blk);
c04fc586c   Gary Hade   mm: show node to ...
484
485
486
487
488
  		ret = register_mem_sect_under_node(mem_blk, nid);
  		if (!err)
  			err = ret;
  
  		/* discard ref obtained in find_memory_block() */
c04fc586c   Gary Hade   mm: show node to ...
489
  	}
63d027a63   Robin Holt   driver core: Conv...
490
491
492
  
  	if (mem_blk)
  		kobject_put(&mem_blk->sysdev.kobj);
c04fc586c   Gary Hade   mm: show node to ...
493
494
  	return err;
  }
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
495

39da08cb0   Lee Schermerhorn   hugetlb: offload ...
496
  #ifdef CONFIG_HUGETLBFS
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
497
498
499
500
  /*
   * Handle per node hstate attribute [un]registration on transistions
   * to/from memoryless state.
   */
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  static void node_hugetlb_work(struct work_struct *work)
  {
  	struct node *node = container_of(work, struct node, node_work);
  
  	/*
  	 * We only get here when a node transitions to/from memoryless state.
  	 * We can detect which transition occurred by examining whether the
  	 * node has memory now.  hugetlb_register_node() already check this
  	 * so we try to register the attributes.  If that fails, then the
  	 * node has transitioned to memoryless, try to unregister the
  	 * attributes.
  	 */
  	if (!hugetlb_register_node(node))
  		hugetlb_unregister_node(node);
  }
  
  static void init_node_hugetlb_work(int nid)
  {
  	INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work);
  }
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
521
522
523
524
525
526
527
528
  
  static int node_memory_callback(struct notifier_block *self,
  				unsigned long action, void *arg)
  {
  	struct memory_notify *mnb = arg;
  	int nid = mnb->status_change_nid;
  
  	switch (action) {
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
529
530
531
532
533
534
  	case MEM_ONLINE:
  	case MEM_OFFLINE:
  		/*
  		 * offload per node hstate [un]registration to a work thread
  		 * when transitioning to/from memoryless state.
  		 */
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
535
  		if (nid != NUMA_NO_NODE)
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
536
  			schedule_work(&node_devices[nid].node_work);
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
537
  		break;
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
538

4faf8d950   Lee Schermerhorn   hugetlb: handle m...
539
540
541
542
543
544
545
546
547
548
  	case MEM_GOING_ONLINE:
  	case MEM_GOING_OFFLINE:
  	case MEM_CANCEL_ONLINE:
  	case MEM_CANCEL_OFFLINE:
  	default:
  		break;
  	}
  
  	return NOTIFY_OK;
  }
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
549
550
  #endif	/* CONFIG_HUGETLBFS */
  #else	/* !CONFIG_MEMORY_HOTPLUG_SPARSE */
c04fc586c   Gary Hade   mm: show node to ...
551
  static int link_mem_sections(int nid) { return 0; }
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
552
  #endif	/* CONFIG_MEMORY_HOTPLUG_SPARSE */
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
553

39da08cb0   Lee Schermerhorn   hugetlb: offload ...
554
555
  #if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \
      !defined(CONFIG_HUGETLBFS)
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
556
557
558
559
560
  static inline int node_memory_callback(struct notifier_block *self,
  				unsigned long action, void *arg)
  {
  	return NOTIFY_OK;
  }
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
561
562
563
564
  
  static void init_node_hugetlb_work(int nid) { }
  
  #endif
c04fc586c   Gary Hade   mm: show node to ...
565

0fc44159b   Yasunori Goto   [PATCH] Register ...
566
567
568
  int register_one_node(int nid)
  {
  	int error = 0;
76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
569
  	int cpu;
0fc44159b   Yasunori Goto   [PATCH] Register ...
570
571
572
573
574
575
576
577
578
  
  	if (node_online(nid)) {
  		int p_node = parent_node(nid);
  		struct node *parent = NULL;
  
  		if (p_node != nid)
  			parent = &node_devices[p_node];
  
  		error = register_node(&node_devices[nid], nid, parent);
76b67ed9d   KAMEZAWA Hiroyuki   [PATCH] node hotp...
579
580
581
582
583
584
  
  		/* link cpu under this node */
  		for_each_present_cpu(cpu) {
  			if (cpu_to_node(cpu) == nid)
  				register_cpu_under_node(cpu, nid);
  		}
c04fc586c   Gary Hade   mm: show node to ...
585
586
587
  
  		/* link memory sections under this node */
  		error = link_mem_sections(nid);
39da08cb0   Lee Schermerhorn   hugetlb: offload ...
588
589
590
  
  		/* initialize work queue for memory hot plug */
  		init_node_hugetlb_work(nid);
0fc44159b   Yasunori Goto   [PATCH] Register ...
591
592
593
594
595
596
597
598
599
600
  	}
  
  	return error;
  
  }
  
  void unregister_one_node(int nid)
  {
  	unregister_node(&node_devices[nid]);
  }
bde631a51   Lee Schermerhorn   mm: add node stat...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  /*
   * node states attributes
   */
  
  static ssize_t print_nodes_state(enum node_states state, char *buf)
  {
  	int n;
  
  	n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]);
  	if (n > 0 && PAGE_SIZE > n + 1) {
  		*(buf + n++) = '
  ';
  		*(buf + n++) = '\0';
  	}
  	return n;
  }
b15f562fc   Andi Kleen   sysdev: Convert n...
617
618
619
620
  struct node_attr {
  	struct sysdev_class_attribute attr;
  	enum node_states state;
  };
bde631a51   Lee Schermerhorn   mm: add node stat...
621

b15f562fc   Andi Kleen   sysdev: Convert n...
622
623
  static ssize_t show_node_state(struct sysdev_class *class,
  			       struct sysdev_class_attribute *attr, char *buf)
bde631a51   Lee Schermerhorn   mm: add node stat...
624
  {
b15f562fc   Andi Kleen   sysdev: Convert n...
625
626
  	struct node_attr *na = container_of(attr, struct node_attr, attr);
  	return print_nodes_state(na->state, buf);
bde631a51   Lee Schermerhorn   mm: add node stat...
627
  }
b15f562fc   Andi Kleen   sysdev: Convert n...
628
629
  #define _NODE_ATTR(name, state) \
  	{ _SYSDEV_CLASS_ATTR(name, 0444, show_node_state, NULL), state }
bde631a51   Lee Schermerhorn   mm: add node stat...
630

b15f562fc   Andi Kleen   sysdev: Convert n...
631
632
633
634
635
  static struct node_attr node_state_attr[] = {
  	_NODE_ATTR(possible, N_POSSIBLE),
  	_NODE_ATTR(online, N_ONLINE),
  	_NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY),
  	_NODE_ATTR(has_cpu, N_CPU),
bde631a51   Lee Schermerhorn   mm: add node stat...
636
  #ifdef CONFIG_HIGHMEM
b15f562fc   Andi Kleen   sysdev: Convert n...
637
  	_NODE_ATTR(has_high_memory, N_HIGH_MEMORY),
bde631a51   Lee Schermerhorn   mm: add node stat...
638
  #endif
bde631a51   Lee Schermerhorn   mm: add node stat...
639
  };
3701cde6e   Andi Kleen   sysdev: Use sysde...
640
641
642
643
644
645
646
647
648
649
  static struct sysdev_class_attribute *node_state_attrs[] = {
  	&node_state_attr[0].attr,
  	&node_state_attr[1].attr,
  	&node_state_attr[2].attr,
  	&node_state_attr[3].attr,
  #ifdef CONFIG_HIGHMEM
  	&node_state_attr[4].attr,
  #endif
  	NULL
  };
bde631a51   Lee Schermerhorn   mm: add node stat...
650

4faf8d950   Lee Schermerhorn   hugetlb: handle m...
651
  #define NODE_CALLBACK_PRI	2	/* lower than SLAB */
4b45099b7   Keiichiro Tokunaga   [PATCH] Driver co...
652
  static int __init register_node_type(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  {
bde631a51   Lee Schermerhorn   mm: add node stat...
654
  	int ret;
3701cde6e   Andi Kleen   sysdev: Use sysde...
655
656
   	BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES);
   	BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES);
bde631a51   Lee Schermerhorn   mm: add node stat...
657
  	ret = sysdev_class_register(&node_class);
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
658
  	if (!ret) {
4faf8d950   Lee Schermerhorn   hugetlb: handle m...
659
660
661
  		hotplug_memory_notifier(node_memory_callback,
  					NODE_CALLBACK_PRI);
  	}
bde631a51   Lee Schermerhorn   mm: add node stat...
662
663
664
665
666
667
  
  	/*
  	 * Note:  we're not going to unregister the node class if we fail
  	 * to register the node state class attribute files.
  	 */
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  }
  postcore_initcall(register_node_type);