Skip to content

Commit 208d54e

Browse files
hansendcLinus Torvalds
authored andcommitted
[PATCH] memory hotplug locking: node_size_lock
pgdat->node_size_lock is basically only neeeded in one place in the normal code: show_mem(), which is the arch-specific sysrq-m printing function. Strictly speaking, the architectures not doing memory hotplug do no need this locking in show_mem(). However, they are all included for completeness. This should also make any future consolidation of all of the implementations a little more straightforward. This lock is also held in the sparsemem code during a memory removal, as sections are invalidated. This is the place there pfn_valid() is made false for a memory area that's being removed. The lock is only required when doing pfn_valid() operations on memory which the user does not already have a reference on the page, such as in show_mem(). Signed-off-by: Dave Hansen <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent c6a57e1 commit 208d54e

File tree

9 files changed

+76
-2
lines changed

9 files changed

+76
-2
lines changed

arch/alpha/mm/numa.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ show_mem(void)
371371
show_free_areas();
372372
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
373373
for_each_online_node(nid) {
374+
unsigned long flags;
375+
pgdat_resize_lock(NODE_DATA(nid), &flags);
374376
i = node_spanned_pages(nid);
375377
while (i-- > 0) {
376378
struct page *page = nid_page_nr(nid, i);
@@ -384,6 +386,7 @@ show_mem(void)
384386
else
385387
shared += page_count(page) - 1;
386388
}
389+
pgdat_resize_unlock(NODE_DATA(nid), &flags);
387390
}
388391
printk("%ld pages of RAM\n",total);
389392
printk("%ld free pages\n",free);

arch/i386/mm/pgtable.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ void show_mem(void)
3131
pg_data_t *pgdat;
3232
unsigned long i;
3333
struct page_state ps;
34+
unsigned long flags;
3435

3536
printk(KERN_INFO "Mem-info:\n");
3637
show_free_areas();
3738
printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
3839
for_each_pgdat(pgdat) {
40+
pgdat_resize_lock(pgdat, &flags);
3941
for (i = 0; i < pgdat->node_spanned_pages; ++i) {
4042
page = pgdat_page_nr(pgdat, i);
4143
total++;
@@ -48,6 +50,7 @@ void show_mem(void)
4850
else if (page_count(page))
4951
shared += page_count(page) - 1;
5052
}
53+
pgdat_resize_unlock(pgdat, &flags);
5154
}
5255
printk(KERN_INFO "%d pages of RAM\n", total);
5356
printk(KERN_INFO "%d pages of HIGHMEM\n", highmem);

arch/ia64/mm/discontig.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,9 +555,13 @@ void show_mem(void)
555555
show_free_areas();
556556
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
557557
for_each_pgdat(pgdat) {
558-
unsigned long present = pgdat->node_present_pages;
558+
unsigned long present;
559+
unsigned long flags;
559560
int shared = 0, cached = 0, reserved = 0;
561+
560562
printk("Node ID: %d\n", pgdat->node_id);
563+
pgdat_resize_lock(pgdat, &flags);
564+
present = pgdat->node_present_pages;
561565
for(i = 0; i < pgdat->node_spanned_pages; i++) {
562566
struct page *page;
563567
if (pfn_valid(pgdat->node_start_pfn + i))
@@ -571,6 +575,7 @@ void show_mem(void)
571575
else if (page_count(page))
572576
shared += page_count(page)-1;
573577
}
578+
pgdat_resize_unlock(pgdat, &flags);
574579
total_present += present;
575580
total_reserved += reserved;
576581
total_cached += cached;

arch/m32r/mm/init.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ void show_mem(void)
4848
show_free_areas();
4949
printk("Free swap: %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
5050
for_each_pgdat(pgdat) {
51+
unsigned long flags;
52+
pgdat_resize_lock(pgdat, &flags);
5153
for (i = 0; i < pgdat->node_spanned_pages; ++i) {
5254
page = pgdat_page_nr(pgdat, i);
5355
total++;
@@ -60,6 +62,7 @@ void show_mem(void)
6062
else if (page_count(page))
6163
shared += page_count(page) - 1;
6264
}
65+
pgdat_resize_unlock(pgdat, &flags);
6366
}
6467
printk("%d pages of RAM\n", total);
6568
printk("%d pages of HIGHMEM\n",highmem);
@@ -150,10 +153,14 @@ int __init reservedpages_count(void)
150153
int reservedpages, nid, i;
151154

152155
reservedpages = 0;
153-
for_each_online_node(nid)
156+
for_each_online_node(nid) {
157+
unsigned long flags;
158+
pgdat_resize_lock(NODE_DATA(nid), &flags);
154159
for (i = 0 ; i < MAX_LOW_PFN(nid) - START_PFN(nid) ; i++)
155160
if (PageReserved(nid_page_nr(nid, i)))
156161
reservedpages++;
162+
pgdat_resize_unlock(NODE_DATA(nid), &flags);
163+
}
157164

158165
return reservedpages;
159166
}

arch/parisc/mm/init.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,9 @@ void show_mem(void)
505505

506506
for (j = node_start_pfn(i); j < node_end_pfn(i); j++) {
507507
struct page *p;
508+
unsigned long flags;
508509

510+
pgdat_resize_lock(NODE_DATA(i), &flags);
509511
p = nid_page_nr(i, j) - node_start_pfn(i);
510512

511513
total++;
@@ -517,6 +519,7 @@ void show_mem(void)
517519
free++;
518520
else
519521
shared += page_count(p) - 1;
522+
pgdat_resize_unlock(NODE_DATA(i), &flags);
520523
}
521524
}
522525
#endif

arch/ppc64/mm/init.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ void show_mem(void)
104104
show_free_areas();
105105
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
106106
for_each_pgdat(pgdat) {
107+
unsigned long flags;
108+
pgdat_resize_lock(pgdat, &flags);
107109
for (i = 0; i < pgdat->node_spanned_pages; i++) {
108110
page = pgdat_page_nr(pgdat, i);
109111
total++;
@@ -114,6 +116,7 @@ void show_mem(void)
114116
else if (page_count(page))
115117
shared += page_count(page) - 1;
116118
}
119+
pgdat_resize_unlock(pgdat, &flags);
117120
}
118121
printk("%ld pages of RAM\n", total);
119122
printk("%ld reserved pages\n", reserved);
@@ -647,11 +650,14 @@ void __init mem_init(void)
647650
#endif
648651

649652
for_each_pgdat(pgdat) {
653+
unsigned long flags;
654+
pgdat_resize_lock(pgdat, &flags);
650655
for (i = 0; i < pgdat->node_spanned_pages; i++) {
651656
page = pgdat_page_nr(pgdat, i);
652657
if (PageReserved(page))
653658
reservedpages++;
654659
}
660+
pgdat_resize_unlock(pgdat, &flags);
655661
}
656662

657663
codesize = (unsigned long)&_etext - (unsigned long)&_stext;

include/linux/memory_hotplug.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef __LINUX_MEMORY_HOTPLUG_H
2+
#define __LINUX_MEMORY_HOTPLUG_H
3+
4+
#include <linux/mmzone.h>
5+
#include <linux/spinlock.h>
6+
7+
#ifdef CONFIG_MEMORY_HOTPLUG
8+
/*
9+
* pgdat resizing functions
10+
*/
11+
static inline
12+
void pgdat_resize_lock(struct pglist_data *pgdat, unsigned long *flags)
13+
{
14+
spin_lock_irqsave(&pgdat->node_size_lock, *flags);
15+
}
16+
static inline
17+
void pgdat_resize_unlock(struct pglist_data *pgdat, unsigned long *flags)
18+
{
19+
spin_lock_irqrestore(&pgdat->node_size_lock, *flags);
20+
}
21+
static inline
22+
void pgdat_resize_init(struct pglist_data *pgdat)
23+
{
24+
spin_lock_init(&pgdat->node_size_lock);
25+
}
26+
#else /* ! CONFIG_MEMORY_HOTPLUG */
27+
/*
28+
* Stub functions for when hotplug is off
29+
*/
30+
static inline void pgdat_resize_lock(struct pglist_data *p, unsigned long *f) {}
31+
static inline void pgdat_resize_unlock(struct pglist_data *p, unsigned long *f) {}
32+
static inline void pgdat_resize_init(struct pglist_data *pgdat) {}
33+
#endif
34+
#endif /* __LINUX_MEMORY_HOTPLUG_H */

include/linux/mmzone.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,16 @@ typedef struct pglist_data {
273273
struct page *node_mem_map;
274274
#endif
275275
struct bootmem_data *bdata;
276+
#ifdef CONFIG_MEMORY_HOTPLUG
277+
/*
278+
* Must be held any time you expect node_start_pfn, node_present_pages
279+
* or node_spanned_pages stay constant. Holding this will also
280+
* guarantee that any pfn_valid() stays that way.
281+
*
282+
* Nests above zone->lock and zone->size_seqlock.
283+
*/
284+
spinlock_t node_size_lock;
285+
#endif
276286
unsigned long node_start_pfn;
277287
unsigned long node_present_pages; /* total number of physical pages */
278288
unsigned long node_spanned_pages; /* total size of physical page
@@ -293,6 +303,8 @@ typedef struct pglist_data {
293303
#endif
294304
#define nid_page_nr(nid, pagenr) pgdat_page_nr(NODE_DATA(nid),(pagenr))
295305

306+
#include <linux/memory_hotplug.h>
307+
296308
extern struct pglist_data *pgdat_list;
297309

298310
void __get_zone_counts(unsigned long *active, unsigned long *inactive,

mm/page_alloc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,7 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
19581958
int nid = pgdat->node_id;
19591959
unsigned long zone_start_pfn = pgdat->node_start_pfn;
19601960

1961+
pgdat_resize_init(pgdat);
19611962
pgdat->nr_zones = 0;
19621963
init_waitqueue_head(&pgdat->kswapd_wait);
19631964
pgdat->kswapd_max_order = 0;

0 commit comments

Comments
 (0)