Blame view

drivers/base/memory.c 16.3 KB
3947be196   Dave Hansen   [PATCH] memory ho...
1
  /*
10fbcf4c6   Kay Sievers   convert 'memory' ...
2
   * Memory subsystem support
3947be196   Dave Hansen   [PATCH] memory ho...
3
4
5
6
7
8
9
10
11
   *
   * Written by Matt Tolentino <matthew.e.tolentino@intel.com>
   *            Dave Hansen <haveblue@us.ibm.com>
   *
   * This file provides the necessary infrastructure to represent
   * a SPARSEMEM-memory-model system's physical memory in /sysfs.
   * All arch-independent code that assumes MEMORY_HOTPLUG requires
   * SPARSEMEM should be contained here, or in mm/memory_hotplug.c.
   */
3947be196   Dave Hansen   [PATCH] memory ho...
12
13
  #include <linux/module.h>
  #include <linux/init.h>
3947be196   Dave Hansen   [PATCH] memory ho...
14
  #include <linux/topology.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
15
  #include <linux/capability.h>
3947be196   Dave Hansen   [PATCH] memory ho...
16
17
18
19
20
  #include <linux/device.h>
  #include <linux/memory.h>
  #include <linux/kobject.h>
  #include <linux/memory_hotplug.h>
  #include <linux/mm.h>
da19cbcf7   Daniel Walker   driver core: memo...
21
  #include <linux/mutex.h>
9f1b16a51   Shaohua Li   memory_probe: fix...
22
  #include <linux/stat.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
9f1b16a51   Shaohua Li   memory_probe: fix...
24

60063497a   Arun Sharma   atomic: use <linu...
25
  #include <linux/atomic.h>
3947be196   Dave Hansen   [PATCH] memory ho...
26
  #include <asm/uaccess.h>
2938ffbd4   Nathan Fontenot   Driver core: Add ...
27
  static DEFINE_MUTEX(mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
28
  #define MEMORY_CLASS_NAME	"memory"
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
29
30
31
32
33
34
35
  
  static int sections_per_block;
  
  static inline int base_memory_block_id(int section_nr)
  {
  	return section_nr / sections_per_block;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
36

10fbcf4c6   Kay Sievers   convert 'memory' ...
37
  static struct bus_type memory_subsys = {
af5ca3f4e   Kay Sievers   Driver core: chan...
38
  	.name = MEMORY_CLASS_NAME,
10fbcf4c6   Kay Sievers   convert 'memory' ...
39
  	.dev_name = MEMORY_CLASS_NAME,
3947be196   Dave Hansen   [PATCH] memory ho...
40
  };
e041c6834   Alan Stern   [PATCH] Notifier ...
41
  static BLOCKING_NOTIFIER_HEAD(memory_chain);
3947be196   Dave Hansen   [PATCH] memory ho...
42

98a38ebdd   Andy Whitcroft   [PATCH] memhotplu...
43
  int register_memory_notifier(struct notifier_block *nb)
3947be196   Dave Hansen   [PATCH] memory ho...
44
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
45
          return blocking_notifier_chain_register(&memory_chain, nb);
3947be196   Dave Hansen   [PATCH] memory ho...
46
  }
3c82c30cd   Hannes Hering   memory: Introduce...
47
  EXPORT_SYMBOL(register_memory_notifier);
3947be196   Dave Hansen   [PATCH] memory ho...
48

98a38ebdd   Andy Whitcroft   [PATCH] memhotplu...
49
  void unregister_memory_notifier(struct notifier_block *nb)
3947be196   Dave Hansen   [PATCH] memory ho...
50
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
51
          blocking_notifier_chain_unregister(&memory_chain, nb);
3947be196   Dave Hansen   [PATCH] memory ho...
52
  }
3c82c30cd   Hannes Hering   memory: Introduce...
53
  EXPORT_SYMBOL(unregister_memory_notifier);
3947be196   Dave Hansen   [PATCH] memory ho...
54

925cc71e5   Robert Jennings   mm: Add notifier ...
55
56
57
58
59
60
61
62
63
64
65
66
67
  static ATOMIC_NOTIFIER_HEAD(memory_isolate_chain);
  
  int register_memory_isolate_notifier(struct notifier_block *nb)
  {
  	return atomic_notifier_chain_register(&memory_isolate_chain, nb);
  }
  EXPORT_SYMBOL(register_memory_isolate_notifier);
  
  void unregister_memory_isolate_notifier(struct notifier_block *nb)
  {
  	atomic_notifier_chain_unregister(&memory_isolate_chain, nb);
  }
  EXPORT_SYMBOL(unregister_memory_isolate_notifier);
3947be196   Dave Hansen   [PATCH] memory ho...
68
69
70
  /*
   * register_memory - Setup a sysfs device for a memory block
   */
00a41db52   Badari Pulavarty   driver core: regi...
71
  static
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
72
  int register_memory(struct memory_block *memory)
3947be196   Dave Hansen   [PATCH] memory ho...
73
74
  {
  	int error;
10fbcf4c6   Kay Sievers   convert 'memory' ...
75
76
  	memory->dev.bus = &memory_subsys;
  	memory->dev.id = memory->start_section_nr / sections_per_block;
3947be196   Dave Hansen   [PATCH] memory ho...
77

10fbcf4c6   Kay Sievers   convert 'memory' ...
78
  	error = device_register(&memory->dev);
3947be196   Dave Hansen   [PATCH] memory ho...
79
80
81
82
  	return error;
  }
  
  static void
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
83
  unregister_memory(struct memory_block *memory)
3947be196   Dave Hansen   [PATCH] memory ho...
84
  {
10fbcf4c6   Kay Sievers   convert 'memory' ...
85
  	BUG_ON(memory->dev.bus != &memory_subsys);
3947be196   Dave Hansen   [PATCH] memory ho...
86

00a41db52   Badari Pulavarty   driver core: regi...
87
  	/* drop the ref. we got in remove_memory_block() */
10fbcf4c6   Kay Sievers   convert 'memory' ...
88
89
  	kobject_put(&memory->dev.kobj);
  	device_unregister(&memory->dev);
3947be196   Dave Hansen   [PATCH] memory ho...
90
  }
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  unsigned long __weak memory_block_size_bytes(void)
  {
  	return MIN_MEMORY_BLOCK_SIZE;
  }
  
  static unsigned long get_memory_block_size(void)
  {
  	unsigned long block_sz;
  
  	block_sz = memory_block_size_bytes();
  
  	/* Validate blk_sz is a power of 2 and not less than section size */
  	if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) {
  		WARN_ON(1);
  		block_sz = MIN_MEMORY_BLOCK_SIZE;
  	}
  
  	return block_sz;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
110
111
112
113
  /*
   * use this as the physical section index that this memsection
   * uses.
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
114
115
  static ssize_t show_mem_start_phys_index(struct device *dev,
  			struct device_attribute *attr, char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
116
117
  {
  	struct memory_block *mem =
10fbcf4c6   Kay Sievers   convert 'memory' ...
118
  		container_of(dev, struct memory_block, dev);
d33601644   Nathan Fontenot   memory hotplug: U...
119
120
121
122
123
124
  	unsigned long phys_index;
  
  	phys_index = mem->start_section_nr / sections_per_block;
  	return sprintf(buf, "%08lx
  ", phys_index);
  }
10fbcf4c6   Kay Sievers   convert 'memory' ...
125
126
  static ssize_t show_mem_end_phys_index(struct device *dev,
  			struct device_attribute *attr, char *buf)
d33601644   Nathan Fontenot   memory hotplug: U...
127
128
  {
  	struct memory_block *mem =
10fbcf4c6   Kay Sievers   convert 'memory' ...
129
  		container_of(dev, struct memory_block, dev);
d33601644   Nathan Fontenot   memory hotplug: U...
130
131
132
133
134
  	unsigned long phys_index;
  
  	phys_index = mem->end_section_nr / sections_per_block;
  	return sprintf(buf, "%08lx
  ", phys_index);
3947be196   Dave Hansen   [PATCH] memory ho...
135
136
137
  }
  
  /*
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
138
139
   * Show whether the section of memory is likely to be hot-removable
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
140
141
  static ssize_t show_mem_removable(struct device *dev,
  			struct device_attribute *attr, char *buf)
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
142
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
143
144
  	unsigned long i, pfn;
  	int ret = 1;
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
145
  	struct memory_block *mem =
10fbcf4c6   Kay Sievers   convert 'memory' ...
146
  		container_of(dev, struct memory_block, dev);
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
147

0c2c99b1b   Nathan Fontenot   memory hotplug: A...
148
  	for (i = 0; i < sections_per_block; i++) {
d33601644   Nathan Fontenot   memory hotplug: U...
149
  		pfn = section_nr_to_pfn(mem->start_section_nr + i);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
150
151
  		ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
  	}
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
152
153
154
155
156
  	return sprintf(buf, "%d
  ", ret);
  }
  
  /*
3947be196   Dave Hansen   [PATCH] memory ho...
157
158
   * online, offline, going offline, etc.
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
159
160
  static ssize_t show_mem_state(struct device *dev,
  			struct device_attribute *attr, char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
161
162
  {
  	struct memory_block *mem =
10fbcf4c6   Kay Sievers   convert 'memory' ...
163
  		container_of(dev, struct memory_block, dev);
3947be196   Dave Hansen   [PATCH] memory ho...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  	ssize_t len = 0;
  
  	/*
  	 * We can probably put these states in a nice little array
  	 * so that they're not open-coded
  	 */
  	switch (mem->state) {
  		case MEM_ONLINE:
  			len = sprintf(buf, "online
  ");
  			break;
  		case MEM_OFFLINE:
  			len = sprintf(buf, "offline
  ");
  			break;
  		case MEM_GOING_OFFLINE:
  			len = sprintf(buf, "going-offline
  ");
  			break;
  		default:
  			len = sprintf(buf, "ERROR-UNKNOWN-%ld
  ",
  					mem->state);
  			WARN_ON(1);
  			break;
  	}
  
  	return len;
  }
7b78d335a   Yasunori Goto   memory hotplug: r...
193
  int memory_notify(unsigned long val, void *v)
3947be196   Dave Hansen   [PATCH] memory ho...
194
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
195
  	return blocking_notifier_call_chain(&memory_chain, val, v);
3947be196   Dave Hansen   [PATCH] memory ho...
196
  }
925cc71e5   Robert Jennings   mm: Add notifier ...
197
198
199
200
  int memory_isolate_notify(unsigned long val, void *v)
  {
  	return atomic_notifier_call_chain(&memory_isolate_chain, val, v);
  }
3947be196   Dave Hansen   [PATCH] memory ho...
201
  /*
2bbcb8788   Mel Gorman   mm: memory hotplu...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
   * The probe routines leave the pages reserved, just as the bootmem code does.
   * Make sure they're still that way.
   */
  static bool pages_correctly_reserved(unsigned long start_pfn,
  					unsigned long nr_pages)
  {
  	int i, j;
  	struct page *page;
  	unsigned long pfn = start_pfn;
  
  	/*
  	 * memmap between sections is not contiguous except with
  	 * SPARSEMEM_VMEMMAP. We lookup the page once per section
  	 * and assume memmap is contiguous within each section
  	 */
  	for (i = 0; i < sections_per_block; i++, pfn += PAGES_PER_SECTION) {
  		if (WARN_ON_ONCE(!pfn_valid(pfn)))
  			return false;
  		page = pfn_to_page(pfn);
  
  		for (j = 0; j < PAGES_PER_SECTION; j++) {
  			if (PageReserved(page + j))
  				continue;
  
  			printk(KERN_WARNING "section number %ld page number %d "
  				"not reserved, was it already online?
  ",
  				pfn_to_section_nr(pfn), j);
  
  			return false;
  		}
  	}
  
  	return true;
  }
  
  /*
3947be196   Dave Hansen   [PATCH] memory ho...
239
240
241
242
   * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
   * OK to have direct references to sparsemem variables in here.
   */
  static int
5409d2cd8   Anton Blanchard   memory hotplug: S...
243
  memory_block_action(unsigned long phys_index, unsigned long action)
3947be196   Dave Hansen   [PATCH] memory ho...
244
  {
3947be196   Dave Hansen   [PATCH] memory ho...
245
  	unsigned long start_pfn, start_paddr;
5409d2cd8   Anton Blanchard   memory hotplug: S...
246
  	unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
247
  	struct page *first_page;
3947be196   Dave Hansen   [PATCH] memory ho...
248
  	int ret;
3947be196   Dave Hansen   [PATCH] memory ho...
249

de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
250
  	first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);
3947be196   Dave Hansen   [PATCH] memory ho...
251
252
  	switch (action) {
  		case MEM_ONLINE:
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
253
  			start_pfn = page_to_pfn(first_page);
2bbcb8788   Mel Gorman   mm: memory hotplu...
254
255
256
  
  			if (!pages_correctly_reserved(start_pfn, nr_pages))
  				return -EBUSY;
5409d2cd8   Anton Blanchard   memory hotplug: S...
257
  			ret = online_pages(start_pfn, nr_pages);
3947be196   Dave Hansen   [PATCH] memory ho...
258
259
  			break;
  		case MEM_OFFLINE:
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
260
  			start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
3947be196   Dave Hansen   [PATCH] memory ho...
261
  			ret = remove_memory(start_paddr,
5409d2cd8   Anton Blanchard   memory hotplug: S...
262
  					    nr_pages << PAGE_SHIFT);
3947be196   Dave Hansen   [PATCH] memory ho...
263
264
  			break;
  		default:
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
265
266
267
  			WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
  			     "%ld
  ", __func__, phys_index, action, action);
3947be196   Dave Hansen   [PATCH] memory ho...
268
269
  			ret = -EINVAL;
  	}
3947be196   Dave Hansen   [PATCH] memory ho...
270
271
272
273
274
275
276
  
  	return ret;
  }
  
  static int memory_block_change_state(struct memory_block *mem,
  		unsigned long to_state, unsigned long from_state_req)
  {
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
277
  	int ret = 0;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
278

da19cbcf7   Daniel Walker   driver core: memo...
279
  	mutex_lock(&mem->state_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
280
281
282
283
284
  
  	if (mem->state != from_state_req) {
  		ret = -EINVAL;
  		goto out;
  	}
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
285
286
  	if (to_state == MEM_OFFLINE)
  		mem->state = MEM_GOING_OFFLINE;
5409d2cd8   Anton Blanchard   memory hotplug: S...
287
  	ret = memory_block_action(mem->start_section_nr, to_state);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
288

f5138e422   Michael Holzheu   kdump: add udev e...
289
  	if (ret) {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
290
  		mem->state = from_state_req;
f5138e422   Michael Holzheu   kdump: add udev e...
291
292
  		goto out;
  	}
3947be196   Dave Hansen   [PATCH] memory ho...
293

f5138e422   Michael Holzheu   kdump: add udev e...
294
295
296
297
298
299
300
301
302
303
304
  	mem->state = to_state;
  	switch (mem->state) {
  	case MEM_OFFLINE:
  		kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
  		break;
  	case MEM_ONLINE:
  		kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
  		break;
  	default:
  		break;
  	}
3947be196   Dave Hansen   [PATCH] memory ho...
305
  out:
da19cbcf7   Daniel Walker   driver core: memo...
306
  	mutex_unlock(&mem->state_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
307
308
309
310
  	return ret;
  }
  
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
311
312
  store_mem_state(struct device *dev,
  		struct device_attribute *attr, const char *buf, size_t count)
3947be196   Dave Hansen   [PATCH] memory ho...
313
314
  {
  	struct memory_block *mem;
3947be196   Dave Hansen   [PATCH] memory ho...
315
  	int ret = -EINVAL;
10fbcf4c6   Kay Sievers   convert 'memory' ...
316
  	mem = container_of(dev, struct memory_block, dev);
3947be196   Dave Hansen   [PATCH] memory ho...
317
318
319
320
321
  
  	if (!strncmp(buf, "online", min((int)count, 6)))
  		ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
  	else if(!strncmp(buf, "offline", min((int)count, 7)))
  		ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
322

3947be196   Dave Hansen   [PATCH] memory ho...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  	if (ret)
  		return ret;
  	return count;
  }
  
  /*
   * phys_device is a bad name for this.  What I really want
   * is a way to differentiate between memory ranges that
   * are part of physical devices that constitute
   * a complete removable unit or fru.
   * i.e. do these ranges belong to the same physical device,
   * s.t. if I offline all of these sections I can then
   * remove the physical device?
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
337
338
  static ssize_t show_phys_device(struct device *dev,
  				struct device_attribute *attr, char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
339
340
  {
  	struct memory_block *mem =
10fbcf4c6   Kay Sievers   convert 'memory' ...
341
  		container_of(dev, struct memory_block, dev);
3947be196   Dave Hansen   [PATCH] memory ho...
342
343
344
  	return sprintf(buf, "%d
  ", mem->phys_device);
  }
10fbcf4c6   Kay Sievers   convert 'memory' ...
345
346
347
348
349
  static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
  static DEVICE_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL);
  static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state);
  static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL);
  static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL);
3947be196   Dave Hansen   [PATCH] memory ho...
350
351
  
  #define mem_create_simple_file(mem, attr_name)	\
10fbcf4c6   Kay Sievers   convert 'memory' ...
352
  	device_create_file(&mem->dev, &dev_attr_##attr_name)
3947be196   Dave Hansen   [PATCH] memory ho...
353
  #define mem_remove_simple_file(mem, attr_name)	\
10fbcf4c6   Kay Sievers   convert 'memory' ...
354
  	device_remove_file(&mem->dev, &dev_attr_##attr_name)
3947be196   Dave Hansen   [PATCH] memory ho...
355
356
357
358
359
  
  /*
   * Block size attribute stuff
   */
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
360
  print_block_size(struct device *dev, struct device_attribute *attr,
8564a6c14   Andi Kleen   sysdev: Fix type ...
361
  		 char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
362
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
363
364
  	return sprintf(buf, "%lx
  ", get_memory_block_size());
3947be196   Dave Hansen   [PATCH] memory ho...
365
  }
10fbcf4c6   Kay Sievers   convert 'memory' ...
366
  static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL);
3947be196   Dave Hansen   [PATCH] memory ho...
367
368
369
  
  static int block_size_init(void)
  {
10fbcf4c6   Kay Sievers   convert 'memory' ...
370
371
  	return device_create_file(memory_subsys.dev_root,
  				  &dev_attr_block_size_bytes);
3947be196   Dave Hansen   [PATCH] memory ho...
372
373
374
375
376
377
378
379
380
381
  }
  
  /*
   * Some architectures will have custom drivers to do this, and
   * will not need to do it from userspace.  The fake hot-add code
   * as well as ppc64 will do all of their discovery in userspace
   * and will require this interface.
   */
  #ifdef CONFIG_ARCH_MEMORY_PROBE
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
382
  memory_probe_store(struct device *dev, struct device_attribute *attr,
28812fe11   Andi Kleen   driver-core: Add ...
383
  		   const char *buf, size_t count)
3947be196   Dave Hansen   [PATCH] memory ho...
384
385
  {
  	u64 phys_addr;
bc02af93d   Yasunori Goto   [PATCH] pgdat all...
386
  	int nid;
6add7cd61   Nathan Fontenot   memory hotplug: s...
387
  	int i, ret;
61b94feaf   Anton Blanchard   memory hotplug: R...
388
  	unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
3947be196   Dave Hansen   [PATCH] memory ho...
389
390
  
  	phys_addr = simple_strtoull(buf, NULL, 0);
61b94feaf   Anton Blanchard   memory hotplug: R...
391
392
  	if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
  		return -EINVAL;
6add7cd61   Nathan Fontenot   memory hotplug: s...
393
394
395
396
397
  	for (i = 0; i < sections_per_block; i++) {
  		nid = memory_add_physaddr_to_nid(phys_addr);
  		ret = add_memory(nid, phys_addr,
  				 PAGES_PER_SECTION << PAGE_SHIFT);
  		if (ret)
9f0af69b2   Nikanth Karthikesan   sysfs-memory: fix...
398
  			goto out;
6add7cd61   Nathan Fontenot   memory hotplug: s...
399
400
401
  
  		phys_addr += MIN_MEMORY_BLOCK_SIZE;
  	}
3947be196   Dave Hansen   [PATCH] memory ho...
402

9f0af69b2   Nikanth Karthikesan   sysfs-memory: fix...
403
404
405
  	ret = count;
  out:
  	return ret;
3947be196   Dave Hansen   [PATCH] memory ho...
406
  }
10fbcf4c6   Kay Sievers   convert 'memory' ...
407
  static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
3947be196   Dave Hansen   [PATCH] memory ho...
408
409
410
  
  static int memory_probe_init(void)
  {
10fbcf4c6   Kay Sievers   convert 'memory' ...
411
  	return device_create_file(memory_subsys.dev_root, &dev_attr_probe);
3947be196   Dave Hansen   [PATCH] memory ho...
412
413
  }
  #else
28ec24e23   Andrew Morton   [PATCH] driver/ba...
414
415
416
417
  static inline int memory_probe_init(void)
  {
  	return 0;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
418
  #endif
facb6011f   Andi Kleen   HWPOISON: Add sof...
419
420
421
422
423
424
425
  #ifdef CONFIG_MEMORY_FAILURE
  /*
   * Support for offlining pages of memory
   */
  
  /* Soft offline a page */
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
426
427
  store_soft_offline_page(struct device *dev,
  			struct device_attribute *attr,
28812fe11   Andi Kleen   driver-core: Add ...
428
  			const char *buf, size_t count)
facb6011f   Andi Kleen   HWPOISON: Add sof...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  {
  	int ret;
  	u64 pfn;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (strict_strtoull(buf, 0, &pfn) < 0)
  		return -EINVAL;
  	pfn >>= PAGE_SHIFT;
  	if (!pfn_valid(pfn))
  		return -ENXIO;
  	ret = soft_offline_page(pfn_to_page(pfn), 0);
  	return ret == 0 ? count : ret;
  }
  
  /* Forcibly offline a page, including killing processes. */
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
445
446
  store_hard_offline_page(struct device *dev,
  			struct device_attribute *attr,
28812fe11   Andi Kleen   driver-core: Add ...
447
  			const char *buf, size_t count)
facb6011f   Andi Kleen   HWPOISON: Add sof...
448
449
450
451
452
453
454
455
456
457
458
  {
  	int ret;
  	u64 pfn;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (strict_strtoull(buf, 0, &pfn) < 0)
  		return -EINVAL;
  	pfn >>= PAGE_SHIFT;
  	ret = __memory_failure(pfn, 0, 0);
  	return ret ? ret : count;
  }
10fbcf4c6   Kay Sievers   convert 'memory' ...
459
460
  static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
  static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
facb6011f   Andi Kleen   HWPOISON: Add sof...
461
462
463
464
  
  static __init int memory_fail_init(void)
  {
  	int err;
10fbcf4c6   Kay Sievers   convert 'memory' ...
465
466
  	err = device_create_file(memory_subsys.dev_root,
  				&dev_attr_soft_offline_page);
facb6011f   Andi Kleen   HWPOISON: Add sof...
467
  	if (!err)
10fbcf4c6   Kay Sievers   convert 'memory' ...
468
469
  		err = device_create_file(memory_subsys.dev_root,
  				&dev_attr_hard_offline_page);
facb6011f   Andi Kleen   HWPOISON: Add sof...
470
471
472
473
474
475
476
477
  	return err;
  }
  #else
  static inline int memory_fail_init(void)
  {
  	return 0;
  }
  #endif
3947be196   Dave Hansen   [PATCH] memory ho...
478
479
480
481
482
  /*
   * Note that phys_device is optional.  It is here to allow for
   * differentiation between which *physical* devices each
   * section belongs to...
   */
bc32df008   Heiko Carstens   memory hotplug: a...
483
484
485
486
  int __weak arch_get_memory_phys_device(unsigned long start_pfn)
  {
  	return 0;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
487

10fbcf4c6   Kay Sievers   convert 'memory' ...
488
489
490
491
  /*
   * A reference for the returned object is held and the reference for the
   * hinted object is released.
   */
98383031e   Robin Holt   driver core: Intr...
492
493
  struct memory_block *find_memory_block_hinted(struct mem_section *section,
  					      struct memory_block *hint)
3947be196   Dave Hansen   [PATCH] memory ho...
494
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
495
  	int block_id = base_memory_block_id(__section_nr(section));
10fbcf4c6   Kay Sievers   convert 'memory' ...
496
497
  	struct device *hintdev = hint ? &hint->dev : NULL;
  	struct device *dev;
3947be196   Dave Hansen   [PATCH] memory ho...
498

10fbcf4c6   Kay Sievers   convert 'memory' ...
499
500
501
502
  	dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev);
  	if (hint)
  		put_device(&hint->dev);
  	if (!dev)
3947be196   Dave Hansen   [PATCH] memory ho...
503
  		return NULL;
10fbcf4c6   Kay Sievers   convert 'memory' ...
504
  	return container_of(dev, struct memory_block, dev);
3947be196   Dave Hansen   [PATCH] memory ho...
505
  }
98383031e   Robin Holt   driver core: Intr...
506
507
508
509
510
511
  /*
   * For now, we have a linear search to go find the appropriate
   * memory_block corresponding to a particular phys_index. If
   * this gets to be a real problem, we can always use a radix
   * tree or something here.
   *
10fbcf4c6   Kay Sievers   convert 'memory' ...
512
   * This could be made generic for all device subsystems.
98383031e   Robin Holt   driver core: Intr...
513
514
515
516
517
   */
  struct memory_block *find_memory_block(struct mem_section *section)
  {
  	return find_memory_block_hinted(section, NULL);
  }
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
518
519
  static int init_memory_block(struct memory_block **memory,
  			     struct mem_section *section, unsigned long state)
e4619c857   Nathan Fontenot   Driver core: Move...
520
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
521
  	struct memory_block *mem;
e4619c857   Nathan Fontenot   Driver core: Move...
522
  	unsigned long start_pfn;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
523
  	int scn_nr;
e4619c857   Nathan Fontenot   Driver core: Move...
524
  	int ret = 0;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
525
  	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
e4619c857   Nathan Fontenot   Driver core: Move...
526
527
  	if (!mem)
  		return -ENOMEM;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
528
  	scn_nr = __section_nr(section);
d33601644   Nathan Fontenot   memory hotplug: U...
529
530
531
  	mem->start_section_nr =
  			base_memory_block_id(scn_nr) * sections_per_block;
  	mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
e4619c857   Nathan Fontenot   Driver core: Move...
532
  	mem->state = state;
076812159   Nathan Fontenot   Driver core: Add ...
533
  	mem->section_count++;
e4619c857   Nathan Fontenot   Driver core: Move...
534
  	mutex_init(&mem->state_mutex);
d33601644   Nathan Fontenot   memory hotplug: U...
535
  	start_pfn = section_nr_to_pfn(mem->start_section_nr);
e4619c857   Nathan Fontenot   Driver core: Move...
536
  	mem->phys_device = arch_get_memory_phys_device(start_pfn);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
537
  	ret = register_memory(mem);
e4619c857   Nathan Fontenot   Driver core: Move...
538
539
540
  	if (!ret)
  		ret = mem_create_simple_file(mem, phys_index);
  	if (!ret)
d33601644   Nathan Fontenot   memory hotplug: U...
541
542
  		ret = mem_create_simple_file(mem, end_phys_index);
  	if (!ret)
e4619c857   Nathan Fontenot   Driver core: Move...
543
544
545
546
547
  		ret = mem_create_simple_file(mem, state);
  	if (!ret)
  		ret = mem_create_simple_file(mem, phys_device);
  	if (!ret)
  		ret = mem_create_simple_file(mem, removable);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  
  	*memory = mem;
  	return ret;
  }
  
  static int add_memory_section(int nid, struct mem_section *section,
  			unsigned long state, enum mem_add_context context)
  {
  	struct memory_block *mem;
  	int ret = 0;
  
  	mutex_lock(&mem_sysfs_mutex);
  
  	mem = find_memory_block(section);
  	if (mem) {
  		mem->section_count++;
10fbcf4c6   Kay Sievers   convert 'memory' ...
564
  		kobject_put(&mem->dev.kobj);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
565
566
  	} else
  		ret = init_memory_block(&mem, section, state);
e4619c857   Nathan Fontenot   Driver core: Move...
567
  	if (!ret) {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
568
569
  		if (context == HOTPLUG &&
  		    mem->section_count == sections_per_block)
e4619c857   Nathan Fontenot   Driver core: Move...
570
571
  			ret = register_mem_sect_under_node(mem, nid);
  	}
2938ffbd4   Nathan Fontenot   Driver core: Add ...
572
  	mutex_unlock(&mem_sysfs_mutex);
e4619c857   Nathan Fontenot   Driver core: Move...
573
574
  	return ret;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
575
576
577
578
  int remove_memory_block(unsigned long node_id, struct mem_section *section,
  		int phys_device)
  {
  	struct memory_block *mem;
2938ffbd4   Nathan Fontenot   Driver core: Add ...
579
  	mutex_lock(&mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
580
  	mem = find_memory_block(section);
d33601644   Nathan Fontenot   memory hotplug: U...
581
  	unregister_mem_sect_under_nodes(mem, __section_nr(section));
076812159   Nathan Fontenot   Driver core: Add ...
582
583
584
  
  	mem->section_count--;
  	if (mem->section_count == 0) {
076812159   Nathan Fontenot   Driver core: Add ...
585
  		mem_remove_simple_file(mem, phys_index);
d33601644   Nathan Fontenot   memory hotplug: U...
586
  		mem_remove_simple_file(mem, end_phys_index);
076812159   Nathan Fontenot   Driver core: Add ...
587
588
589
  		mem_remove_simple_file(mem, state);
  		mem_remove_simple_file(mem, phys_device);
  		mem_remove_simple_file(mem, removable);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
590
591
592
  		unregister_memory(mem);
  		kfree(mem);
  	} else
10fbcf4c6   Kay Sievers   convert 'memory' ...
593
  		kobject_put(&mem->dev.kobj);
3947be196   Dave Hansen   [PATCH] memory ho...
594

2938ffbd4   Nathan Fontenot   Driver core: Add ...
595
  	mutex_unlock(&mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
596
597
598
599
600
601
602
  	return 0;
  }
  
  /*
   * need an interface for the VM to add new memory regions,
   * but without onlining it.
   */
c04fc586c   Gary Hade   mm: show node to ...
603
  int register_new_memory(int nid, struct mem_section *section)
3947be196   Dave Hansen   [PATCH] memory ho...
604
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
605
  	return add_memory_section(nid, section, MEM_OFFLINE, HOTPLUG);
3947be196   Dave Hansen   [PATCH] memory ho...
606
607
608
609
  }
  
  int unregister_memory_section(struct mem_section *section)
  {
540557b94   Andy Whitcroft   sparsemem: record...
610
  	if (!present_section(section))
3947be196   Dave Hansen   [PATCH] memory ho...
611
612
613
614
615
616
617
618
619
620
621
622
  		return -EINVAL;
  
  	return remove_memory_block(0, section, 0);
  }
  
  /*
   * Initialize the sysfs support for memory devices...
   */
  int __init memory_dev_init(void)
  {
  	unsigned int i;
  	int ret;
28ec24e23   Andrew Morton   [PATCH] driver/ba...
623
  	int err;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
624
  	unsigned long block_sz;
3947be196   Dave Hansen   [PATCH] memory ho...
625

10fbcf4c6   Kay Sievers   convert 'memory' ...
626
  	ret = subsys_system_register(&memory_subsys, NULL);
28ec24e23   Andrew Morton   [PATCH] driver/ba...
627
628
  	if (ret)
  		goto out;
3947be196   Dave Hansen   [PATCH] memory ho...
629

0c2c99b1b   Nathan Fontenot   memory hotplug: A...
630
631
  	block_sz = get_memory_block_size();
  	sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
3947be196   Dave Hansen   [PATCH] memory ho...
632
633
634
635
636
  	/*
  	 * Create entries for memory sections that were found
  	 * during boot and have been initialized
  	 */
  	for (i = 0; i < NR_MEM_SECTIONS; i++) {
540557b94   Andy Whitcroft   sparsemem: record...
637
  		if (!present_section_nr(i))
3947be196   Dave Hansen   [PATCH] memory ho...
638
  			continue;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
639
640
  		err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE,
  					 BOOT);
28ec24e23   Andrew Morton   [PATCH] driver/ba...
641
642
  		if (!ret)
  			ret = err;
3947be196   Dave Hansen   [PATCH] memory ho...
643
  	}
28ec24e23   Andrew Morton   [PATCH] driver/ba...
644
645
646
  	err = memory_probe_init();
  	if (!ret)
  		ret = err;
facb6011f   Andi Kleen   HWPOISON: Add sof...
647
648
649
  	err = memory_fail_init();
  	if (!ret)
  		ret = err;
28ec24e23   Andrew Morton   [PATCH] driver/ba...
650
651
652
653
654
  	err = block_size_init();
  	if (!ret)
  		ret = err;
  out:
  	if (ret)
2b3a302a0   Harvey Harrison   driver core: repl...
655
656
  		printk(KERN_ERR "%s() failed: %d
  ", __func__, ret);
3947be196   Dave Hansen   [PATCH] memory ho...
657
658
  	return ret;
  }