Commit 00c3e276 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'akpm' (Andrew's patch-bomb)

Merge random patches from Andrew Morton.

* Merge emailed patches from Andrew Morton <akpm@linux-foundation.org>: (32 commits)
  memblock: free allocated memblock_reserved_regions later
  mm: sparse: fix usemap allocation above node descriptor section
  mm: sparse: fix section usemap placement calculation
  xtensa: fix incorrect memset
  shmem: cleanup shmem_add_to_page_cache
  shmem: fix negative rss in memcg memory.stat
  tmpfs: revert SEEK_DATA and SEEK_HOLE
  drivers/rtc/rtc-twl.c: fix threaded IRQ to use IRQF_ONESHOT
  fat: fix non-atomic NFS i_pos read
  MAINTAINERS: add OMAP CPUfreq driver to OMAP Power Management section
  sgi-xp: nested calls to spin_lock_irqsave()
  fs: ramfs: file-nommu: add SetPageUptodate()
  drivers/rtc/rtc-mxc.c: fix irq enabled interrupts warning
  mm/memory_hotplug.c: release memory resources if hotadd_new_pgdat() fails
  h8300/uaccess: add mising __clear_user()
  h8300/uaccess: remove assignment to __gu_val in unhandled case of get_user()
  h8300/time: add missing #include <asm/irq_regs.h>
  h8300/signal: fix typo "statis"
  h8300/pgtable: add missing #include <asm-generic/pgtable.h>
  drivers/rtc/rtc-ab8500.c: ensure correct probing of the AB8500 RTC when Device Tree is enabled
  ...
parents 605cd836 29f67386
...@@ -4857,6 +4857,7 @@ M: Kevin Hilman <khilman@ti.com> ...@@ -4857,6 +4857,7 @@ M: Kevin Hilman <khilman@ti.com>
L: linux-omap@vger.kernel.org L: linux-omap@vger.kernel.org
S: Maintained S: Maintained
F: arch/arm/*omap*/*pm* F: arch/arm/*omap*/*pm*
F: drivers/cpufreq/omap-cpufreq.c
OMAP POWERDOMAIN/CLOCKDOMAIN SOC ADAPTATION LAYER SUPPORT OMAP POWERDOMAIN/CLOCKDOMAIN SOC ADAPTATION LAYER SUPPORT
M: Rajendra Nayak <rnayak@ti.com> M: Rajendra Nayak <rnayak@ti.com>
......
...@@ -70,4 +70,7 @@ extern int is_in_rom(unsigned long); ...@@ -70,4 +70,7 @@ extern int is_in_rom(unsigned long);
#define VMALLOC_END 0xffffffff #define VMALLOC_END 0xffffffff
#define arch_enter_lazy_cpu_mode() do {} while (0) #define arch_enter_lazy_cpu_mode() do {} while (0)
#include <asm-generic/pgtable.h>
#endif /* _H8300_PGTABLE_H */ #endif /* _H8300_PGTABLE_H */
...@@ -100,7 +100,6 @@ extern int __put_user_bad(void); ...@@ -100,7 +100,6 @@ extern int __put_user_bad(void);
break; \ break; \
default: \ default: \
__gu_err = __get_user_bad(); \ __gu_err = __get_user_bad(); \
__gu_val = 0; \
break; \ break; \
} \ } \
(x) = __gu_val; \ (x) = __gu_val; \
...@@ -159,4 +158,6 @@ clear_user(void *to, unsigned long n) ...@@ -159,4 +158,6 @@ clear_user(void *to, unsigned long n)
return 0; return 0;
} }
#define __clear_user clear_user
#endif /* _H8300_UACCESS_H */ #endif /* _H8300_UACCESS_H */
...@@ -447,7 +447,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, ...@@ -447,7 +447,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
* want to handle. Thus you cannot kill init even with a SIGKILL even by * want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake. * mistake.
*/ */
statis void do_signal(struct pt_regs *regs) static void do_signal(struct pt_regs *regs)
{ {
siginfo_t info; siginfo_t info;
int signr; int signr;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/profile.h> #include <linux/profile.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq_regs.h>
#include <asm/timer.h> #include <asm/timer.h>
#define TICK_SIZE (tick_nsec / 1000) #define TICK_SIZE (tick_nsec / 1000)
......
...@@ -81,9 +81,6 @@ struct pt_regs { ...@@ -81,9 +81,6 @@ struct pt_regs {
#define PTRACE_GETFPREGS 14 #define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15 #define PTRACE_SETFPREGS 15
/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL) #define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#ifndef _ASM_TIMEX_H #ifndef _ASM_TIMEX_H
#define _ASM_TIMEX_H #define _ASM_TIMEX_H
#include <asm/hardirq.h>
#include <unit/timex.h> #include <unit/timex.h>
#define TICK_SIZE (tick_nsec / 1000) #define TICK_SIZE (tick_nsec / 1000)
...@@ -30,16 +29,6 @@ static inline cycles_t get_cycles(void) ...@@ -30,16 +29,6 @@ static inline cycles_t get_cycles(void)
extern int init_clockevents(void); extern int init_clockevents(void);
extern int init_clocksource(void); extern int init_clocksource(void);
static inline void setup_jiffies_interrupt(int irq,
struct irqaction *action)
{
u16 tmp;
setup_irq(irq, action);
set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
tmp = GxICR(irq);
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_TIMEX_H */ #endif /* _ASM_TIMEX_H */
...@@ -70,6 +70,16 @@ static void event_handler(struct clock_event_device *dev) ...@@ -70,6 +70,16 @@ static void event_handler(struct clock_event_device *dev)
{ {
} }
static inline void setup_jiffies_interrupt(int irq,
struct irqaction *action)
{
u16 tmp;
setup_irq(irq, action);
set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
tmp = GxICR(irq);
}
int __init init_clockevents(void) int __init init_clockevents(void)
{ {
struct clock_event_device *cd; struct clock_event_device *cd;
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
#include <linux/irqreturn.h>
struct clocksource; struct clocksource;
struct clock_event_device; struct clock_event_device;
......
...@@ -170,9 +170,9 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask, ...@@ -170,9 +170,9 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
case SC1TXIRQ: case SC1TXIRQ:
#ifdef CONFIG_MN10300_TTYSM1_TIMER12 #ifdef CONFIG_MN10300_TTYSM1_TIMER12
case TM12IRQ: case TM12IRQ:
#elif CONFIG_MN10300_TTYSM1_TIMER9 #elif defined(CONFIG_MN10300_TTYSM1_TIMER9)
case TM9IRQ: case TM9IRQ:
#elif CONFIG_MN10300_TTYSM1_TIMER3 #elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
case TM3IRQ: case TM3IRQ:
#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */ #endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
#endif /* CONFIG_MN10300_TTYSM1 */ #endif /* CONFIG_MN10300_TTYSM1 */
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/export.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/export.h>
#include <asm/io.h> #include <asm/io.h>
static unsigned long pci_sram_allocated = 0xbc000000; static unsigned long pci_sram_allocated = 0xbc000000;
......
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
#ifndef _ASM_UNIT_TIMEX_H #ifndef _ASM_UNIT_TIMEX_H
#define _ASM_UNIT_TIMEX_H #define _ASM_UNIT_TIMEX_H
#ifndef __ASSEMBLY__
#include <linux/irq.h>
#endif /* __ASSEMBLY__ */
#include <asm/timer-regs.h> #include <asm/timer-regs.h>
#include <unit/clock.h> #include <unit/clock.h>
#include <asm/param.h> #include <asm/param.h>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/timex.h> #include <asm/timex.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/intctl-regs.h> #include <asm/intctl-regs.h>
......
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
#ifndef _ASM_UNIT_TIMEX_H #ifndef _ASM_UNIT_TIMEX_H
#define _ASM_UNIT_TIMEX_H #define _ASM_UNIT_TIMEX_H
#ifndef __ASSEMBLY__
#include <linux/irq.h>
#endif /* __ASSEMBLY__ */
#include <asm/timer-regs.h> #include <asm/timer-regs.h>
#include <unit/clock.h> #include <unit/clock.h>
#include <asm/param.h> #include <asm/param.h>
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/intctl-regs.h> #include <asm/intctl-regs.h>
......
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
#ifndef _ASM_UNIT_TIMEX_H #ifndef _ASM_UNIT_TIMEX_H
#define _ASM_UNIT_TIMEX_H #define _ASM_UNIT_TIMEX_H
#ifndef __ASSEMBLY__
#include <linux/irq.h>
#endif /* __ASSEMBLY__ */
#include <asm/timer-regs.h> #include <asm/timer-regs.h>
#include <unit/clock.h> #include <unit/clock.h>
#include <asm/param.h> #include <asm/param.h>
......
...@@ -277,7 +277,7 @@ void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) ...@@ -277,7 +277,7 @@ void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
/* Don't leak any random bits. */ /* Don't leak any random bits. */
memset(elfregs, 0, sizeof (elfregs)); memset(elfregs, 0, sizeof(*elfregs));
/* Note: PS.EXCM is not set while user task is running; its /* Note: PS.EXCM is not set while user task is running; its
* being set in regs->ps is for exception handling convenience. * being set in regs->ps is for exception handling convenience.
......
...@@ -452,9 +452,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, ...@@ -452,9 +452,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
if (msg->activate_gru_mq_desc_gpa != if (msg->activate_gru_mq_desc_gpa !=
part_uv->activate_gru_mq_desc_gpa) { part_uv->activate_gru_mq_desc_gpa) {
spin_lock_irqsave(&part_uv->flags_lock, irq_flags); spin_lock(&part_uv->flags_lock);
part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV; part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); spin_unlock(&part_uv->flags_lock);
part_uv->activate_gru_mq_desc_gpa = part_uv->activate_gru_mq_desc_gpa =
msg->activate_gru_mq_desc_gpa; msg->activate_gru_mq_desc_gpa;
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/mfd/abx500.h> #include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h>
#define AB8500_RTC_SOFF_STAT_REG 0x00 #define AB8500_RTC_SOFF_STAT_REG 0x00
#define AB8500_RTC_CC_CONF_REG 0x01 #define AB8500_RTC_CC_CONF_REG 0x01
...@@ -422,7 +423,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) ...@@ -422,7 +423,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
} }
err = request_threaded_irq(irq, NULL, rtc_alarm_handler, err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
IRQF_NO_SUSPEND, "ab8500-rtc", rtc); IRQF_NO_SUSPEND | IRQF_ONESHOT, "ab8500-rtc", rtc);
if (err < 0) { if (err < 0) {
rtc_device_unregister(rtc); rtc_device_unregister(rtc);
return err; return err;
...@@ -430,7 +431,6 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) ...@@ -430,7 +431,6 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc); platform_set_drvdata(pdev, rtc);
err = ab8500_sysfs_rtc_register(&pdev->dev); err = ab8500_sysfs_rtc_register(&pdev->dev);
if (err) { if (err) {
dev_err(&pdev->dev, "sysfs RTC failed to register\n"); dev_err(&pdev->dev, "sysfs RTC failed to register\n");
...@@ -454,10 +454,16 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev) ...@@ -454,10 +454,16 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id ab8500_rtc_match[] = {
{ .compatible = "stericsson,ab8500-rtc", },
{}
};
static struct platform_driver ab8500_rtc_driver = { static struct platform_driver ab8500_rtc_driver = {
.driver = { .driver = {
.name = "ab8500-rtc", .name = "ab8500-rtc",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = ab8500_rtc_match,
}, },
.probe = ab8500_rtc_probe, .probe = ab8500_rtc_probe,
.remove = __devexit_p(ab8500_rtc_remove), .remove = __devexit_p(ab8500_rtc_remove),
......
...@@ -202,10 +202,11 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) ...@@ -202,10 +202,11 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
struct platform_device *pdev = dev_id; struct platform_device *pdev = dev_id;
struct rtc_plat_data *pdata = platform_get_drvdata(pdev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
void __iomem *ioaddr = pdata->ioaddr; void __iomem *ioaddr = pdata->ioaddr;
unsigned long flags;
u32 status; u32 status;
u32 events = 0; u32 events = 0;
spin_lock_irq(&pdata->rtc->irq_lock); spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR); status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR);
/* clear interrupt sources */ /* clear interrupt sources */
writew(status, ioaddr + RTC_RTCISR); writew(status, ioaddr + RTC_RTCISR);
...@@ -224,7 +225,7 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) ...@@ -224,7 +225,7 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
events |= (RTC_PF | RTC_IRQF); events |= (RTC_PF | RTC_IRQF);
rtc_update_irq(pdata->rtc, 1, events); rtc_update_irq(pdata->rtc, 1, events);
spin_unlock_irq(&pdata->rtc->irq_lock); spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -458,12 +458,12 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev) ...@@ -458,12 +458,12 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
clk_disable(config->clk); clk_disable(config->clk);
clk_put(config->clk); clk_put(config->clk);
iounmap(config->ioaddr); iounmap(config->ioaddr);
kfree(config);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) if (res)
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
rtc_device_unregister(config->rtc); rtc_device_unregister(config->rtc);
kfree(config);
return 0; return 0;
} }
......
...@@ -510,7 +510,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) ...@@ -510,7 +510,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
} }
ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt, ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
IRQF_TRIGGER_RISING, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&rtc->dev), rtc); dev_name(&rtc->dev), rtc);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n"); dev_err(&pdev->dev, "IRQ is not free.\n");
......
...@@ -738,22 +738,21 @@ static int ...@@ -738,22 +738,21 @@ static int
fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent) fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent)
{ {
int len = *lenp; int len = *lenp;
u32 ipos_h, ipos_m, ipos_l; struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
loff_t i_pos;
if (len < 5) { if (len < 5) {
*lenp = 5; *lenp = 5;
return 255; /* no room */ return 255; /* no room */
} }
ipos_h = MSDOS_I(inode)->i_pos >> 8; i_pos = fat_i_pos_read(sbi, inode);
ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28;
*lenp = 5; *lenp = 5;
fh[0] = inode->i_ino; fh[0] = inode->i_ino;
fh[1] = inode->i_generation; fh[1] = inode->i_generation;
fh[2] = ipos_h; fh[2] = i_pos >> 8;
fh[3] = ipos_m | MSDOS_I(inode)->i_logstart; fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart;
fh[4] = ipos_l; fh[4] = (i_pos & 0x0f) << 28;
if (parent) if (parent)
fh[4] |= MSDOS_I(parent)->i_logstart; fh[4] |= MSDOS_I(parent)->i_logstart;
return 3; return 3;
......
...@@ -1950,7 +1950,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, ...@@ -1950,7 +1950,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
if (ret < 0) if (ret < 0)
mlog_errno(ret); mlog_errno(ret);
if (file->f_flags & O_SYNC) if (file && (file->f_flags & O_SYNC))
handle->h_sync = 1; handle->h_sync = 1;
ocfs2_commit_trans(osb, handle); ocfs2_commit_trans(osb, handle);
......
...@@ -110,6 +110,7 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) ...@@ -110,6 +110,7 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
/* prevent the page from being discarded on memory pressure */ /* prevent the page from being discarded on memory pressure */
SetPageDirty(page); SetPageDirty(page);
SetPageUptodate(page);
unlock_page(page); unlock_page(page);
put_page(page); put_page(page);
......
...@@ -91,6 +91,11 @@ extern void *__alloc_bootmem_node_nopanic(pg_data_t *pgdat, ...@@ -91,6 +91,11 @@ extern void *__alloc_bootmem_node_nopanic(pg_data_t *pgdat,
unsigned long size, unsigned long size,
unsigned long align, unsigned long align,
unsigned long goal); unsigned long goal);
void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
unsigned long size,
unsigned long align,
unsigned long goal,
unsigned long limit);
extern void *__alloc_bootmem_low(unsigned long size, extern void *__alloc_bootmem_low(unsigned long size,
unsigned long align, unsigned long align,
unsigned long goal); unsigned long goal);
......
...@@ -50,9 +50,7 @@ phys_addr_t memblock_find_in_range_node(phys_addr_t start, phys_addr_t end, ...@@ -50,9 +50,7 @@ phys_addr_t memblock_find_in_range_node(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align, int nid); phys_addr_t size, phys_addr_t align, int nid);
phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end, phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align); phys_addr_t size, phys_addr_t align);
int memblock_free_reserved_regions(void); phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
int memblock_reserve_reserved_regions(void);
void memblock_allow_resize(void); void memblock_allow_resize(void);
int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid); int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
int memblock_add(phys_addr_t base, phys_addr_t size); int memblock_add(phys_addr_t base, phys_addr_t size);
......
...@@ -694,7 +694,7 @@ typedef struct pglist_data { ...@@ -694,7 +694,7 @@ typedef struct pglist_data {
range, including holes */ range, including holes */
int node_id; int node_id;
wait_queue_head_t kswapd_wait; wait_queue_head_t kswapd_wait;
struct task_struct *kswapd; struct task_struct *kswapd; /* Protected by lock_memory_hotplug() */
int kswapd_max_order; int kswapd_max_order;
enum zone_type classzone_idx; enum zone_type classzone_idx;
} pg_data_t; } pg_data_t;
......
...@@ -1788,7 +1788,6 @@ SYSCALL_DEFINE1(umask, int, mask) ...@@ -1788,7 +1788,6 @@ SYSCALL_DEFINE1(umask, int, mask)
#ifdef CONFIG_CHECKPOINT_RESTORE #ifdef CONFIG_CHECKPOINT_RESTORE
static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
{ {
struct vm_area_struct *vma;
struct file *exe_file; struct file *exe_file;
struct dentry *dentry; struct dentry *dentry;
int err; int err;
...@@ -1816,12 +1815,16 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) ...@@ -1816,12 +1815,16 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
down_write(&mm->mmap_sem); down_write(&mm->mmap_sem);
/* /*
* Forbid mm->exe_file change if there are mapped other files. * Forbid mm->exe_file change if old file still mapped.
*/ */
err = -EBUSY; err = -EBUSY;
for (vma = mm->mmap; vma; vma = vma->vm_next) { if (mm->exe_file) {
if (vma->vm_file && !path_equal(&vma->vm_file->f_path, struct vm_area_struct *vma;
&exe_file->f_path))
for (vma = mm->mmap; vma; vma = vma->vm_next)
if (vma->vm_file &&
path_equal(&vma->vm_file->f_path,
&mm->exe_file->f_path))
goto exit_unlock; goto exit_unlock;
} }
...@@ -1835,6 +1838,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) ...@@ -1835,6 +1838,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags)) if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags))
goto exit_unlock; goto exit_unlock;
err = 0;
set_mm_exe_file(mm, exe_file); set_mm_exe_file(mm, exe_file);
exit_unlock: exit_unlock:
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
......
...@@ -698,7 +698,7 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align, ...@@ -698,7 +698,7 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
return ___alloc_bootmem(size, align, goal, limit); return ___alloc_bootmem(size, align, goal, limit);
} }
static void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat, void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
unsigned long size, unsigned long align, unsigned long size, unsigned long align,
unsigned long goal, unsigned long limit) unsigned long goal, unsigned long limit)
{ {
......
...@@ -701,8 +701,11 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) ...@@ -701,8 +701,11 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
if (err) { if (err) {
putback_lru_pages(&cc->migratepages); putback_lru_pages(&cc->migratepages);
cc->nr_migratepages = 0; cc->nr_migratepages = 0;
if (err == -ENOMEM) {
ret = COMPACT_PARTIAL;
goto out;
}
} }
} }
out: out:
......
...@@ -143,30 +143,6 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, ...@@ -143,30 +143,6 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
MAX_NUMNODES); MAX_NUMNODES);
} }
/*
* Free memblock.reserved.regions
*/
int __init_memblock memblock_free_reserved_regions(void)
{
if (memblock.reserved.regions == memblock_reserved_init_regions)
return 0;
return memblock_free(__pa(memblock.reserved.regions),
sizeof(struct memblock_region) * memblock.reserved.max);
}
/*
* Reserve memblock.reserved.regions
*/
int __init_memblock memblock_reserve_reserved_regions(void)
{
if (memblock.reserved.regions == memblock_reserved_init_regions)
return 0;
return memblock_reserve(__pa(memblock.reserved.regions),
sizeof(struct memblock_region) * memblock.reserved.max);
}
static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
{ {
type->total_size -= type->regions[r].size; type->total_size -= type->regions[r].size;
...@@ -184,6 +160,18 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u ...@@ -184,6 +160,18 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
} }
} }
phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
phys_addr_t *addr)
{
if (memblock.reserved.regions == memblock_reserved_init_regions)
return 0;
*addr = __pa(memblock.reserved.regions);
return PAGE_ALIGN(sizeof(struct memblock_region) *
memblock.reserved.max);
}
/** /**
* memblock_double_array - double the size of the memblock regions array * memblock_double_array - double the size of the memblock regions array
* @type: memblock type of the regions array being doubled * @type: memblock type of the regions array being doubled
...@@ -204,6 +192,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, ...@@ -204,6 +192,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
phys_addr_t new_area_size) phys_addr_t new_area_size)
{ {
struct memblock_region *new_array, *old_array; struct memblock_region *new_array, *old_array;
phys_addr_t old_alloc_size, new_alloc_size;
phys_addr_t old_size, new_size, addr; phys_addr_t old_size, new_size, addr;
int use_slab = slab_is_available(); int use_slab = slab_is_available();
int *in_slab; int *in_slab;
...@@ -217,6 +206,12 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, ...@@ -217,6 +206,12 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
/* Calculate new doubled size */ /* Calculate new doubled size */
old_size = type->max * sizeof(struct memblock_region); old_size = type->max * sizeof(struct memblock_region);
new_size = old_size << 1; new_size = old_size << 1;
/*
* We need to allocated new one align to PAGE_SIZE,
* so we can free them completely later.
*/
old_alloc_size = PAGE_ALIGN(old_size);
new_alloc_size = PAGE_ALIGN(new_size);
/* Retrieve the slab flag */ /* Retrieve the slab flag */
if (type == &memblock.memory) if (type == &memblock.memory)
...@@ -245,11 +240,11 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, ...@@ -245,11 +240,11 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
addr = memblock_find_in_range(new_area_start + new_area_size, addr = memblock_find_in_range(new_area_start + new_area_size,
memblock.current_limit, memblock.current_limit,
new_size, sizeof(phys_addr_t)); new_alloc_size, PAGE_SIZE);
if (!addr && new_area_size) if (!addr && new_area_size)
addr = memblock_find_in_range(0, addr = memblock_find_in_range(0,
min(new_area_start, memblock.current_limit), min(new_area_start, memblock.current_limit),
new_size, sizeof(phys_addr_t)); new_alloc_size, PAGE_SIZE);
new_array = addr ? __va(addr) : 0; new_array = addr ? __va(addr) : 0;
} }
...@@ -279,13 +274,13 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, ...@@ -279,13 +274,13 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
kfree(old_array); kfree(old_array);
else if (old_array != memblock_memory_init_regions && else if (old_array != memblock_memory_init_regions &&
old_array != memblock_reserved_init_regions) old_array != memblock_reserved_init_regions)
memblock_free(__pa(old_array), old_size); memblock_free(__pa(old_array), old_alloc_size);
/* Reserve the new array if that comes from the memblock. /* Reserve the new array if that comes from the memblock.
* Otherwise, we needn't do it * Otherwise, we needn't do it
*/ */
if (!use_slab) if (!use_slab)
BUG_ON(memblock_reserve(addr, new_size)); BUG_ON(memblock_reserve(addr, new_alloc_size));
/* Update slab flag */ /* Update slab flag */
*in_slab = use_slab; *in_slab = use_slab;
......
...@@ -618,7 +618,7 @@ int __ref add_memory(int nid, u64 start, u64 size) ...@@ -618,7 +618,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
pgdat = hotadd_new_pgdat(nid, start); pgdat = hotadd_new_pgdat(nid, start);
ret = -ENOMEM; ret = -ENOMEM;
if (!pgdat) if (!pgdat)
goto out; goto error;
new_pgdat = 1; new_pgdat = 1;
} }
......
...@@ -105,27 +105,35 @@ static void __init __free_pages_memory(unsigned long start, unsigned long end) ...@@ -105,27 +105,35 @@ static void __init __free_pages_memory(unsigned long start, unsigned long end)
__free_pages_bootmem(pfn_to_page(i), 0); __free_pages_bootmem(pfn_to_page(i), 0);
} }
static unsigned long __init __free_memory_core(phys_addr_t start,
phys_addr_t end)
{
unsigned long start_pfn = PFN_UP(start);
unsigned long end_pfn = min_t(unsigned long,
PFN_DOWN(end), max_low_pfn);
if (start_pfn > end_pfn)
return 0;
__free_pages_memory(start_pfn, end_pfn);
return end_pfn - start_pfn;
}
unsigned long __init free_low_memory_core_early(int nodeid) unsigned long __init free_low_memory_core_early(int nodeid)
{ {
unsigned long count = 0; unsigned long count = 0;
phys_addr_t start, end; phys_addr_t start, end, size;
u64 i; u64 i;
/* free reserved array temporarily so that it's treated as free area */ for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL)
memblock_free_reserved_regions(); count += __free_memory_core(start, end);
for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL) { /* free range that is used for reserved array if we allocate it */
unsigned long start_pfn = PFN_UP(start); size = get_allocated_memblock_reserved_regions_info(&start);
unsigned long end_pfn = min_t(unsigned long, if (size)
PFN_DOWN(end), max_low_pfn); count += __free_memory_core(start, start + size);
if (start_pfn < end_pfn) {
__free_pages_memory(start_pfn, end_pfn);
count += end_pfn - start_pfn;
}
}
/* put region array back? */
memblock_reserve_reserved_regions();
return count; return count;
} }
...@@ -274,7 +282,7 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align, ...@@ -274,7 +282,7 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
return ___alloc_bootmem(size, align, goal, limit); return ___alloc_bootmem(size, align, goal, limit);
} }
static void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat, void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
unsigned long size, unsigned long size,
unsigned long align, unsigned long align,
unsigned long goal, unsigned long goal,
......
...@@ -263,6 +263,24 @@ static int shmem_radix_tree_replace(struct address_space *mapping, ...@@ -263,6 +263,24 @@ static int shmem_radix_tree_replace(struct address_space *mapping,
return 0; return 0;
} }
/*
* Sometimes, before we decide whether to proceed or to fail, we must check
* that an entry was not already brought back from swap by a racing thread.
*
* Checking page is not enough: by the time a SwapCache page is locked, it
* might be reused, and again be SwapCache, using the same swap as before.
*/
static bool shmem_confirm_swap(struct address_space *mapping,
pgoff_t index, swp_entry_t swap)
{
void *item;
rcu_read_lock();
item = radix_tree_lookup(&mapping->page_tree, index);
rcu_read_unlock();
return item == swp_to_radix_entry(swap);
}
/* /*
* Like add_to_page_cache_locked, but error if expected item has gone. * Like add_to_page_cache_locked, but error if expected item has gone.
*/ */
...@@ -270,25 +288,21 @@ static int shmem_add_to_page_cache(struct page *page, ...@@ -270,25 +288,21 @@ static int shmem_add_to_page_cache(struct page *page,
struct address_space *mapping, struct address_space *mapping,
pgoff_t index, gfp_t gfp, void *expected) pgoff_t index, gfp_t gfp, void *expected)
{ {
int error = 0; int error;
VM_BUG_ON(!PageLocked(page)); VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(!PageSwapBacked(page)); VM_BUG_ON(!PageSwapBacked(page));
if (!expected)
error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
if (!error) {
page_cache_get(page); page_cache_get(page);
page->mapping = mapping; page->mapping = mapping;
page->index = index; page->index = index;
spin_lock_irq(&mapping->tree_lock); spin_lock_irq(&mapping->tree_lock);
if (!expected) if (!expected)
error = radix_tree_insert(&mapping->page_tree, error = radix_tree_insert(&mapping->page_tree, index, page);
index, page);
else else
error = shmem_radix_tree_replace(mapping, index, error = shmem_radix_tree_replace(mapping, index, expected,
expected, page); page);
if (!error) { if (!error) {
mapping->nrpages++; mapping->nrpages++;
__inc_zone_page_state(page, NR_FILE_PAGES); __inc_zone_page_state(page, NR_FILE_PAGES);
...@@ -299,11 +313,6 @@ static int shmem_add_to_page_cache(struct page *page, ...@@ -299,11 +313,6 @@ static int shmem_add_to_page_cache(struct page *page,
spin_unlock_irq(&mapping->tree_lock); spin_unlock_irq(&mapping->tree_lock);
page_cache_release(page); page_cache_release(page);
} }
if (!expected)
radix_tree_preload_end();
}
if (error)
mem_cgroup_uncharge_cache_page(page);
return error; return error;
} }
...@@ -1124,9 +1133,9 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, ...@@ -1124,9 +1133,9 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
/* We have to do this with page locked to prevent races */ /* We have to do this with page locked to prevent races */
lock_page(page); lock_page(page);
if (!PageSwapCache(page) || page_private(page) != swap.val || if (!PageSwapCache(page) || page_private(page) != swap.val ||
page->mapping) { !shmem_confirm_swap(mapping, index, swap)) {
error = -EEXIST; /* try again */ error = -EEXIST; /* try again */
goto failed; goto unlock;
} }
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
error = -EIO; error = -EIO;
...@@ -1142,9 +1151,12 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, ...@@ -1142,9 +1151,12 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
error = mem_cgroup_cache_charge(page, current->mm, error = mem_cgroup_cache_charge(page, current->mm,
gfp & GFP_RECLAIM_MASK); gfp & GFP_RECLAIM_MASK);
if (!error) if (!error) {
error = shmem_add_to_page_cache(page, mapping, index, error = shmem_add_to_page_cache(page, mapping, index,
gfp, swp_to_radix_entry(swap)); gfp, swp_to_radix_entry(swap));
/* We already confirmed swap, and make no allocation */
VM_BUG_ON(error);
}
if (error) if (error)
goto failed; goto failed;
...@@ -1181,11 +1193,18 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, ...@@ -1181,11 +1193,18 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
__set_page_locked(page); __set_page_locked(page);
error = mem_cgroup_cache_charge(page, current->mm, error = mem_cgroup_cache_charge(page, current->mm,
gfp & GFP_RECLAIM_MASK); gfp & GFP_RECLAIM_MASK);
if (!error) if (error)
goto decused;
error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
if (!error) {
error = shmem_add_to_page_cache(page, mapping, index, error = shmem_add_to_page_cache(page, mapping, index,
gfp, NULL); gfp, NULL);
if (error) radix_tree_preload_end();
}
if (error) {
mem_cgroup_uncharge_cache_page(page);
goto decused; goto decused;
}
lru_cache_add_anon(page); lru_cache_add_anon(page);
spin_lock(&info->lock); spin_lock(&info->lock);
...@@ -1245,14 +1264,10 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, ...@@ -1245,14 +1264,10 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
unacct: unacct:
shmem_unacct_blocks(info->flags, 1); shmem_unacct_blocks(info->flags, 1);
failed: failed:
if (swap.val && error != -EINVAL) { if (swap.val && error != -EINVAL &&
struct page *test = find_get_page(mapping, index); !shmem_confirm_swap(mapping, index, swap))
if (test && !radix_tree_exceptional_entry(test))
page_cache_release(test);
/* Have another try if the entry has changed */
if (test != swp_to_radix_entry(swap))
error = -EEXIST; error = -EEXIST;
} unlock:
if (page) { if (page) {
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
...@@ -1264,7 +1279,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, ...@@ -1264,7 +1279,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
spin_unlock(&info->lock); spin_unlock(&info->lock);
goto repeat; goto repeat;
} }
if (error == -EEXIST) if (error == -EEXIST) /* from above or from radix_tree_insert */
goto repeat; goto repeat;
return error; return error;
} }
...@@ -1692,98 +1707,6 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, ...@@ -1692,98 +1707,6 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
return error; return error;
} }
/*
* llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
*/
static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
pgoff_t index, pgoff_t end, int origin)
{
struct page *page;
struct pagevec pvec;
pgoff_t indices[PAGEVEC_SIZE];
bool done = false;
int i;
pagevec_init(&pvec, 0);
pvec.nr = 1; /* start small: we may be there already */
while (!done) {
pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
pvec.nr, pvec.pages, indices);
if (!pvec.nr) {
if (origin == SEEK_DATA)
index = end;
break;
}
for (i = 0; i < pvec.nr; i++, index++) {
if (index < indices[i]) {
if (origin == SEEK_HOLE) {
done = true;
break;
}
index = indices[i];
}
page = pvec.pages[i];
if (page && !radix_tree_exceptional_entry(page)) {
if (!PageUptodate(page))
page = NULL;
}
if (index >= end ||
(page && origin == SEEK_DATA) ||
(!page && origin == SEEK_HOLE)) {
done = true;
break;
}
}
shmem_deswap_pagevec(&pvec);
pagevec_release(&pvec);
pvec.nr = PAGEVEC_SIZE;
cond_resched();
}
return index;
}
static loff_t shmem_file_llseek(struct file *file, loff_t offset, int origin)
{
struct address_space *mapping;
struct inode *inode;
pgoff_t start, end;
loff_t new_offset;
if (origin != SEEK_DATA && origin != SEEK_HOLE)
return generic_file_llseek_size(file, offset, origin,
MAX_LFS_FILESIZE);
mapping = file->f_mapping;
inode = mapping->host;
mutex_lock(&inode->i_mutex);
/* We're holding i_mutex so we can access i_size directly */
if (offset < 0)
offset = -EINVAL;
else if (offset >= inode->i_size)
offset = -ENXIO;
else {
start = offset >> PAGE_CACHE_SHIFT;
end = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
new_offset = shmem_seek_hole_data(mapping, start, end, origin);
new_offset <<= PAGE_CACHE_SHIFT;
if (new_offset > offset) {
if (new_offset < inode->i_size)
offset = new_offset;
else if (origin == SEEK_DATA)
offset = -ENXIO;
else
offset = inode->i_size;
}
}
if (offset >= 0 && offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
mutex_unlock(&inode->i_mutex);
return offset;
}
static long shmem_fallocate(struct file *file, int mode, loff_t offset, static long shmem_fallocate(struct file *file, int mode, loff_t offset,
loff_t len) loff_t len)
{ {
...@@ -2787,7 +2710,7 @@ static const struct address_space_operations shmem_aops = { ...@@ -2787,7 +2710,7 @@ static const struct address_space_operations shmem_aops = {
static const struct file_operations shmem_file_operations = { static const struct file_operations shmem_file_operations = {
.mmap = shmem_mmap, .mmap = shmem_mmap,
#ifdef CONFIG_TMPFS #ifdef CONFIG_TMPFS
.llseek = shmem_file_llseek, .llseek = generic_file_llseek,
.read = do_sync_read, .read = do_sync_read,
.write = do_sync_write, .write = do_sync_write,
.aio_read = shmem_file_aio_read, .aio_read = shmem_file_aio_read,
......
...@@ -275,8 +275,9 @@ static unsigned long * __init ...@@ -275,8 +275,9 @@ static unsigned long * __init
sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
unsigned long size) unsigned long size)
{ {
pg_data_t *host_pgdat; unsigned long goal, limit;
unsigned long goal; unsigned long *p;
int nid;
/* /*
* A page may contain usemaps for other sections preventing the * A page may contain usemaps for other sections preventing the
* page being freed and making a section unremovable while * page being freed and making a section unremovable while
...@@ -287,10 +288,17 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, ...@@ -287,10 +288,17 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
* from the same section as the pgdat where possible to avoid * from the same section as the pgdat where possible to avoid
* this problem. * this problem.
*/ */
goal = __pa(pgdat) & PAGE_SECTION_MASK; goal = __pa(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT);
host_pgdat = NODE_DATA(early_pfn_to_nid(goal >> PAGE_SHIFT)); limit = goal + (1UL << PA_SECTION_SHIFT);
return __alloc_bootmem_node_nopanic(host_pgdat, size, nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
SMP_CACHE_BYTES, goal); again:
p = ___alloc_bootmem_node_nopanic(NODE_DATA(nid), size,
SMP_CACHE_BYTES, goal, limit);
if (!p && limit) {
limit = 0;
goto again;
}
return p;
} }
static void __init check_usemap_section_nr(int nid, unsigned long *usemap) static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
......
...@@ -2955,14 +2955,17 @@ int kswapd_run(int nid) ...@@ -2955,14 +2955,17 @@ int kswapd_run(int nid)
} }
/* /*
* Called by memory hotplug when all memory in a node is offlined. * Called by memory hotplug when all memory in a node is offlined. Caller must
* hold lock_memory_hotplug().
*/ */
void kswapd_stop(int nid) void kswapd_stop(int nid)
{ {
struct task_struct *kswapd = NODE_DATA(nid)->kswapd; struct task_struct *kswapd = NODE_DATA(nid)->kswapd;
if (kswapd) if (kswapd) {
kthread_stop(kswapd); kthread_stop(kswapd);
NODE_DATA(nid)->kswapd = NULL;
}
} }
static int __init kswapd_init(void) static int __init kswapd_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment