diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-23 12:27:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-23 12:27:54 -0500 |
commit | 4f57d865f1d863346ac50db9c25859e73a86499c (patch) | |
tree | ac3cf5abdc3ce4b5c051f03c682f8b0668d66caf | |
parent | 46c5b83bcc5ab4db34716954fc64645eba7038ca (diff) | |
parent | c25a785d6647984505fa165b5cd84cfc9a95970b (diff) |
Merge branch 'akpm'
Quoth Andrew:
"Random fixes. And a simple new LED driver which I'm trying to sneak
in while you're not looking."
Sneaking successful.
* akpm:
score: fix off-by-one index into syscall table
mm: fix rss count leakage during migration
SHM_UNLOCK: fix Unevictable pages stranded after swap
SHM_UNLOCK: fix long unpreemptible section
kdump: define KEXEC_NOTE_BYTES arch specific for s390x
mm/hugetlb.c: undo change to page mapcount in fault handler
mm: memcg: update the correct soft limit tree during migration
proc: clear_refs: do not clear reserved pages
drivers/video/backlight/l4f00242t03.c: return proper error in l4f00242t03_probe if regulator_get() fails
drivers/video/backlight/adp88x0_bl.c: fix bit testing logic
kprobes: initialize before using a hlist
ipc/mqueue: simplify reading msgqueue limit
leds: add led driver for Bachmann's ot200
mm: __count_immobile_pages(): make sure the node is online
mm: fix NULL ptr dereference in __count_immobile_pages
mm: fix warnings regarding enum migrate_mode
-rw-r--r-- | arch/s390/include/asm/kexec.h | 18 | ||||
-rw-r--r-- | arch/score/kernel/entry.S | 2 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 7 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-ot200.c | 171 | ||||
-rw-r--r-- | drivers/video/backlight/adp8860_bl.c | 2 | ||||
-rw-r--r-- | drivers/video/backlight/adp8870_bl.c | 2 | ||||
-rw-r--r-- | drivers/video/backlight/l4f00242t03.c | 2 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | include/linux/kexec.h | 2 | ||||
-rw-r--r-- | include/linux/migrate.h | 14 | ||||
-rw-r--r-- | include/linux/migrate_mode.h | 16 | ||||
-rw-r--r-- | include/linux/shmem_fs.h | 1 | ||||
-rw-r--r-- | include/linux/swap.h | 2 | ||||
-rw-r--r-- | ipc/mqueue.c | 3 | ||||
-rw-r--r-- | ipc/shm.c | 37 | ||||
-rw-r--r-- | kernel/kprobes.c | 2 | ||||
-rw-r--r-- | mm/hugetlb.c | 9 | ||||
-rw-r--r-- | mm/memcontrol.c | 2 | ||||
-rw-r--r-- | mm/memory.c | 37 | ||||
-rw-r--r-- | mm/page_alloc.c | 20 | ||||
-rw-r--r-- | mm/shmem.c | 53 | ||||
-rw-r--r-- | mm/vmscan.c | 124 |
24 files changed, 388 insertions, 144 deletions
diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index cf4e47b0948c..3f30dac804ea 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h | |||
@@ -42,6 +42,24 @@ | |||
42 | /* The native architecture */ | 42 | /* The native architecture */ |
43 | #define KEXEC_ARCH KEXEC_ARCH_S390 | 43 | #define KEXEC_ARCH KEXEC_ARCH_S390 |
44 | 44 | ||
45 | /* | ||
46 | * Size for s390x ELF notes per CPU | ||
47 | * | ||
48 | * Seven notes plus zero note at the end: prstatus, fpregset, timer, | ||
49 | * tod_cmp, tod_reg, control regs, and prefix | ||
50 | */ | ||
51 | #define KEXEC_NOTE_BYTES \ | ||
52 | (ALIGN(sizeof(struct elf_note), 4) * 8 + \ | ||
53 | ALIGN(sizeof("CORE"), 4) * 7 + \ | ||
54 | ALIGN(sizeof(struct elf_prstatus), 4) + \ | ||
55 | ALIGN(sizeof(elf_fpregset_t), 4) + \ | ||
56 | ALIGN(sizeof(u64), 4) + \ | ||
57 | ALIGN(sizeof(u64), 4) + \ | ||
58 | ALIGN(sizeof(u32), 4) + \ | ||
59 | ALIGN(sizeof(u64) * 16, 4) + \ | ||
60 | ALIGN(sizeof(u32), 4) \ | ||
61 | ) | ||
62 | |||
45 | /* Provide a dummy definition to avoid build failures. */ | 63 | /* Provide a dummy definition to avoid build failures. */ |
46 | static inline void crash_setup_regs(struct pt_regs *newregs, | 64 | static inline void crash_setup_regs(struct pt_regs *newregs, |
47 | struct pt_regs *oldregs) { } | 65 | struct pt_regs *oldregs) { } |
diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S index 577abba3fac6..83bb96079c43 100644 --- a/arch/score/kernel/entry.S +++ b/arch/score/kernel/entry.S | |||
@@ -408,7 +408,7 @@ ENTRY(handle_sys) | |||
408 | sw r9, [r0, PT_EPC] | 408 | sw r9, [r0, PT_EPC] |
409 | 409 | ||
410 | cmpi.c r27, __NR_syscalls # check syscall number | 410 | cmpi.c r27, __NR_syscalls # check syscall number |
411 | bgtu illegal_syscall | 411 | bgeu illegal_syscall |
412 | 412 | ||
413 | slli r8, r27, 2 # get syscall routine | 413 | slli r8, r27, 2 # get syscall routine |
414 | la r11, sys_call_table | 414 | la r11, sys_call_table |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c957c344233f..9ca28fced2b9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -403,6 +403,13 @@ config LEDS_MAX8997 | |||
403 | This option enables support for on-chip LED drivers on | 403 | This option enables support for on-chip LED drivers on |
404 | MAXIM MAX8997 PMIC. | 404 | MAXIM MAX8997 PMIC. |
405 | 405 | ||
406 | config LEDS_OT200 | ||
407 | tristate "LED support for the Bachmann OT200" | ||
408 | depends on LEDS_CLASS && HAS_IOMEM | ||
409 | help | ||
410 | This option enables support for the LEDs on the Bachmann OT200. | ||
411 | Say Y to enable LEDs on the Bachmann OT200. | ||
412 | |||
406 | config LEDS_TRIGGERS | 413 | config LEDS_TRIGGERS |
407 | bool "LED Trigger support" | 414 | bool "LED Trigger support" |
408 | depends on LEDS_CLASS | 415 | depends on LEDS_CLASS |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index b8a9723477f0..1fc6875a8b20 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -28,6 +28,7 @@ obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o | |||
28 | obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o | 28 | obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o |
29 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o | 29 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o |
30 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o | 30 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o |
31 | obj-$(CONFIG_LEDS_OT200) += leds-ot200.o | ||
31 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o | 32 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o |
32 | obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o | 33 | obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o |
33 | obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o | 34 | obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o |
diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c new file mode 100644 index 000000000000..c4646825a620 --- /dev/null +++ b/drivers/leds/leds-ot200.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * Bachmann ot200 leds driver. | ||
3 | * | ||
4 | * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> | ||
5 | * Christian Gmeiner <christian.gmeiner@gmail.com> | ||
6 | * | ||
7 | * License: GPL as published by the FSF. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/leds.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/module.h> | ||
17 | |||
18 | |||
19 | struct ot200_led { | ||
20 | struct led_classdev cdev; | ||
21 | const char *name; | ||
22 | unsigned long port; | ||
23 | u8 mask; | ||
24 | }; | ||
25 | |||
26 | /* | ||
27 | * The device has three leds on the back panel (led_err, led_init and led_run) | ||
28 | * and can handle up to seven leds on the front panel. | ||
29 | */ | ||
30 | |||
31 | static struct ot200_led leds[] = { | ||
32 | { | ||
33 | .name = "led_run", | ||
34 | .port = 0x5a, | ||
35 | .mask = BIT(0), | ||
36 | }, | ||
37 | { | ||
38 | .name = "led_init", | ||
39 | .port = 0x5a, | ||
40 | .mask = BIT(1), | ||
41 | }, | ||
42 | { | ||
43 | .name = "led_err", | ||
44 | .port = 0x5a, | ||
45 | .mask = BIT(2), | ||
46 | }, | ||
47 | { | ||
48 | .name = "led_1", | ||
49 | .port = 0x49, | ||
50 | .mask = BIT(7), | ||
51 | }, | ||
52 | { | ||
53 | .name = "led_2", | ||
54 | .port = 0x49, | ||
55 | .mask = BIT(6), | ||
56 | }, | ||
57 | { | ||
58 | .name = "led_3", | ||
59 | .port = 0x49, | ||
60 | .mask = BIT(5), | ||
61 | }, | ||
62 | { | ||
63 | .name = "led_4", | ||
64 | .port = 0x49, | ||
65 | .mask = BIT(4), | ||
66 | }, | ||
67 | { | ||
68 | .name = "led_5", | ||
69 | .port = 0x49, | ||
70 | .mask = BIT(3), | ||
71 | }, | ||
72 | { | ||
73 | .name = "led_6", | ||
74 | .port = 0x49, | ||
75 | .mask = BIT(2), | ||
76 | }, | ||
77 | { | ||
78 | .name = "led_7", | ||
79 | .port = 0x49, | ||
80 | .mask = BIT(1), | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | static DEFINE_SPINLOCK(value_lock); | ||
85 | |||
86 | /* | ||
87 | * we need to store the current led states, as it is not | ||
88 | * possible to read the current led state via inb(). | ||
89 | */ | ||
90 | static u8 leds_back; | ||
91 | static u8 leds_front; | ||
92 | |||
93 | static void ot200_led_brightness_set(struct led_classdev *led_cdev, | ||
94 | enum led_brightness value) | ||
95 | { | ||
96 | struct ot200_led *led = container_of(led_cdev, struct ot200_led, cdev); | ||
97 | u8 *val; | ||
98 | unsigned long flags; | ||
99 | |||
100 | spin_lock_irqsave(&value_lock, flags); | ||
101 | |||
102 | if (led->port == 0x49) | ||
103 | val = &leds_front; | ||
104 | else if (led->port == 0x5a) | ||
105 | val = &leds_back; | ||
106 | else | ||
107 | BUG(); | ||
108 | |||
109 | if (value == LED_OFF) | ||
110 | *val &= ~led->mask; | ||
111 | else | ||
112 | *val |= led->mask; | ||
113 | |||
114 | outb(*val, led->port); | ||
115 | spin_unlock_irqrestore(&value_lock, flags); | ||
116 | } | ||
117 | |||
118 | static int __devinit ot200_led_probe(struct platform_device *pdev) | ||
119 | { | ||
120 | int i; | ||
121 | int ret; | ||
122 | |||
123 | for (i = 0; i < ARRAY_SIZE(leds); i++) { | ||
124 | |||
125 | leds[i].cdev.name = leds[i].name; | ||
126 | leds[i].cdev.brightness_set = ot200_led_brightness_set; | ||
127 | |||
128 | ret = led_classdev_register(&pdev->dev, &leds[i].cdev); | ||
129 | if (ret < 0) | ||
130 | goto err; | ||
131 | } | ||
132 | |||
133 | leds_front = 0; /* turn off all front leds */ | ||
134 | leds_back = BIT(1); /* turn on init led */ | ||
135 | outb(leds_front, 0x49); | ||
136 | outb(leds_back, 0x5a); | ||
137 | |||
138 | return 0; | ||
139 | |||
140 | err: | ||
141 | for (i = i - 1; i >= 0; i--) | ||
142 | led_classdev_unregister(&leds[i].cdev); | ||
143 | |||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static int __devexit ot200_led_remove(struct platform_device *pdev) | ||
148 | { | ||
149 | int i; | ||
150 | |||
151 | for (i = 0; i < ARRAY_SIZE(leds); i++) | ||
152 | led_classdev_unregister(&leds[i].cdev); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct platform_driver ot200_led_driver = { | ||
158 | .probe = ot200_led_probe, | ||
159 | .remove = __devexit_p(ot200_led_remove), | ||
160 | .driver = { | ||
161 | .name = "leds-ot200", | ||
162 | .owner = THIS_MODULE, | ||
163 | }, | ||
164 | }; | ||
165 | |||
166 | module_platform_driver(ot200_led_driver); | ||
167 | |||
168 | MODULE_AUTHOR("Sebastian A. Siewior <bigeasy@linutronix.de>"); | ||
169 | MODULE_DESCRIPTION("ot200 LED driver"); | ||
170 | MODULE_LICENSE("GPL"); | ||
171 | MODULE_ALIAS("platform:leds-ot200"); | ||
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 66bc74d9ce2a..378276c9d3cf 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c | |||
@@ -146,7 +146,7 @@ static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask | |||
146 | 146 | ||
147 | ret = adp8860_read(client, reg, ®_val); | 147 | ret = adp8860_read(client, reg, ®_val); |
148 | 148 | ||
149 | if (!ret && ((reg_val & bit_mask) == 0)) { | 149 | if (!ret && ((reg_val & bit_mask) != bit_mask)) { |
150 | reg_val |= bit_mask; | 150 | reg_val |= bit_mask; |
151 | ret = adp8860_write(client, reg, reg_val); | 151 | ret = adp8860_write(client, reg, reg_val); |
152 | } | 152 | } |
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 6c68a6899e87..6735059376d6 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c | |||
@@ -160,7 +160,7 @@ static int adp8870_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask | |||
160 | 160 | ||
161 | ret = adp8870_read(client, reg, ®_val); | 161 | ret = adp8870_read(client, reg, ®_val); |
162 | 162 | ||
163 | if (!ret && ((reg_val & bit_mask) == 0)) { | 163 | if (!ret && ((reg_val & bit_mask) != bit_mask)) { |
164 | reg_val |= bit_mask; | 164 | reg_val |= bit_mask; |
165 | ret = adp8870_write(client, reg, reg_val); | 165 | ret = adp8870_write(client, reg, reg_val); |
166 | } | 166 | } |
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 4f5d1c4cb6ab..27d1d7a29c77 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c | |||
@@ -190,6 +190,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) | |||
190 | 190 | ||
191 | priv->io_reg = regulator_get(&spi->dev, "vdd"); | 191 | priv->io_reg = regulator_get(&spi->dev, "vdd"); |
192 | if (IS_ERR(priv->io_reg)) { | 192 | if (IS_ERR(priv->io_reg)) { |
193 | ret = PTR_ERR(priv->io_reg); | ||
193 | dev_err(&spi->dev, "%s: Unable to get the IO regulator\n", | 194 | dev_err(&spi->dev, "%s: Unable to get the IO regulator\n", |
194 | __func__); | 195 | __func__); |
195 | goto err3; | 196 | goto err3; |
@@ -197,6 +198,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) | |||
197 | 198 | ||
198 | priv->core_reg = regulator_get(&spi->dev, "vcore"); | 199 | priv->core_reg = regulator_get(&spi->dev, "vcore"); |
199 | if (IS_ERR(priv->core_reg)) { | 200 | if (IS_ERR(priv->core_reg)) { |
201 | ret = PTR_ERR(priv->core_reg); | ||
200 | dev_err(&spi->dev, "%s: Unable to get the core regulator\n", | 202 | dev_err(&spi->dev, "%s: Unable to get the core regulator\n", |
201 | __func__); | 203 | __func__); |
202 | goto err4; | 204 | goto err4; |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index e418c5abdb0e..7dcd2a250495 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -518,6 +518,9 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, | |||
518 | if (!page) | 518 | if (!page) |
519 | continue; | 519 | continue; |
520 | 520 | ||
521 | if (PageReserved(page)) | ||
522 | continue; | ||
523 | |||
521 | /* Clear accessed and referenced bits. */ | 524 | /* Clear accessed and referenced bits. */ |
522 | ptep_test_and_clear_young(vma, addr, pte); | 525 | ptep_test_and_clear_young(vma, addr, pte); |
523 | ClearPageReferenced(page); | 526 | ClearPageReferenced(page); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 0244082d42c5..4b3a41fe22bf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/ioctl.h> | 10 | #include <linux/ioctl.h> |
11 | #include <linux/blk_types.h> | 11 | #include <linux/blk_types.h> |
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/migrate_mode.h> | ||
13 | 14 | ||
14 | /* | 15 | /* |
15 | * It's silly to have NR_OPEN bigger than NR_FILE, but you can change | 16 | * It's silly to have NR_OPEN bigger than NR_FILE, but you can change |
@@ -526,7 +527,6 @@ enum positive_aop_returns { | |||
526 | struct page; | 527 | struct page; |
527 | struct address_space; | 528 | struct address_space; |
528 | struct writeback_control; | 529 | struct writeback_control; |
529 | enum migrate_mode; | ||
530 | 530 | ||
531 | struct iov_iter { | 531 | struct iov_iter { |
532 | const struct iovec *iov; | 532 | const struct iovec *iov; |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 2fa0901219d4..0d7d6a1b172f 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
@@ -50,9 +50,11 @@ | |||
50 | * note header. For kdump, the code in vmcore.c runs in the context | 50 | * note header. For kdump, the code in vmcore.c runs in the context |
51 | * of the second kernel to combine them into one note. | 51 | * of the second kernel to combine them into one note. |
52 | */ | 52 | */ |
53 | #ifndef KEXEC_NOTE_BYTES | ||
53 | #define KEXEC_NOTE_BYTES ( (KEXEC_NOTE_HEAD_BYTES * 2) + \ | 54 | #define KEXEC_NOTE_BYTES ( (KEXEC_NOTE_HEAD_BYTES * 2) + \ |
54 | KEXEC_CORE_NOTE_NAME_BYTES + \ | 55 | KEXEC_CORE_NOTE_NAME_BYTES + \ |
55 | KEXEC_CORE_NOTE_DESC_BYTES ) | 56 | KEXEC_CORE_NOTE_DESC_BYTES ) |
57 | #endif | ||
56 | 58 | ||
57 | /* | 59 | /* |
58 | * This structure is used to hold the arguments that are used when loading | 60 | * This structure is used to hold the arguments that are used when loading |
diff --git a/include/linux/migrate.h b/include/linux/migrate.h index eaf867412f7a..05ed2828a553 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h | |||
@@ -3,22 +3,10 @@ | |||
3 | 3 | ||
4 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
5 | #include <linux/mempolicy.h> | 5 | #include <linux/mempolicy.h> |
6 | #include <linux/migrate_mode.h> | ||
6 | 7 | ||
7 | typedef struct page *new_page_t(struct page *, unsigned long private, int **); | 8 | typedef struct page *new_page_t(struct page *, unsigned long private, int **); |
8 | 9 | ||
9 | /* | ||
10 | * MIGRATE_ASYNC means never block | ||
11 | * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking | ||
12 | * on most operations but not ->writepage as the potential stall time | ||
13 | * is too significant | ||
14 | * MIGRATE_SYNC will block when migrating pages | ||
15 | */ | ||
16 | enum migrate_mode { | ||
17 | MIGRATE_ASYNC, | ||
18 | MIGRATE_SYNC_LIGHT, | ||
19 | MIGRATE_SYNC, | ||
20 | }; | ||
21 | |||
22 | #ifdef CONFIG_MIGRATION | 10 | #ifdef CONFIG_MIGRATION |
23 | #define PAGE_MIGRATION 1 | 11 | #define PAGE_MIGRATION 1 |
24 | 12 | ||
diff --git a/include/linux/migrate_mode.h b/include/linux/migrate_mode.h new file mode 100644 index 000000000000..ebf3d89a3919 --- /dev/null +++ b/include/linux/migrate_mode.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef MIGRATE_MODE_H_INCLUDED | ||
2 | #define MIGRATE_MODE_H_INCLUDED | ||
3 | /* | ||
4 | * MIGRATE_ASYNC means never block | ||
5 | * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking | ||
6 | * on most operations but not ->writepage as the potential stall time | ||
7 | * is too significant | ||
8 | * MIGRATE_SYNC will block when migrating pages | ||
9 | */ | ||
10 | enum migrate_mode { | ||
11 | MIGRATE_ASYNC, | ||
12 | MIGRATE_SYNC_LIGHT, | ||
13 | MIGRATE_SYNC, | ||
14 | }; | ||
15 | |||
16 | #endif /* MIGRATE_MODE_H_INCLUDED */ | ||
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index e4c711c6f321..79ab2555b3b0 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h | |||
@@ -48,6 +48,7 @@ extern struct file *shmem_file_setup(const char *name, | |||
48 | loff_t size, unsigned long flags); | 48 | loff_t size, unsigned long flags); |
49 | extern int shmem_zero_setup(struct vm_area_struct *); | 49 | extern int shmem_zero_setup(struct vm_area_struct *); |
50 | extern int shmem_lock(struct file *file, int lock, struct user_struct *user); | 50 | extern int shmem_lock(struct file *file, int lock, struct user_struct *user); |
51 | extern void shmem_unlock_mapping(struct address_space *mapping); | ||
51 | extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, | 52 | extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, |
52 | pgoff_t index, gfp_t gfp_mask); | 53 | pgoff_t index, gfp_t gfp_mask); |
53 | extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end); | 54 | extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end); |
diff --git a/include/linux/swap.h b/include/linux/swap.h index 06061a7f8e69..3e60228e7299 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
@@ -273,7 +273,7 @@ static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order) | |||
273 | #endif | 273 | #endif |
274 | 274 | ||
275 | extern int page_evictable(struct page *page, struct vm_area_struct *vma); | 275 | extern int page_evictable(struct page *page, struct vm_area_struct *vma); |
276 | extern void scan_mapping_unevictable_pages(struct address_space *); | 276 | extern void check_move_unevictable_pages(struct page **, int nr_pages); |
277 | 277 | ||
278 | extern unsigned long scan_unevictable_pages; | 278 | extern unsigned long scan_unevictable_pages; |
279 | extern int scan_unevictable_handler(struct ctl_table *, int, | 279 | extern int scan_unevictable_handler(struct ctl_table *, int, |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 9b7c8ab7d75c..86ee272de210 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
@@ -128,7 +128,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, | |||
128 | 128 | ||
129 | if (S_ISREG(mode)) { | 129 | if (S_ISREG(mode)) { |
130 | struct mqueue_inode_info *info; | 130 | struct mqueue_inode_info *info; |
131 | struct task_struct *p = current; | ||
132 | unsigned long mq_bytes, mq_msg_tblsz; | 131 | unsigned long mq_bytes, mq_msg_tblsz; |
133 | 132 | ||
134 | inode->i_fop = &mqueue_file_operations; | 133 | inode->i_fop = &mqueue_file_operations; |
@@ -159,7 +158,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, | |||
159 | 158 | ||
160 | spin_lock(&mq_lock); | 159 | spin_lock(&mq_lock); |
161 | if (u->mq_bytes + mq_bytes < u->mq_bytes || | 160 | if (u->mq_bytes + mq_bytes < u->mq_bytes || |
162 | u->mq_bytes + mq_bytes > task_rlimit(p, RLIMIT_MSGQUEUE)) { | 161 | u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) { |
163 | spin_unlock(&mq_lock); | 162 | spin_unlock(&mq_lock); |
164 | /* mqueue_evict_inode() releases info->messages */ | 163 | /* mqueue_evict_inode() releases info->messages */ |
165 | ret = -EMFILE; | 164 | ret = -EMFILE; |
@@ -870,9 +870,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
870 | case SHM_LOCK: | 870 | case SHM_LOCK: |
871 | case SHM_UNLOCK: | 871 | case SHM_UNLOCK: |
872 | { | 872 | { |
873 | struct file *uninitialized_var(shm_file); | 873 | struct file *shm_file; |
874 | |||
875 | lru_add_drain_all(); /* drain pagevecs to lru lists */ | ||
876 | 874 | ||
877 | shp = shm_lock_check(ns, shmid); | 875 | shp = shm_lock_check(ns, shmid); |
878 | if (IS_ERR(shp)) { | 876 | if (IS_ERR(shp)) { |
@@ -895,22 +893,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
895 | err = security_shm_shmctl(shp, cmd); | 893 | err = security_shm_shmctl(shp, cmd); |
896 | if (err) | 894 | if (err) |
897 | goto out_unlock; | 895 | goto out_unlock; |
898 | 896 | ||
899 | if(cmd==SHM_LOCK) { | 897 | shm_file = shp->shm_file; |
898 | if (is_file_hugepages(shm_file)) | ||
899 | goto out_unlock; | ||
900 | |||
901 | if (cmd == SHM_LOCK) { | ||
900 | struct user_struct *user = current_user(); | 902 | struct user_struct *user = current_user(); |
901 | if (!is_file_hugepages(shp->shm_file)) { | 903 | err = shmem_lock(shm_file, 1, user); |
902 | err = shmem_lock(shp->shm_file, 1, user); | 904 | if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) { |
903 | if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){ | 905 | shp->shm_perm.mode |= SHM_LOCKED; |
904 | shp->shm_perm.mode |= SHM_LOCKED; | 906 | shp->mlock_user = user; |
905 | shp->mlock_user = user; | ||
906 | } | ||
907 | } | 907 | } |
908 | } else if (!is_file_hugepages(shp->shm_file)) { | 908 | goto out_unlock; |
909 | shmem_lock(shp->shm_file, 0, shp->mlock_user); | ||
910 | shp->shm_perm.mode &= ~SHM_LOCKED; | ||
911 | shp->mlock_user = NULL; | ||
912 | } | 909 | } |
910 | |||
911 | /* SHM_UNLOCK */ | ||
912 | if (!(shp->shm_perm.mode & SHM_LOCKED)) | ||
913 | goto out_unlock; | ||
914 | shmem_lock(shm_file, 0, shp->mlock_user); | ||
915 | shp->shm_perm.mode &= ~SHM_LOCKED; | ||
916 | shp->mlock_user = NULL; | ||
917 | get_file(shm_file); | ||
913 | shm_unlock(shp); | 918 | shm_unlock(shp); |
919 | shmem_unlock_mapping(shm_file->f_mapping); | ||
920 | fput(shm_file); | ||
914 | goto out; | 921 | goto out; |
915 | } | 922 | } |
916 | case IPC_RMID: | 923 | case IPC_RMID: |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 95dd7212e610..29f5b65bee29 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -1077,6 +1077,7 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) | |||
1077 | /* Early boot. kretprobe_table_locks not yet initialized. */ | 1077 | /* Early boot. kretprobe_table_locks not yet initialized. */ |
1078 | return; | 1078 | return; |
1079 | 1079 | ||
1080 | INIT_HLIST_HEAD(&empty_rp); | ||
1080 | hash = hash_ptr(tk, KPROBE_HASH_BITS); | 1081 | hash = hash_ptr(tk, KPROBE_HASH_BITS); |
1081 | head = &kretprobe_inst_table[hash]; | 1082 | head = &kretprobe_inst_table[hash]; |
1082 | kretprobe_table_lock(hash, &flags); | 1083 | kretprobe_table_lock(hash, &flags); |
@@ -1085,7 +1086,6 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) | |||
1085 | recycle_rp_inst(ri, &empty_rp); | 1086 | recycle_rp_inst(ri, &empty_rp); |
1086 | } | 1087 | } |
1087 | kretprobe_table_unlock(hash, &flags); | 1088 | kretprobe_table_unlock(hash, &flags); |
1088 | INIT_HLIST_HEAD(&empty_rp); | ||
1089 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | 1089 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { |
1090 | hlist_del(&ri->hlist); | 1090 | hlist_del(&ri->hlist); |
1091 | kfree(ri); | 1091 | kfree(ri); |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ea8c3a4cd2ae..5f34bd8dda34 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -2508,6 +2508,7 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2508 | { | 2508 | { |
2509 | struct hstate *h = hstate_vma(vma); | 2509 | struct hstate *h = hstate_vma(vma); |
2510 | int ret = VM_FAULT_SIGBUS; | 2510 | int ret = VM_FAULT_SIGBUS; |
2511 | int anon_rmap = 0; | ||
2511 | pgoff_t idx; | 2512 | pgoff_t idx; |
2512 | unsigned long size; | 2513 | unsigned long size; |
2513 | struct page *page; | 2514 | struct page *page; |
@@ -2562,14 +2563,13 @@ retry: | |||
2562 | spin_lock(&inode->i_lock); | 2563 | spin_lock(&inode->i_lock); |
2563 | inode->i_blocks += blocks_per_huge_page(h); | 2564 | inode->i_blocks += blocks_per_huge_page(h); |
2564 | spin_unlock(&inode->i_lock); | 2565 | spin_unlock(&inode->i_lock); |
2565 | page_dup_rmap(page); | ||
2566 | } else { | 2566 | } else { |
2567 | lock_page(page); | 2567 | lock_page(page); |
2568 | if (unlikely(anon_vma_prepare(vma))) { | 2568 | if (unlikely(anon_vma_prepare(vma))) { |
2569 | ret = VM_FAULT_OOM; | 2569 | ret = VM_FAULT_OOM; |
2570 | goto backout_unlocked; | 2570 | goto backout_unlocked; |
2571 | } | 2571 | } |
2572 | hugepage_add_new_anon_rmap(page, vma, address); | 2572 | anon_rmap = 1; |
2573 | } | 2573 | } |
2574 | } else { | 2574 | } else { |
2575 | /* | 2575 | /* |
@@ -2582,7 +2582,6 @@ retry: | |||
2582 | VM_FAULT_SET_HINDEX(h - hstates); | 2582 | VM_FAULT_SET_HINDEX(h - hstates); |
2583 | goto backout_unlocked; | 2583 | goto backout_unlocked; |
2584 | } | 2584 | } |
2585 | page_dup_rmap(page); | ||
2586 | } | 2585 | } |
2587 | 2586 | ||
2588 | /* | 2587 | /* |
@@ -2606,6 +2605,10 @@ retry: | |||
2606 | if (!huge_pte_none(huge_ptep_get(ptep))) | 2605 | if (!huge_pte_none(huge_ptep_get(ptep))) |
2607 | goto backout; | 2606 | goto backout; |
2608 | 2607 | ||
2608 | if (anon_rmap) | ||
2609 | hugepage_add_new_anon_rmap(page, vma, address); | ||
2610 | else | ||
2611 | page_dup_rmap(page); | ||
2609 | new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE) | 2612 | new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE) |
2610 | && (vma->vm_flags & VM_SHARED))); | 2613 | && (vma->vm_flags & VM_SHARED))); |
2611 | set_huge_pte_at(mm, address, ptep, new_pte); | 2614 | set_huge_pte_at(mm, address, ptep, new_pte); |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3dbff4dcde35..4baddbae94cc 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -3247,7 +3247,7 @@ int mem_cgroup_prepare_migration(struct page *page, | |||
3247 | ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; | 3247 | ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; |
3248 | else | 3248 | else |
3249 | ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; | 3249 | ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; |
3250 | __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype); | 3250 | __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype); |
3251 | return ret; | 3251 | return ret; |
3252 | } | 3252 | } |
3253 | 3253 | ||
diff --git a/mm/memory.c b/mm/memory.c index 5e30583c2605..fa2f04e0337c 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -878,15 +878,24 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
878 | } | 878 | } |
879 | if (likely(!non_swap_entry(entry))) | 879 | if (likely(!non_swap_entry(entry))) |
880 | rss[MM_SWAPENTS]++; | 880 | rss[MM_SWAPENTS]++; |
881 | else if (is_write_migration_entry(entry) && | 881 | else if (is_migration_entry(entry)) { |
882 | is_cow_mapping(vm_flags)) { | 882 | page = migration_entry_to_page(entry); |
883 | /* | 883 | |
884 | * COW mappings require pages in both parent | 884 | if (PageAnon(page)) |
885 | * and child to be set to read. | 885 | rss[MM_ANONPAGES]++; |
886 | */ | 886 | else |
887 | make_migration_entry_read(&entry); | 887 | rss[MM_FILEPAGES]++; |
888 | pte = swp_entry_to_pte(entry); | 888 | |
889 | set_pte_at(src_mm, addr, src_pte, pte); | 889 | if (is_write_migration_entry(entry) && |
890 | is_cow_mapping(vm_flags)) { | ||
891 | /* | ||
892 | * COW mappings require pages in both | ||
893 | * parent and child to be set to read. | ||
894 | */ | ||
895 | make_migration_entry_read(&entry); | ||
896 | pte = swp_entry_to_pte(entry); | ||
897 | set_pte_at(src_mm, addr, src_pte, pte); | ||
898 | } | ||
890 | } | 899 | } |
891 | } | 900 | } |
892 | goto out_set_pte; | 901 | goto out_set_pte; |
@@ -1191,6 +1200,16 @@ again: | |||
1191 | 1200 | ||
1192 | if (!non_swap_entry(entry)) | 1201 | if (!non_swap_entry(entry)) |
1193 | rss[MM_SWAPENTS]--; | 1202 | rss[MM_SWAPENTS]--; |
1203 | else if (is_migration_entry(entry)) { | ||
1204 | struct page *page; | ||
1205 | |||
1206 | page = migration_entry_to_page(entry); | ||
1207 | |||
1208 | if (PageAnon(page)) | ||
1209 | rss[MM_ANONPAGES]--; | ||
1210 | else | ||
1211 | rss[MM_FILEPAGES]--; | ||
1212 | } | ||
1194 | if (unlikely(!free_swap_and_cache(entry))) | 1213 | if (unlikely(!free_swap_and_cache(entry))) |
1195 | print_bad_pte(vma, addr, ptent, NULL); | 1214 | print_bad_pte(vma, addr, ptent, NULL); |
1196 | } | 1215 | } |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0027d8f4a1bb..d2186ecb36f7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -5413,7 +5413,25 @@ __count_immobile_pages(struct zone *zone, struct page *page, int count) | |||
5413 | 5413 | ||
5414 | bool is_pageblock_removable_nolock(struct page *page) | 5414 | bool is_pageblock_removable_nolock(struct page *page) |
5415 | { | 5415 | { |
5416 | struct zone *zone = page_zone(page); | 5416 | struct zone *zone; |
5417 | unsigned long pfn; | ||
5418 | |||
5419 | /* | ||
5420 | * We have to be careful here because we are iterating over memory | ||
5421 | * sections which are not zone aware so we might end up outside of | ||
5422 | * the zone but still within the section. | ||
5423 | * We have to take care about the node as well. If the node is offline | ||
5424 | * its NODE_DATA will be NULL - see page_zone. | ||
5425 | */ | ||
5426 | if (!node_online(page_to_nid(page))) | ||
5427 | return false; | ||
5428 | |||
5429 | zone = page_zone(page); | ||
5430 | pfn = page_to_pfn(page); | ||
5431 | if (zone->zone_start_pfn > pfn || | ||
5432 | zone->zone_start_pfn + zone->spanned_pages <= pfn) | ||
5433 | return false; | ||
5434 | |||
5417 | return __count_immobile_pages(zone, page, 0); | 5435 | return __count_immobile_pages(zone, page, 0); |
5418 | } | 5436 | } |
5419 | 5437 | ||
diff --git a/mm/shmem.c b/mm/shmem.c index feead1943d92..269d049294ab 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -379,7 +379,7 @@ static int shmem_free_swap(struct address_space *mapping, | |||
379 | /* | 379 | /* |
380 | * Pagevec may contain swap entries, so shuffle up pages before releasing. | 380 | * Pagevec may contain swap entries, so shuffle up pages before releasing. |
381 | */ | 381 | */ |
382 | static void shmem_pagevec_release(struct pagevec *pvec) | 382 | static void shmem_deswap_pagevec(struct pagevec *pvec) |
383 | { | 383 | { |
384 | int i, j; | 384 | int i, j; |
385 | 385 | ||
@@ -389,7 +389,36 @@ static void shmem_pagevec_release(struct pagevec *pvec) | |||
389 | pvec->pages[j++] = page; | 389 | pvec->pages[j++] = page; |
390 | } | 390 | } |
391 | pvec->nr = j; | 391 | pvec->nr = j; |
392 | pagevec_release(pvec); | 392 | } |
393 | |||
394 | /* | ||
395 | * SysV IPC SHM_UNLOCK restore Unevictable pages to their evictable lists. | ||
396 | */ | ||
397 | void shmem_unlock_mapping(struct address_space *mapping) | ||
398 | { | ||
399 | struct pagevec pvec; | ||
400 | pgoff_t indices[PAGEVEC_SIZE]; | ||
401 | pgoff_t index = 0; | ||
402 | |||
403 | pagevec_init(&pvec, 0); | ||
404 | /* | ||
405 | * Minor point, but we might as well stop if someone else SHM_LOCKs it. | ||
406 | */ | ||
407 | while (!mapping_unevictable(mapping)) { | ||
408 | /* | ||
409 | * Avoid pagevec_lookup(): find_get_pages() returns 0 as if it | ||
410 | * has finished, if it hits a row of PAGEVEC_SIZE swap entries. | ||
411 | */ | ||
412 | pvec.nr = shmem_find_get_pages_and_swap(mapping, index, | ||
413 | PAGEVEC_SIZE, pvec.pages, indices); | ||
414 | if (!pvec.nr) | ||
415 | break; | ||
416 | index = indices[pvec.nr - 1] + 1; | ||
417 | shmem_deswap_pagevec(&pvec); | ||
418 | check_move_unevictable_pages(pvec.pages, pvec.nr); | ||
419 | pagevec_release(&pvec); | ||
420 | cond_resched(); | ||
421 | } | ||
393 | } | 422 | } |
394 | 423 | ||
395 | /* | 424 | /* |
@@ -440,7 +469,8 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) | |||
440 | } | 469 | } |
441 | unlock_page(page); | 470 | unlock_page(page); |
442 | } | 471 | } |
443 | shmem_pagevec_release(&pvec); | 472 | shmem_deswap_pagevec(&pvec); |
473 | pagevec_release(&pvec); | ||
444 | mem_cgroup_uncharge_end(); | 474 | mem_cgroup_uncharge_end(); |
445 | cond_resched(); | 475 | cond_resched(); |
446 | index++; | 476 | index++; |
@@ -470,7 +500,8 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) | |||
470 | continue; | 500 | continue; |
471 | } | 501 | } |
472 | if (index == start && indices[0] > end) { | 502 | if (index == start && indices[0] > end) { |
473 | shmem_pagevec_release(&pvec); | 503 | shmem_deswap_pagevec(&pvec); |
504 | pagevec_release(&pvec); | ||
474 | break; | 505 | break; |
475 | } | 506 | } |
476 | mem_cgroup_uncharge_start(); | 507 | mem_cgroup_uncharge_start(); |
@@ -494,7 +525,8 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) | |||
494 | } | 525 | } |
495 | unlock_page(page); | 526 | unlock_page(page); |
496 | } | 527 | } |
497 | shmem_pagevec_release(&pvec); | 528 | shmem_deswap_pagevec(&pvec); |
529 | pagevec_release(&pvec); | ||
498 | mem_cgroup_uncharge_end(); | 530 | mem_cgroup_uncharge_end(); |
499 | index++; | 531 | index++; |
500 | } | 532 | } |
@@ -1068,13 +1100,6 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) | |||
1068 | user_shm_unlock(inode->i_size, user); | 1100 | user_shm_unlock(inode->i_size, user); |
1069 | info->flags &= ~VM_LOCKED; | 1101 | info->flags &= ~VM_LOCKED; |
1070 | mapping_clear_unevictable(file->f_mapping); | 1102 | mapping_clear_unevictable(file->f_mapping); |
1071 | /* | ||
1072 | * Ensure that a racing putback_lru_page() can see | ||
1073 | * the pages of this mapping are evictable when we | ||
1074 | * skip them due to !PageLRU during the scan. | ||
1075 | */ | ||
1076 | smp_mb__after_clear_bit(); | ||
1077 | scan_mapping_unevictable_pages(file->f_mapping); | ||
1078 | } | 1103 | } |
1079 | retval = 0; | 1104 | retval = 0; |
1080 | 1105 | ||
@@ -2445,6 +2470,10 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) | |||
2445 | return 0; | 2470 | return 0; |
2446 | } | 2471 | } |
2447 | 2472 | ||
2473 | void shmem_unlock_mapping(struct address_space *mapping) | ||
2474 | { | ||
2475 | } | ||
2476 | |||
2448 | void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) | 2477 | void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) |
2449 | { | 2478 | { |
2450 | truncate_inode_pages_range(inode->i_mapping, lstart, lend); | 2479 | truncate_inode_pages_range(inode->i_mapping, lstart, lend); |
diff --git a/mm/vmscan.c b/mm/vmscan.c index 2880396f7953..c52b23552659 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/buffer_head.h> /* for try_to_release_page(), | 26 | #include <linux/buffer_head.h> /* for try_to_release_page(), |
27 | buffer_heads_over_limit */ | 27 | buffer_heads_over_limit */ |
28 | #include <linux/mm_inline.h> | 28 | #include <linux/mm_inline.h> |
29 | #include <linux/pagevec.h> | ||
30 | #include <linux/backing-dev.h> | 29 | #include <linux/backing-dev.h> |
31 | #include <linux/rmap.h> | 30 | #include <linux/rmap.h> |
32 | #include <linux/topology.h> | 31 | #include <linux/topology.h> |
@@ -661,7 +660,7 @@ redo: | |||
661 | * When racing with an mlock or AS_UNEVICTABLE clearing | 660 | * When racing with an mlock or AS_UNEVICTABLE clearing |
662 | * (page is unlocked) make sure that if the other thread | 661 | * (page is unlocked) make sure that if the other thread |
663 | * does not observe our setting of PG_lru and fails | 662 | * does not observe our setting of PG_lru and fails |
664 | * isolation/check_move_unevictable_page, | 663 | * isolation/check_move_unevictable_pages, |
665 | * we see PG_mlocked/AS_UNEVICTABLE cleared below and move | 664 | * we see PG_mlocked/AS_UNEVICTABLE cleared below and move |
666 | * the page back to the evictable list. | 665 | * the page back to the evictable list. |
667 | * | 666 | * |
@@ -3499,100 +3498,61 @@ int page_evictable(struct page *page, struct vm_area_struct *vma) | |||
3499 | return 1; | 3498 | return 1; |
3500 | } | 3499 | } |
3501 | 3500 | ||
3501 | #ifdef CONFIG_SHMEM | ||
3502 | /** | 3502 | /** |
3503 | * check_move_unevictable_page - check page for evictability and move to appropriate zone lru list | 3503 | * check_move_unevictable_pages - check pages for evictability and move to appropriate zone lru list |
3504 | * @page: page to check evictability and move to appropriate lru list | 3504 | * @pages: array of pages to check |
3505 | * @zone: zone page is in | 3505 | * @nr_pages: number of pages to check |
3506 | * | 3506 | * |
3507 | * Checks a page for evictability and moves the page to the appropriate | 3507 | * Checks pages for evictability and moves them to the appropriate lru list. |
3508 | * zone lru list. | ||
3509 | * | 3508 | * |
3510 | * Restrictions: zone->lru_lock must be held, page must be on LRU and must | 3509 | * This function is only used for SysV IPC SHM_UNLOCK. |
3511 | * have PageUnevictable set. | ||
3512 | */ | 3510 | */ |
3513 | static void check_move_unevictable_page(struct page *page, struct zone *zone) | 3511 | void check_move_unevictable_pages(struct page **pages, int nr_pages) |
3514 | { | 3512 | { |
3515 | struct lruvec *lruvec; | 3513 | struct lruvec *lruvec; |
3514 | struct zone *zone = NULL; | ||
3515 | int pgscanned = 0; | ||
3516 | int pgrescued = 0; | ||
3517 | int i; | ||
3516 | 3518 | ||
3517 | VM_BUG_ON(PageActive(page)); | 3519 | for (i = 0; i < nr_pages; i++) { |
3518 | retry: | 3520 | struct page *page = pages[i]; |
3519 | ClearPageUnevictable(page); | 3521 | struct zone *pagezone; |
3520 | if (page_evictable(page, NULL)) { | ||
3521 | enum lru_list l = page_lru_base_type(page); | ||
3522 | |||
3523 | __dec_zone_state(zone, NR_UNEVICTABLE); | ||
3524 | lruvec = mem_cgroup_lru_move_lists(zone, page, | ||
3525 | LRU_UNEVICTABLE, l); | ||
3526 | list_move(&page->lru, &lruvec->lists[l]); | ||
3527 | __inc_zone_state(zone, NR_INACTIVE_ANON + l); | ||
3528 | __count_vm_event(UNEVICTABLE_PGRESCUED); | ||
3529 | } else { | ||
3530 | /* | ||
3531 | * rotate unevictable list | ||
3532 | */ | ||
3533 | SetPageUnevictable(page); | ||
3534 | lruvec = mem_cgroup_lru_move_lists(zone, page, LRU_UNEVICTABLE, | ||
3535 | LRU_UNEVICTABLE); | ||
3536 | list_move(&page->lru, &lruvec->lists[LRU_UNEVICTABLE]); | ||
3537 | if (page_evictable(page, NULL)) | ||
3538 | goto retry; | ||
3539 | } | ||
3540 | } | ||
3541 | |||
3542 | /** | ||
3543 | * scan_mapping_unevictable_pages - scan an address space for evictable pages | ||
3544 | * @mapping: struct address_space to scan for evictable pages | ||
3545 | * | ||
3546 | * Scan all pages in mapping. Check unevictable pages for | ||
3547 | * evictability and move them to the appropriate zone lru list. | ||
3548 | */ | ||
3549 | void scan_mapping_unevictable_pages(struct address_space *mapping) | ||
3550 | { | ||
3551 | pgoff_t next = 0; | ||
3552 | pgoff_t end = (i_size_read(mapping->host) + PAGE_CACHE_SIZE - 1) >> | ||
3553 | PAGE_CACHE_SHIFT; | ||
3554 | struct zone *zone; | ||
3555 | struct pagevec pvec; | ||
3556 | |||
3557 | if (mapping->nrpages == 0) | ||
3558 | return; | ||
3559 | |||
3560 | pagevec_init(&pvec, 0); | ||
3561 | while (next < end && | ||
3562 | pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { | ||
3563 | int i; | ||
3564 | int pg_scanned = 0; | ||
3565 | |||
3566 | zone = NULL; | ||
3567 | |||
3568 | for (i = 0; i < pagevec_count(&pvec); i++) { | ||
3569 | struct page *page = pvec.pages[i]; | ||
3570 | pgoff_t page_index = page->index; | ||
3571 | struct zone *pagezone = page_zone(page); | ||
3572 | 3522 | ||
3573 | pg_scanned++; | 3523 | pgscanned++; |
3574 | if (page_index > next) | 3524 | pagezone = page_zone(page); |
3575 | next = page_index; | 3525 | if (pagezone != zone) { |
3576 | next++; | 3526 | if (zone) |
3527 | spin_unlock_irq(&zone->lru_lock); | ||
3528 | zone = pagezone; | ||
3529 | spin_lock_irq(&zone->lru_lock); | ||
3530 | } | ||
3577 | 3531 | ||
3578 | if (pagezone != zone) { | 3532 | if (!PageLRU(page) || !PageUnevictable(page)) |
3579 | if (zone) | 3533 | continue; |
3580 | spin_unlock_irq(&zone->lru_lock); | ||
3581 | zone = pagezone; | ||
3582 | spin_lock_irq(&zone->lru_lock); | ||
3583 | } | ||
3584 | 3534 | ||
3585 | if (PageLRU(page) && PageUnevictable(page)) | 3535 | if (page_evictable(page, NULL)) { |
3586 | check_move_unevictable_page(page, zone); | 3536 | enum lru_list lru = page_lru_base_type(page); |
3537 | |||
3538 | VM_BUG_ON(PageActive(page)); | ||
3539 | ClearPageUnevictable(page); | ||
3540 | __dec_zone_state(zone, NR_UNEVICTABLE); | ||
3541 | lruvec = mem_cgroup_lru_move_lists(zone, page, | ||
3542 | LRU_UNEVICTABLE, lru); | ||
3543 | list_move(&page->lru, &lruvec->lists[lru]); | ||
3544 | __inc_zone_state(zone, NR_INACTIVE_ANON + lru); | ||
3545 | pgrescued++; | ||
3587 | } | 3546 | } |
3588 | if (zone) | ||
3589 | spin_unlock_irq(&zone->lru_lock); | ||
3590 | pagevec_release(&pvec); | ||
3591 | |||
3592 | count_vm_events(UNEVICTABLE_PGSCANNED, pg_scanned); | ||
3593 | } | 3547 | } |
3594 | 3548 | ||
3549 | if (zone) { | ||
3550 | __count_vm_events(UNEVICTABLE_PGRESCUED, pgrescued); | ||
3551 | __count_vm_events(UNEVICTABLE_PGSCANNED, pgscanned); | ||
3552 | spin_unlock_irq(&zone->lru_lock); | ||
3553 | } | ||
3595 | } | 3554 | } |
3555 | #endif /* CONFIG_SHMEM */ | ||
3596 | 3556 | ||
3597 | static void warn_scan_unevictable_pages(void) | 3557 | static void warn_scan_unevictable_pages(void) |
3598 | { | 3558 | { |