Commit 532bfc85 authored by Linus Torvalds's avatar Linus Torvalds

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

Merge third batch of patches from Andrew Morton:
 - Some MM stragglers
 - core SMP library cleanups (on_each_cpu_mask)
 - Some IPI optimisations
 - kexec
 - kdump
 - IPMI
 - the radix-tree iterator work
 - various other misc bits.

 "That'll do for -rc1.  I still have ~10 patches for 3.4, will send
  those along when they've baked a little more."

* emailed from Andrew Morton <akpm@linux-foundation.org>: (35 commits)
  backlight: fix typo in tosa_lcd.c
  crc32: add help text for the algorithm select option
  mm: move hugepage test examples to tools/testing/selftests/vm
  mm: move slabinfo.c to tools/vm
  mm: move page-types.c from Documentation to tools/vm
  selftests/Makefile: make `run_tests' depend on `all'
  selftests: launch individual selftests from the main Makefile
  radix-tree: use iterators in find_get_pages* functions
  radix-tree: rewrite gang lookup using iterator
  radix-tree: introduce bit-optimized iterator
  fs/proc/namespaces.c: prevent crash when ns_entries[] is empty
  nbd: rename the nbd_device variable from lo to nbd
  pidns: add reboot_pid_ns() to handle the reboot syscall
  sysctl: use bitmap library functions
  ipmi: use locks on watchdog timeout set on reboot
  ipmi: simplify locking
  ipmi: fix message handling during panics
  ipmi: use a tasklet for handling received messages
  ipmi: increase KCS timeouts
  ipmi: decrease the IPMI message transaction time in interrupt mode
  ...
parents 0195c002 8da00edc
obj-m := DocBook/ accounting/ auxdisplay/ connector/ \ obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \ filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
pcmcia/ spi/ timers/ vm/ watchdog/src/ pcmcia/ spi/ timers/ watchdog/src/
# kbuild trick to avoid linker error. Can be omitted if a module is built.
obj- := dummy.o
# List of programs to build
hostprogs-y := page-types hugepage-mmap hugepage-shm map_hugetlb
# Tell kbuild to always build the programs
always := $(hostprogs-y)
...@@ -13,18 +13,6 @@ ...@@ -13,18 +13,6 @@
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
static void on_each_cpu_mask(void (*func)(void *), void *info, int wait,
const struct cpumask *mask)
{
preempt_disable();
smp_call_function_many(mask, func, info, wait);
if (cpumask_test_cpu(smp_processor_id(), mask))
func(info);
preempt_enable();
}
/**********************************************************************/ /**********************************************************************/
/* /*
...@@ -87,7 +75,7 @@ void flush_tlb_all(void) ...@@ -87,7 +75,7 @@ void flush_tlb_all(void)
void flush_tlb_mm(struct mm_struct *mm) void flush_tlb_mm(struct mm_struct *mm)
{ {
if (tlb_ops_need_broadcast()) if (tlb_ops_need_broadcast())
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
else else
local_flush_tlb_mm(mm); local_flush_tlb_mm(mm);
} }
...@@ -98,7 +86,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) ...@@ -98,7 +86,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
struct tlb_args ta; struct tlb_args ta;
ta.ta_vma = vma; ta.ta_vma = vma;
ta.ta_start = uaddr; ta.ta_start = uaddr;
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page,
&ta, 1);
} else } else
local_flush_tlb_page(vma, uaddr); local_flush_tlb_page(vma, uaddr);
} }
...@@ -121,7 +110,8 @@ void flush_tlb_range(struct vm_area_struct *vma, ...@@ -121,7 +110,8 @@ void flush_tlb_range(struct vm_area_struct *vma,
ta.ta_vma = vma; ta.ta_vma = vma;
ta.ta_start = start; ta.ta_start = start;
ta.ta_end = end; ta.ta_end = end;
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range,
&ta, 1);
} else } else
local_flush_tlb_range(vma, start, end); local_flush_tlb_range(vma, start, end);
} }
......
...@@ -843,7 +843,7 @@ early_param("additional_cpus", setup_additional_cpus); ...@@ -843,7 +843,7 @@ early_param("additional_cpus", setup_additional_cpus);
* are onlined, or offlined. The reason is per-cpu data-structures * are onlined, or offlined. The reason is per-cpu data-structures
* are allocated by some modules at init time, and dont expect to * are allocated by some modules at init time, and dont expect to
* do this dynamically on cpu arrival/departure. * do this dynamically on cpu arrival/departure.
* cpu_present_map on the other hand can change dynamically. * cpu_present_mask on the other hand can change dynamically.
* In case when cpu_hotplug is not compiled, then we resort to current * In case when cpu_hotplug is not compiled, then we resort to current
* behaviour, which is cpu_possible == cpu_present. * behaviour, which is cpu_possible == cpu_present.
* - Ashok Raj * - Ashok Raj
...@@ -921,7 +921,7 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) ...@@ -921,7 +921,7 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
acpi_map_cpu2node(handle, cpu, physid); acpi_map_cpu2node(handle, cpu, physid);
cpu_set(cpu, cpu_present_map); set_cpu_present(cpu, true);
ia64_cpu_to_sapicid[cpu] = physid; ia64_cpu_to_sapicid[cpu] = physid;
acpi_processor_set_pdc(handle); acpi_processor_set_pdc(handle);
...@@ -940,7 +940,7 @@ EXPORT_SYMBOL(acpi_map_lsapic); ...@@ -940,7 +940,7 @@ EXPORT_SYMBOL(acpi_map_lsapic);
int acpi_unmap_lsapic(int cpu) int acpi_unmap_lsapic(int cpu)
{ {
ia64_cpu_to_sapicid[cpu] = -1; ia64_cpu_to_sapicid[cpu] = -1;
cpu_clear(cpu, cpu_present_map); set_cpu_present(cpu, false);
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
/* NUMA specific cleanup's */ /* NUMA specific cleanup's */
......
...@@ -117,7 +117,7 @@ static inline int find_unassigned_vector(cpumask_t domain) ...@@ -117,7 +117,7 @@ static inline int find_unassigned_vector(cpumask_t domain)
cpumask_t mask; cpumask_t mask;
int pos, vector; int pos, vector;
cpus_and(mask, domain, cpu_online_map); cpumask_and(&mask, &domain, cpu_online_mask);
if (cpus_empty(mask)) if (cpus_empty(mask))
return -EINVAL; return -EINVAL;
...@@ -140,7 +140,7 @@ static int __bind_irq_vector(int irq, int vector, cpumask_t domain) ...@@ -140,7 +140,7 @@ static int __bind_irq_vector(int irq, int vector, cpumask_t domain)
BUG_ON((unsigned)irq >= NR_IRQS); BUG_ON((unsigned)irq >= NR_IRQS);
BUG_ON((unsigned)vector >= IA64_NUM_VECTORS); BUG_ON((unsigned)vector >= IA64_NUM_VECTORS);
cpus_and(mask, domain, cpu_online_map); cpumask_and(&mask, &domain, cpu_online_mask);
if (cpus_empty(mask)) if (cpus_empty(mask))
return -EINVAL; return -EINVAL;
if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain)) if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
...@@ -178,7 +178,7 @@ static void __clear_irq_vector(int irq) ...@@ -178,7 +178,7 @@ static void __clear_irq_vector(int irq)
BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED); BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
vector = cfg->vector; vector = cfg->vector;
domain = cfg->domain; domain = cfg->domain;
cpus_and(mask, cfg->domain, cpu_online_map); cpumask_and(&mask, &cfg->domain, cpu_online_mask);
for_each_cpu_mask(cpu, mask) for_each_cpu_mask(cpu, mask)
per_cpu(vector_irq, cpu)[vector] = -1; per_cpu(vector_irq, cpu)[vector] = -1;
cfg->vector = IRQ_VECTOR_UNASSIGNED; cfg->vector = IRQ_VECTOR_UNASSIGNED;
...@@ -321,7 +321,7 @@ void irq_complete_move(unsigned irq) ...@@ -321,7 +321,7 @@ void irq_complete_move(unsigned irq)
if (unlikely(cpu_isset(smp_processor_id(), cfg->old_domain))) if (unlikely(cpu_isset(smp_processor_id(), cfg->old_domain)))
return; return;
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); cpumask_and(&cleanup_mask, &cfg->old_domain, cpu_online_mask);
cfg->move_cleanup_count = cpus_weight(cleanup_mask); cfg->move_cleanup_count = cpus_weight(cleanup_mask);
for_each_cpu_mask(i, cleanup_mask) for_each_cpu_mask(i, cleanup_mask)
platform_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0); platform_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0);
......
...@@ -1514,7 +1514,8 @@ static void ...@@ -1514,7 +1514,8 @@ static void
ia64_mca_cmc_poll (unsigned long dummy) ia64_mca_cmc_poll (unsigned long dummy)
{ {
/* Trigger a CMC interrupt cascade */ /* Trigger a CMC interrupt cascade */
platform_send_ipi(first_cpu(cpu_online_map), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR,
IA64_IPI_DM_INT, 0);
} }
/* /*
...@@ -1590,7 +1591,8 @@ static void ...@@ -1590,7 +1591,8 @@ static void
ia64_mca_cpe_poll (unsigned long dummy) ia64_mca_cpe_poll (unsigned long dummy)
{ {
/* Trigger a CPE interrupt cascade */ /* Trigger a CPE interrupt cascade */
platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR,
IA64_IPI_DM_INT, 0);
} }
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
......
...@@ -57,7 +57,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) ...@@ -57,7 +57,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
return irq; return irq;
irq_set_msi_desc(irq, desc); irq_set_msi_desc(irq, desc);
cpus_and(mask, irq_to_domain(irq), cpu_online_map); cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
dest_phys_id = cpu_physical_id(first_cpu(mask)); dest_phys_id = cpu_physical_id(first_cpu(mask));
vector = irq_to_vector(irq); vector = irq_to_vector(irq);
...@@ -179,7 +179,7 @@ msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) ...@@ -179,7 +179,7 @@ msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
unsigned dest; unsigned dest;
cpumask_t mask; cpumask_t mask;
cpus_and(mask, irq_to_domain(irq), cpu_online_map); cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
dest = cpu_physical_id(first_cpu(mask)); dest = cpu_physical_id(first_cpu(mask));
msg->address_hi = 0; msg->address_hi = 0;
......
...@@ -485,7 +485,7 @@ mark_bsp_online (void) ...@@ -485,7 +485,7 @@ mark_bsp_online (void)
{ {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* If we register an early console, allow CPU 0 to printk */ /* If we register an early console, allow CPU 0 to printk */
cpu_set(smp_processor_id(), cpu_online_map); set_cpu_online(smp_processor_id(), true);
#endif #endif
} }
......
...@@ -76,7 +76,7 @@ stop_this_cpu(void) ...@@ -76,7 +76,7 @@ stop_this_cpu(void)
/* /*
* Remove this CPU: * Remove this CPU:
*/ */
cpu_clear(smp_processor_id(), cpu_online_map); set_cpu_online(smp_processor_id(), false);
max_xtp(); max_xtp();
local_irq_disable(); local_irq_disable();
cpu_halt(); cpu_halt();
......
...@@ -400,7 +400,7 @@ smp_callin (void) ...@@ -400,7 +400,7 @@ smp_callin (void)
/* Setup the per cpu irq handling data structures */ /* Setup the per cpu irq handling data structures */
__setup_vector_irq(cpuid); __setup_vector_irq(cpuid);
notify_cpu_starting(cpuid); notify_cpu_starting(cpuid);
cpu_set(cpuid, cpu_online_map); set_cpu_online(cpuid, true);
per_cpu(cpu_state, cpuid) = CPU_ONLINE; per_cpu(cpu_state, cpuid) = CPU_ONLINE;
spin_unlock(&vector_lock); spin_unlock(&vector_lock);
ipi_call_unlock_irq(); ipi_call_unlock_irq();
...@@ -547,7 +547,7 @@ do_boot_cpu (int sapicid, int cpu) ...@@ -547,7 +547,7 @@ do_boot_cpu (int sapicid, int cpu)
if (!cpu_isset(cpu, cpu_callin_map)) { if (!cpu_isset(cpu, cpu_callin_map)) {
printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid); printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
ia64_cpu_to_sapicid[cpu] = -1; ia64_cpu_to_sapicid[cpu] = -1;
cpu_clear(cpu, cpu_online_map); /* was set in smp_callin() */ set_cpu_online(cpu, false); /* was set in smp_callin() */
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
...@@ -577,8 +577,7 @@ smp_build_cpu_map (void) ...@@ -577,8 +577,7 @@ smp_build_cpu_map (void)
} }
ia64_cpu_to_sapicid[0] = boot_cpu_id; ia64_cpu_to_sapicid[0] = boot_cpu_id;
cpus_clear(cpu_present_map); init_cpu_present(cpumask_of(0));
set_cpu_present(0, true);
set_cpu_possible(0, true); set_cpu_possible(0, true);
for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) { for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
sapicid = smp_boot_data.cpu_phys_id[i]; sapicid = smp_boot_data.cpu_phys_id[i];
...@@ -605,10 +604,6 @@ smp_prepare_cpus (unsigned int max_cpus) ...@@ -605,10 +604,6 @@ smp_prepare_cpus (unsigned int max_cpus)
smp_setup_percpu_timer(); smp_setup_percpu_timer();
/*
* We have the boot CPU online for sure.
*/
cpu_set(0, cpu_online_map);
cpu_set(0, cpu_callin_map); cpu_set(0, cpu_callin_map);
local_cpu_data->loops_per_jiffy = loops_per_jiffy; local_cpu_data->loops_per_jiffy = loops_per_jiffy;
...@@ -632,7 +627,7 @@ smp_prepare_cpus (unsigned int max_cpus) ...@@ -632,7 +627,7 @@ smp_prepare_cpus (unsigned int max_cpus)
void __devinit smp_prepare_boot_cpu(void) void __devinit smp_prepare_boot_cpu(void)
{ {
cpu_set(smp_processor_id(), cpu_online_map); set_cpu_online(smp_processor_id(), true);
cpu_set(smp_processor_id(), cpu_callin_map); cpu_set(smp_processor_id(), cpu_callin_map);
set_numa_node(cpu_to_node_map[smp_processor_id()]); set_numa_node(cpu_to_node_map[smp_processor_id()]);
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
...@@ -689,7 +684,7 @@ int migrate_platform_irqs(unsigned int cpu) ...@@ -689,7 +684,7 @@ int migrate_platform_irqs(unsigned int cpu)
/* /*
* Now re-target the CPEI to a different processor * Now re-target the CPEI to a different processor
*/ */
new_cpei_cpu = any_online_cpu(cpu_online_map); new_cpei_cpu = cpumask_any(cpu_online_mask);
mask = cpumask_of(new_cpei_cpu); mask = cpumask_of(new_cpei_cpu);
set_cpei_target_cpu(new_cpei_cpu); set_cpei_target_cpu(new_cpei_cpu);
data = irq_get_irq_data(ia64_cpe_irq); data = irq_get_irq_data(ia64_cpe_irq);
...@@ -731,10 +726,10 @@ int __cpu_disable(void) ...@@ -731,10 +726,10 @@ int __cpu_disable(void)
return -EBUSY; return -EBUSY;
} }
cpu_clear(cpu, cpu_online_map); set_cpu_online(cpu, false);
if (migrate_platform_irqs(cpu)) { if (migrate_platform_irqs(cpu)) {
cpu_set(cpu, cpu_online_map); set_cpu_online(cpu, true);
return -EBUSY; return -EBUSY;
} }
......
...@@ -220,7 +220,8 @@ static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf) ...@@ -220,7 +220,8 @@ static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf)
ssize_t len; ssize_t len;
cpumask_t shared_cpu_map; cpumask_t shared_cpu_map;
cpus_and(shared_cpu_map, this_leaf->shared_cpu_map, cpu_online_map); cpumask_and(&shared_cpu_map,
&this_leaf->shared_cpu_map, cpu_online_mask);
len = cpumask_scnprintf(buf, NR_CPUS+1, &shared_cpu_map); len = cpumask_scnprintf(buf, NR_CPUS+1, &shared_cpu_map);
len += sprintf(buf+len, "\n"); len += sprintf(buf+len, "\n");
return len; return len;
......
...@@ -43,10 +43,6 @@ void evaluate_message(int tag); ...@@ -43,10 +43,6 @@ void evaluate_message(int tag);
/* Boot a secondary cpu */ /* Boot a secondary cpu */
void online_secondary(void); void online_secondary(void);
/* Call a function on a specified set of CPUs (may include this one). */
extern void on_each_cpu_mask(const struct cpumask *mask,
void (*func)(void *), void *info, bool wait);
/* Topology of the supervisor tile grid, and coordinates of boot processor */ /* Topology of the supervisor tile grid, and coordinates of boot processor */
extern HV_Topology smp_topology; extern HV_Topology smp_topology;
...@@ -91,9 +87,6 @@ void print_disabled_cpus(void); ...@@ -91,9 +87,6 @@ void print_disabled_cpus(void);
#else /* !CONFIG_SMP */ #else /* !CONFIG_SMP */
#define on_each_cpu_mask(mask, func, info, wait) \
do { if (cpumask_test_cpu(0, (mask))) func(info); } while (0)
#define smp_master_cpu 0 #define smp_master_cpu 0
#define smp_height 1 #define smp_height 1
#define smp_width 1 #define smp_width 1
......
...@@ -87,25 +87,6 @@ void send_IPI_allbutself(int tag) ...@@ -87,25 +87,6 @@ void send_IPI_allbutself(int tag)
send_IPI_many(&mask, tag); send_IPI_many(&mask, tag);
} }
/*
* Provide smp_call_function_mask, but also run function locally
* if specified in the mask.
*/
void on_each_cpu_mask(const struct cpumask *mask, void (*func)(void *),
void *info, bool wait)
{
int cpu = get_cpu();
smp_call_function_many(mask, func, info, wait);
if (cpumask_test_cpu(cpu, mask)) {
local_irq_disable();
func(info);
local_irq_enable();
}
put_cpu();
}
/* /*
* Functions related to starting/stopping cpus. * Functions related to starting/stopping cpus.
*/ */
......
...@@ -508,15 +508,6 @@ static void __init memblock_x86_reserve_range_setup_data(void) ...@@ -508,15 +508,6 @@ static void __init memblock_x86_reserve_range_setup_data(void)
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
static inline unsigned long long get_total_mem(void)
{
unsigned long long total;
total = max_pfn - min_low_pfn;
return total << PAGE_SHIFT;
}
/* /*
* Keep the crash kernel below this limit. On 32 bits earlier kernels * Keep the crash kernel below this limit. On 32 bits earlier kernels
* would limit the kernel to the low 512 MiB due to mapping restrictions. * would limit the kernel to the low 512 MiB due to mapping restrictions.
...@@ -535,7 +526,7 @@ static void __init reserve_crashkernel(void) ...@@ -535,7 +526,7 @@ static void __init reserve_crashkernel(void)
unsigned long long crash_size, crash_base; unsigned long long crash_size, crash_base;
int ret; int ret;
total_mem = get_total_mem(); total_mem = memblock_phys_mem_size();
ret = parse_crashkernel(boot_command_line, total_mem, ret = parse_crashkernel(boot_command_line, total_mem,
&crash_size, &crash_base); &crash_size, &crash_base);
......
This diff is collapsed.
...@@ -118,8 +118,8 @@ enum kcs_states { ...@@ -118,8 +118,8 @@ enum kcs_states {
#define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH #define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH
/* Timeouts in microseconds. */ /* Timeouts in microseconds. */
#define IBF_RETRY_TIMEOUT 1000000 #define IBF_RETRY_TIMEOUT 5000000
#define OBF_RETRY_TIMEOUT 1000000 #define OBF_RETRY_TIMEOUT 5000000
#define MAX_ERROR_RETRIES 10 #define MAX_ERROR_RETRIES 10
#define ERROR0_OBF_WAIT_JIFFIES (2*HZ) #define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
......
This diff is collapsed.
...@@ -170,7 +170,6 @@ struct smi_info { ...@@ -170,7 +170,6 @@ struct smi_info {
struct si_sm_handlers *handlers; struct si_sm_handlers *handlers;
enum si_type si_type; enum si_type si_type;
spinlock_t si_lock; spinlock_t si_lock;
spinlock_t msg_lock;
struct list_head xmit_msgs; struct list_head xmit_msgs;
struct list_head hp_xmit_msgs; struct list_head hp_xmit_msgs;
struct ipmi_smi_msg *curr_msg; struct ipmi_smi_msg *curr_msg;
...@@ -319,16 +318,8 @@ static int register_xaction_notifier(struct notifier_block *nb) ...@@ -319,16 +318,8 @@ static int register_xaction_notifier(struct notifier_block *nb)
static void deliver_recv_msg(struct smi_info *smi_info, static void deliver_recv_msg(struct smi_info *smi_info,
struct ipmi_smi_msg *msg) struct ipmi_smi_msg *msg)
{ {
/* Deliver the message to the upper layer with the lock /* Deliver the message to the upper layer. */
released. */
if (smi_info->run_to_completion) {
ipmi_smi_msg_received(smi_info->intf, msg);
} else {
spin_unlock(&(smi_info->si_lock));
ipmi_smi_msg_received(smi_info->intf, msg); ipmi_smi_msg_received(smi_info->intf, msg);
spin_lock(&(smi_info->si_lock));
}
} }
static void return_hosed_msg(struct smi_info *smi_info, int cCode) static void return_hosed_msg(struct smi_info *smi_info, int cCode)
...@@ -357,13 +348,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) ...@@ -357,13 +348,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
struct timeval t; struct timeval t;
#endif #endif
/*
* No need to save flags, we aleady have interrupts off and we
* already hold the SMI lock.
*/
if (!smi_info->run_to_completion)
spin_lock(&(smi_info->msg_lock));
/* Pick the high priority queue first. */ /* Pick the high priority queue first. */
if (!list_empty(&(smi_info->hp_xmit_msgs))) { if (!list_empty(&(smi_info->hp_xmit_msgs))) {
entry = smi_info->hp_xmit_msgs.next; entry = smi_info->hp_xmit_msgs.next;
...@@ -401,9 +385,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) ...@@ -401,9 +385,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
rv = SI_SM_CALL_WITHOUT_DELAY; rv = SI_SM_CALL_WITHOUT_DELAY;
} }
out: out:
if (!smi_info->run_to_completion)
spin_unlock(&(smi_info->msg_lock));
return rv; return rv;
} }
...@@ -480,9 +461,7 @@ static void handle_flags(struct smi_info *smi_info) ...@@ -480,9 +461,7 @@ static void handle_flags(struct smi_info *smi_info)
start_clear_flags(smi_info); start_clear_flags(smi_info);
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
spin_unlock(&(smi_info->si_lock));
ipmi_smi_watchdog_pretimeout(smi_info->intf); ipmi_smi_watchdog_pretimeout(smi_info->intf);
spin_lock(&(smi_info->si_lock));
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) { } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */ /* Messages available. */
smi_info->curr_msg = ipmi_alloc_smi_msg(); smi_info->curr_msg = ipmi_alloc_smi_msg();
...@@ -888,19 +867,6 @@ static void sender(void *send_info, ...@@ -888,19 +867,6 @@ static void sender(void *send_info,
printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec); printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif #endif
/*
* last_timeout_jiffies is updated here to avoid
* smi_timeout() handler passing very large time_diff
* value to smi_event_handler() that causes
* the send command to abort.
*/
smi_info->last_timeout_jiffies = jiffies;
mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
if (smi_info->thread)
wake_up_process(smi_info->thread);
if (smi_info->run_to_completion) { if (smi_info->run_to_completion) {
/* /*
* If we are running to completion, then throw it in * If we are running to completion, then throw it in
...@@ -923,16 +889,29 @@ static void sender(void *send_info, ...@@ -923,16 +889,29 @@ static void sender(void *send_info,
return; return;
} }
spin_lock_irqsave(&smi_info->msg_lock, flags); spin_lock_irqsave(&smi_info->si_lock, flags);
if (priority > 0) if (priority > 0)
list_add_tail(&msg->link, &smi_info->hp_xmit_msgs); list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
else else
list_add_tail(&msg->link, &smi_info->xmit_msgs); list_add_tail(&msg->link, &smi_info->xmit_msgs);
spin_unlock_irqrestore(&smi_info->msg_lock, flags);
spin_lock_irqsave(&smi_info->si_lock, flags); if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) /*
* last_timeout_jiffies is updated here to avoid
* smi_timeout() handler passing very large time_diff
* value to smi_event_handler() that causes
* the send command to abort.
*/
smi_info->last_timeout_jiffies = jiffies;
mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
if (smi_info->thread)
wake_up_process(smi_info->thread);
start_next_msg(smi_info); start_next_msg(smi_info);
smi_event_handler(smi_info, 0);
}
spin_unlock_irqrestore(&smi_info->si_lock, flags); spin_unlock_irqrestore(&smi_info->si_lock, flags);
} }
...@@ -1033,15 +1012,18 @@ static int ipmi_thread(void *data) ...@@ -1033,15 +1012,18 @@ static int ipmi_thread(void *data)
static void poll(void *send_info) static void poll(void *send_info)
{ {
struct smi_info *smi_info = send_info; struct smi_info *smi_info = send_info;
unsigned long flags; unsigned long flags = 0;
int run_to_completion = smi_info->run_to_completion;
/* /*
* Make sure there is some delay in the poll loop so we can * Make sure there is some delay in the poll loop so we can
* drive time forward and timeout things. * drive time forward and timeout things.
*/ */
udelay(10); udelay(10);
if (!run_to_completion)
spin_lock_irqsave(&smi_info->si_lock, flags); spin_lock_irqsave(&smi_info->si_lock, flags);
smi_event_handler(smi_info, 10); smi_event_handler(smi_info, 10);
if (!run_to_completion)
spin_unlock_irqrestore(&smi_info->si_lock, flags); spin_unlock_irqrestore(&smi_info->si_lock, flags);
} }
...@@ -1679,10 +1661,8 @@ static struct smi_info *smi_info_alloc(void) ...@@ -1679,10 +1661,8 @@ static struct smi_info *smi_info_alloc(void)
{ {
struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info) { if (info)
spin_lock_init(&info->si_lock); spin_lock_init(&info->si_lock);
spin_lock_init(&info->msg_lock);
}
return info; return info;
} }
......
...@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void) ...@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void)
msg.cmd = IPMI_WDOG_RESET_TIMER; msg.cmd = IPMI_WDOG_RESET_TIMER;
msg.data = NULL; msg.data = NULL;
msg.data_len = 0; msg.data_len = 0;
atomic_add(2, &panic_done_count);
rv = ipmi_request_supply_msgs(watchdog_user, rv = ipmi_request_supply_msgs(watchdog_user,
(struct ipmi_addr *) &addr, (struct ipmi_addr *) &addr,
0, 0,
...@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void) ...@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void)
&panic_halt_heartbeat_smi_msg, &panic_halt_heartbeat_smi_msg,
&panic_halt_heartbeat_recv_msg, &panic_halt_heartbeat_recv_msg,
1); 1);
if (!rv) if (rv)
atomic_add(2, &panic_done_count); atomic_sub(2, &panic_done_count);
} }
static struct ipmi_smi_msg panic_halt_smi_msg = { static struct ipmi_smi_msg panic_halt_smi_msg = {
...@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void) ...@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void)
/* Wait for the messages to be free. */ /* Wait for the messages to be free. */
while (atomic_read(&panic_done_count) != 0) while (atomic_read(&panic_done_count) != 0)
ipmi_poll_interface(watchdog_user); ipmi_poll_interface(watchdog_user);
atomic_add(2, &panic_done_count);
rv = i_ipmi_set_timeout(&panic_halt_smi_msg, rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
&panic_halt_recv_msg, &panic_halt_recv_msg,
&send_heartbeat_now); &send_heartbeat_now);
if (!rv) { if (rv) {
atomic_add(2, &panic_done_count); atomic_sub(2, &panic_done_count);
if (send_heartbeat_now)
panic_halt_ipmi_heartbeat();
} else
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"Unable to extend the watchdog timeout."); "Unable to extend the watchdog timeout.");
} else {
if (send_heartbeat_now)
panic_halt_ipmi_heartbeat();
}
while (atomic_read(&panic_done_count) != 0) while (atomic_read(&panic_done_count) != 0)
ipmi_poll_interface(watchdog_user); ipmi_poll_interface(watchdog_user);
} }
...@@ -1164,7 +1167,7 @@ static int wdog_reboot_handler(struct notifier_block *this, ...@@ -1164,7 +1167,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
if (code == SYS_POWER_OFF || code == SYS_HALT) { if (code == SYS_POWER_OFF || code == SYS_HALT) {
/* Disable the WDT if we are shutting down. */ /* Disable the WDT if we are shutting down. */
ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
panic_halt_ipmi_set_timeout(); ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
/* Set a long timer to let the reboot happens, but /* Set a long timer to let the reboot happens, but
reboot if it hangs, but only if the watchdog reboot if it hangs, but only if the watchdog
...@@ -1172,7 +1175,7 @@ static int wdog_reboot_handler(struct notifier_block *this, ...@@ -1172,7 +1175,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
timeout = 120; timeout = 120;
pretimeout = 0; pretimeout = 0;
ipmi_watchdog_state = WDOG_TIMEOUT_RESET; ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
panic_halt_ipmi_set_timeout(); ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
} }
} }
return NOTIFY_OK; return NOTIFY_OK;
......
...@@ -271,7 +271,7 @@ static int tosa_lcd_resume(struct spi_device *spi) ...@@ -271,7 +271,7 @@ static int tosa_lcd_resume(struct spi_device *spi)
} }
#else #else
#define tosa_lcd_suspend NULL #define tosa_lcd_suspend NULL
#define tosa_lcd_reume NULL #define tosa_lcd_resume NULL
#endif #endif
static struct spi_driver tosa_lcd_driver = { static struct spi_driver tosa_lcd_driver = {
......
...@@ -1385,9 +1385,22 @@ static void invalidate_bh_lru(void *arg) ...@@ -1385,9 +1385,22 @@ static void invalidate_bh_lru(void *arg)
put_cpu_var(bh_lrus); put_cpu_var(bh_lrus);
} }
static bool has_bh_in_lru(int cpu, void *dummy)
{
struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
int i;
for (i = 0; i < BH_LRU_SIZE; i++) {
if (b->bhs[i])
return 1;
}
return 0;
}
void invalidate_bh_lrus(void) void invalidate_bh_lrus(void)
{ {
on_each_cpu(invalidate_bh_lru, NULL, 1); on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
} }
EXPORT_SYMBOL_GPL(invalidate_bh_lrus); EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
......
...@@ -550,7 +550,7 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, ...@@ -550,7 +550,7 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
seq_put_decimal_ull(m, ' ', shared); seq_put_decimal_ull(m, ' ', shared);
seq_put_decimal_ull(m, ' ', text); seq_put_decimal_ull(m, ' ', text);
seq_put_decimal_ull(m, ' ', 0); seq_put_decimal_ull(m, ' ', 0);
seq_put_decimal_ull(m, ' ', text); seq_put_decimal_ull(m, ' ', data);
seq_put_decimal_ull(m, ' ', 0); seq_put_decimal_ull(m, ' ', 0);
seq_putc(m, '\n'); seq_putc(m, '\n');
......
...@@ -156,15 +156,15 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir, ...@@ -156,15 +156,15 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
if (!ptrace_may_access(task, PTRACE_MODE_READ)) if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out; goto out;
last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; last = &ns_entries[ARRAY_SIZE(ns_entries)];
for (entry = ns_entries; entry <= last; entry++) { for (entry = ns_entries; entry < last; entry++) {
if (strlen((*entry)->name) != len) if (strlen((*entry)->name) != len)
continue; continue;
if (!memcmp(dentry->d_name.name, (*entry)->name, len)) if (!memcmp(dentry->d_name.name, (*entry)->name, len))
break; break;
} }
error = ERR_PTR(-ENOENT); error = ERR_PTR(-ENOENT);
if (entry > last) if (entry == last)
goto out; goto out;
error = proc_ns_instantiate(dir, dentry, task, *entry); error = proc_ns_instantiate(dir, dentry, task, *entry);
......
...@@ -781,9 +781,6 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -781,9 +781,6 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
int err = 0; int err = 0;
pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); pagemap_entry_t pme = make_pme(PM_NOT_PRESENT);
if (pmd_trans_unstable(pmd))
return 0;
/* find the first VMA at or above 'addr' */ /* find the first VMA at or above 'addr' */
vma = find_vma(walk->mm, addr); vma = find_vma(walk->mm, addr);
spin_lock(&walk->mm->page_table_lock); spin_lock(&walk->mm->page_table_lock);
...@@ -802,6 +799,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -802,6 +799,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
return err; return err;
} }
if (pmd_trans_unstable(pmd))
return 0;
for (; addr != end; addr += PAGE_SIZE) { for (; addr != end; addr += PAGE_SIZE) {
/* check to see if we've left 'vma' behind /* check to see if we've left 'vma' behind
......
...@@ -810,11 +810,10 @@ static inline const struct cpumask *get_cpu_mask(unsigned int cpu) ...@@ -810,11 +810,10 @@ static inline const struct cpumask *get_cpu_mask(unsigned int cpu)
#else /* NR_CPUS > 1 */ #else /* NR_CPUS > 1 */
int __first_cpu(const cpumask_t *srcp); int __first_cpu(const cpumask_t *srcp);
int __next_cpu(int n, const cpumask_t *srcp); int __next_cpu(int n, const cpumask_t *srcp);
int __any_online_cpu(const cpumask_t *mask);
#define first_cpu(src) __first_cpu(&(src)) #define first_cpu(src) __first_cpu(&(src))
#define next_cpu(n, src) __next_cpu((n), &(src)) #define next_cpu(n, src) __next_cpu((n), &(src))
#define any_online_cpu(mask) __any_online_cpu(&(mask)) #define any_online_cpu(mask) cpumask_any_and(&mask, cpu_online_mask)
#define for_each_cpu_mask(cpu, mask) \ #define for_each_cpu_mask(cpu, mask) \
for ((cpu) = -1; \ for ((cpu) = -1; \
(cpu) = next_cpu((cpu), (mask)), \ (cpu) = next_cpu((cpu), (mask)), \
......
...@@ -954,7 +954,7 @@ extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new); ...@@ -954,7 +954,7 @@ extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new);
extern void truncate_setsize(struct inode *inode, loff_t newsize); extern void truncate_setsize(struct inode *inode, loff_t newsize);
extern int vmtruncate(struct inode *inode, loff_t offset); extern int vmtruncate(struct inode *inode, loff_t offset);
extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end); extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end);
void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
int truncate_inode_page(struct address_space *mapping, struct page *page); int truncate_inode_page(struct address_space *mapping, struct page *page);
int generic_error_remove_page(struct address_space *mapping, struct page *page); int generic_error_remove_page(struct address_space *mapping, struct page *page);
......
...@@ -33,6 +33,7 @@ struct pid_namespace { ...@@ -33,6 +33,7 @@ struct pid_namespace {
#endif #endif
gid_t pid_gid; gid_t pid_gid;
int hide_pid; int hide_pid;
int reboot; /* group exit code if this pidns was rebooted */
}; };
extern struct pid_namespace init_pid_ns; extern struct pid_namespace init_pid_ns;
...@@ -48,6 +49,7 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns) ...@@ -48,6 +49,7 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns)
extern struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *ns); extern struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *ns);
extern void free_pid_ns(struct kref *kref); extern void free_pid_ns(struct kref *kref);
extern void zap_pid_ns_processes(struct pid_namespace *pid_ns); extern void zap_pid_ns_processes(struct pid_namespace *pid_ns);
extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd);
static inline void put_pid_ns(struct pid_namespace *ns) static inline void put_pid_ns(struct pid_namespace *ns)
{ {
...@@ -75,11 +77,15 @@ static inline void put_pid_ns(struct pid_namespace *ns) ...@@ -75,11 +77,15 @@ static inline void put_pid_ns(struct pid_namespace *ns)
{ {
} }
static inline void zap_pid_ns_processes(struct pid_namespace *ns) static inline void zap_pid_ns_processes(struct pid_namespace *ns)
{ {
BUG(); BUG();
} }
static inline int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
{
return 0;
}
#endif /* CONFIG_PID_NS */ #endif /* CONFIG_PID_NS */
extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk); extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Copyright (C) 2001 Momchil Velikov * Copyright (C) 2001 Momchil Velikov
* Portions Copyright (C) 2001 Christoph Hellwig * Portions Copyright (C) 2001 Christoph Hellwig
* Copyright (C) 2006 Nick Piggin * Copyright (C) 2006 Nick Piggin
* Copyright (C) 2012 Konstantin Khlebnikov
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -257,4 +258,199 @@ static inline void radix_tree_preload_end(void) ...@@ -257,4 +258,199 @@ static inline void radix_tree_preload_end(void)
preempt_enable(); preempt_enable();
} }
/**
* struct radix_tree_iter - radix tree iterator state
*
* @index: index of current slot
* @next_index: next-to-last index for this chunk
* @tags: bit-mask for tag-iterating
*
* This radix tree iterator works in terms of "chunks" of slots. A chunk is a
* subinterval of slots contained within one radix tree leaf node. It is
* described by a pointer to its first slot and a struct radix_tree_iter
* which holds the chunk's position in the tree and its size. For tagged
* iteration radix_tree_iter also holds the slots' bit-mask for one chosen
* radix tree tag.
*/
struct radix_tree_iter {
unsigned long index;
unsigned long next_index;
unsigned long tags;
};
#define RADIX_TREE_ITER_TAG_MASK 0x00FF /* tag index in lower byte */
#define RADIX_TREE_ITER_TAGGED 0x0100 /* lookup tagged slots */
#define RADIX_TREE_ITER_CONTIG 0x0200 /* stop at first hole */
/**
* radix_tree_iter_init - initialize radix tree iterator
*
* @iter: pointer to iterator state
* @start: iteration starting index
* Returns: NULL
*/
static __always_inline void **
radix_tree_iter_init(struct radix_tree_iter *iter, unsigned long start)
{
/*
* Leave iter->tags uninitialized. radix_tree_next_chunk() will fill it
* in the case of a successful tagged chunk lookup. If the lookup was
* unsuccessful or non-tagged then nobody cares about ->tags.
*
* Set index to zero to bypass next_index overflow protection.
* See the comment in radix_tree_next_chunk() for details.
*/
iter->index = 0;
iter->next_index = start;
return NULL;
}
/**
* radix_tree_next_chunk - find next chunk of slots for iteration
*
* @root: radix tree root
* @iter: iterator state
* @flags: RADIX_TREE_ITER_* flags and tag index
* Returns: pointer to chunk first slot, or NULL if there no more left
*
* This function looks up the next chunk in the radix tree starting from
* @iter->next_index. It returns a pointer to the chunk's first slot.
* Also it fills @iter with data about chunk: position in the tree (index),
* its end (next_index), and constructs a bit mask for tagged iterating (tags).
*/
void **radix_tree_next_chunk(struct radix_tree_root *root,
struct radix_tree_iter *iter, unsigned flags);
/**
* radix_tree_chunk_size - get current chunk size
*
* @iter: pointer to radix tree iterator
* Returns: current chunk size
*/
static __always_inline unsigned
radix_tree_chunk_size(struct radix_tree_iter *iter)
{
return iter->next_index - iter->index;
}
/**
* radix_tree_next_slot - find next slot in chunk
*
* @slot: pointer to current slot
* @iter: pointer to interator state
* @flags: RADIX_TREE_ITER_*, should be constant
* Returns: pointer to next slot, or NULL if there no more left
*
* This function updates @iter->index in the case of a successful lookup.
* For tagged lookup it also eats @iter->tags.
*/
static __always_inline void **
radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags)
{
if (flags & RADIX_TREE_ITER_TAGGED) {
iter->tags >>= 1;
if (likely(iter->tags & 1ul)) {
iter->index++;
return slot + 1;
}
if (!(flags & RADIX_TREE_ITER_CONTIG) && likely(iter->tags)) {
unsigned offset = __ffs(iter->tags);
iter->tags >>= offset;
iter->index += offset + 1;
return slot + offset + 1;
}
} else {
unsigned size = radix_tree_chunk_size(iter) - 1;
while (size--) {
slot++;
iter->index++;
if (likely(*slot))
return slot;
if (flags & RADIX_TREE_ITER_CONTIG)
break;
}
}
return NULL;
}
/**
* radix_tree_for_each_chunk - iterate over chunks
*
* @slot: the void** variable for pointer to chunk first slot
* @root: the struct radix_tree_root pointer
* @iter: the struct radix_tree_iter pointer
* @start: iteration starting index
* @flags: RADIX_TREE_ITER_* and tag index
*
* Locks can be released and reacquired between iterations.
*/
#define radix_tree_for_each_chunk(slot, root, iter, start, flags) \
for (slot = radix_tree_iter_init(iter, start) ; \
(slot = radix_tree_next_chunk(root, iter, flags)) ;)
/**
* radix_tree_for_each_chunk_slot - iterate over slots in one chunk
*
* @slot: the void** variable, at the beginning points to chunk first slot
* @iter: the struct radix_tree_iter pointer
* @flags: RADIX_TREE_ITER_*, should be constant
*
* This macro is designed to be nested inside radix_tree_for_each_chunk().
* @slot points to the radix tree slot, @iter->index contains its index.
*/
#define radix_tree_for_each_chunk_slot(slot, iter, flags) \
for (; slot ; slot = radix_tree_next_slot(slot, iter, flags))
/**
* radix_tree_for_each_slot - iterate over non-empty slots
*
* @slot: the void** variable for pointer to slot
* @root: the struct radix_tree_root pointer
* @iter: the struct radix_tree_iter pointer
* @start: iteration starting index
*
* @slot points to radix tree slot, @iter->index contains its index.
*/
#define radix_tree_for_each_slot(slot, root, iter, start) \
for (slot = radix_tree_iter_init(iter, start) ; \
slot || (slot = radix_tree_next_chunk(root, iter, 0)) ; \
slot = radix_tree_next_slot(slot, iter, 0))
/**
* radix_tree_for_each_contig - iterate over contiguous slots
*
* @slot: the void** variable for pointer to slot
* @root: the struct radix_tree_root pointer
* @iter: the struct radix_tree_iter pointer
* @start: iteration starting index
*
* @slot points to radix tree slot, @iter->index contains its index.
*/
#define radix_tree_for_each_contig(slot, root, iter, start) \
for (slot = radix_tree_iter_init(iter, start) ; \
slot || (slot = radix_tree_next_chunk(root, iter, \
RADIX_TREE_ITER_CONTIG)) ; \
slot = radix_tree_next_slot(slot, iter, \
RADIX_TREE_ITER_CONTIG))
/**
* radix_tree_for_each_tagged - iterate over tagged slots
*
* @slot: the void** variable for pointer to slot
* @root: the struct radix_tree_root pointer
* @iter: the struct radix_tree_iter pointer
* @start: iteration starting index
* @tag: tag index
*
* @slot points to radix tree slot, @iter->index contains its index.
*/
#define radix_tree_for_each_tagged(slot, root, iter, start, tag) \
for (slot = radix_tree_iter_init(iter, start) ; \
slot || (slot = radix_tree_next_chunk(root, iter, \
RADIX_TREE_ITER_TAGGED | tag)) ; \
slot = radix_tree_next_slot(slot, iter, \
RADIX_TREE_ITER_TAGGED))
#endif /* _LINUX_RADIX_TREE_H */ #endif /* _LINUX_RADIX_TREE_H */
...@@ -101,6 +101,22 @@ static inline void call_function_init(void) { } ...@@ -101,6 +101,22 @@ static inline void call_function_init(void) { }
*/ */
int on_each_cpu(smp_call_func_t func, void *info, int wait); int on_each_cpu(smp_call_func_t func, void *info, int wait);
/*
* Call a function on processors specified by mask, which might include
* the local one.
*/
void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
void *info, bool wait);
/*
* Call a function on each processor for which the supplied function
* cond_func returns a positive value. This may include the local
* processor.
*/
void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
smp_call_func_t func, void *info, bool wait,
gfp_t gfp_flags);
/* /*
* Mark the boot cpu "online" so that it can call console drivers in * Mark the boot cpu "online" so that it can call console drivers in
* printk() and can access its per-cpu storage. * printk() and can access its per-cpu storage.
...@@ -132,6 +148,36 @@ static inline int up_smp_call_function(smp_call_func_t func, void *info) ...@@ -132,6 +148,36 @@ static inline int up_smp_call_function(smp_call_func_t func, void *info)
local_irq_enable(); \ local_irq_enable(); \
0; \ 0; \
}) })
/*
* Note we still need to test the mask even for UP
* because we actually can get an empty mask from
* code that on SMP might call us without the local
* CPU in the mask.
*/
#define on_each_cpu_mask(mask, func, info, wait) \
do { \
if (cpumask_test_cpu(0, (mask))) { \
local_irq_disable(); \
(func)(info); \
local_irq_enable(); \
} \
} while (0)
/*
* Preemption is disabled here to make sure the cond_func is called under the
* same condtions in UP and SMP.
*/
#define on_each_cpu_cond(cond_func, func, info, wait, gfp_flags)\
do { \
void *__info = (info); \
preempt_disable(); \
if ((cond_func)(0, __info)) { \
local_irq_disable(); \
(func)(__info); \
local_irq_enable(); \
} \
preempt_enable(); \
} while (0)
static inline void smp_send_reschedule(int cpu) { } static inline void smp_send_reschedule(int cpu) { }
#define num_booting_cpus() 1 #define num_booting_cpus() 1
#define smp_prepare_boot_cpu() do {} while (0) #define smp_prepare_boot_cpu() do {} while (0)
......
...@@ -21,6 +21,9 @@ struct bio; ...@@ -21,6 +21,9 @@ struct bio;
#define SWAP_FLAG_PRIO_SHIFT 0 #define SWAP_FLAG_PRIO_SHIFT 0
#define SWAP_FLAG_DISCARD 0x10000 /* discard swap cluster after use */ #define SWAP_FLAG_DISCARD 0x10000 /* discard swap cluster after use */
#define SWAP_FLAGS_VALID (SWAP_FLAG_PRIO_MASK | SWAP_FLAG_PREFER | \
SWAP_FLAG_DISCARD)
static inline int current_is_kswapd(void) static inline int current_is_kswapd(void)
{ {
return current->flags & PF_KSWAPD; return current->flags & PF_KSWAPD;
......
...@@ -1358,6 +1358,10 @@ static int __init parse_crashkernel_simple(char *cmdline, ...@@ -1358,6 +1358,10 @@ static int __init parse_crashkernel_simple(char *cmdline,
if (*cur == '@') if (*cur == '@')
*crash_base = memparse(cur+1, &cur); *crash_base = memparse(cur+1, &cur);
else if (*cur != ' ' && *cur != '\0') {
pr_warning("crashkernel: unrecognized char\n");
return -EINVAL;
}
return 0; return 0;
} }
...@@ -1461,7 +1465,9 @@ static int __init crash_save_vmcoreinfo_init(void) ...@@ -1461,7 +1465,9 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_SYMBOL(init_uts_ns); VMCOREINFO_SYMBOL(init_uts_ns);
VMCOREINFO_SYMBOL(node_online_map); VMCOREINFO_SYMBOL(node_online_map);
#ifdef CONFIG_MMU
VMCOREINFO_SYMBOL(swapper_pg_dir); VMCOREINFO_SYMBOL(swapper_pg_dir);
#endif
VMCOREINFO_SYMBOL(_stext); VMCOREINFO_SYMBOL(_stext);
VMCOREINFO_SYMBOL(vmlist); VMCOREINFO_SYMBOL(vmlist);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/acct.h> #include <linux/acct.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/reboot.h>
#define BITS_PER_PAGE (PAGE_SIZE*8) #define BITS_PER_PAGE (PAGE_SIZE*8)
...@@ -183,6 +184,9 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) ...@@ -183,6 +184,9 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
rc = sys_wait4(-1, NULL, __WALL, NULL); rc = sys_wait4(-1, NULL, __WALL, NULL);
} while (rc != -ECHILD); } while (rc != -ECHILD);
if (pid_ns->reboot)
current->signal->group_exit_code = pid_ns->reboot;
acct_exit_ns(pid_ns); acct_exit_ns(pid_ns);
return; return;
} }
...@@ -217,6 +221,35 @@ static struct ctl_table pid_ns_ctl_table[] = { ...@@ -217,6 +221,35 @@ static struct ctl_table pid_ns_ctl_table[] = {
static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } }; static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } };
int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
{
if (pid_ns == &init_pid_ns)
return 0;
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART2:
case LINUX_REBOOT_CMD_RESTART:
pid_ns->reboot = SIGHUP;
break;
case LINUX_REBOOT_CMD_POWER_OFF:
case LINUX_REBOOT_CMD_HALT:
pid_ns->reboot = SIGINT;
break;
default:
return -EINVAL;
}
read_lock(&tasklist_lock);
force_sig(SIGKILL, pid_ns->child_reaper);
read_unlock(&tasklist_lock);
do_exit(0);
/* Not reached */
return 0;
}
static __init int pid_namespaces_init(void) static __init int pid_namespaces_init(void)
{ {
pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC); pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC);
......
...@@ -701,3 +701,93 @@ int on_each_cpu(void (*func) (void *info), void *info, int wait) ...@@ -701,3 +701,93 @@ int on_each_cpu(void (*func) (void *info), void *info, int wait)
return ret; return ret;
} }
EXPORT_SYMBOL(on_each_cpu); EXPORT_SYMBOL(on_each_cpu);
/**
* on_each_cpu_mask(): Run a function on processors specified by
* cpumask, which may include the local processor.
* @mask: The set of cpus to run on (only runs on online subset).
* @func: The function to run. This must be fast and non-blocking.
* @info: An arbitrary pointer to pass to the function.
* @wait: If true, wait (atomically) until function has completed
* on other CPUs.
*
* If @wait is true, then returns once @func has returned.
*
* You must not call this function with disabled interrupts or
* from a hardware interrupt handler or from a bottom half handler.
*/
void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
void *info, bool wait)
{
int cpu = get_cpu();
smp_call_function_many(mask, func, info, wait);
if (cpumask_test_cpu(cpu, mask)) {
local_irq_disable();
func(info);
local_irq_enable();
}
put_cpu();
}
EXPORT_SYMBOL(on_each_cpu_mask);
/*
* on_each_cpu_cond(): Call a function on each processor for which
* the supplied function cond_func returns true, optionally waiting
* for all the required CPUs to finish. This may include the local
* processor.
* @cond_func: A callback function that is passed a cpu id and
* the the info parameter. The function is called
* with preemption disabled. The function should
* return a blooean value indicating whether to IPI
* the specified CPU.
* @func: The function to run on all applicable CPUs.
* This must be fast and non-blocking.
* @info: An arbitrary pointer to pass to both functions.
* @wait: If true, wait (atomically) until function has
* completed on other CPUs.
* @gfp_flags: GFP flags to use when allocating the cpumask
* used internally by the function.
*
* The function might sleep if the GFP flags indicates a non
* atomic allocation is allowed.
*
* Preemption is disabled to protect against CPUs going offline but not online.
* CPUs going online during the call will not be seen or sent an IPI.
*
* You must not call this function with disabled interrupts or
* from a hardware interrupt handler or from a bottom half handler.
*/
void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
smp_call_func_t func, void *info, bool wait,
gfp_t gfp_flags)
{
cpumask_var_t cpus;
int cpu, ret;
might_sleep_if(gfp_flags & __GFP_WAIT);
if (likely(zalloc_cpumask_var(&cpus, (gfp_flags|__GFP_NOWARN)))) {
preempt_disable();
for_each_online_cpu(cpu)
if (cond_func(cpu, info))
cpumask_set_cpu(cpu, cpus);
on_each_cpu_mask(cpus, func, info, wait);
preempt_enable();
free_cpumask_var(cpus);
} else {
/*
* No free cpumask, bother. No matter, we'll
* just have to IPI them one by one.
*/
preempt_disable();
for_each_online_cpu(cpu)
if (cond_func(cpu, info)) {
ret = smp_call_function_single(cpu, func,
info, wait);
WARN_ON_ONCE(!ret);
}
preempt_enable();
}
}
EXPORT_SYMBOL(on_each_cpu_cond);
...@@ -444,6 +444,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, ...@@ -444,6 +444,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
magic2 != LINUX_REBOOT_MAGIC2C)) magic2 != LINUX_REBOOT_MAGIC2C))
return -EINVAL; return -EINVAL;
/*
* If pid namespaces are enabled and the current task is in a child
* pid_namespace, the command is handled by reboot_pid_ns() which will
* call do_exit().
*/
ret = reboot_pid_ns(task_active_pid_ns(current), cmd);
if (ret)
return ret;
/* Instead of trying to make the power_off code look like /* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way. * halt when pm_power_off is not set do it the easy way.
*/ */
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/bitmap.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
...@@ -2395,9 +2396,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, ...@@ -2395,9 +2396,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
} }
} }
while (val_a <= val_b) bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);
set_bit(val_a++, tmp_bitmap);
first = 0; first = 0;
proc_skip_char(&kbuf, &left, '\n'); proc_skip_char(&kbuf, &left, '\n');
} }
...@@ -2440,8 +2439,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, ...@@ -2440,8 +2439,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
if (*ppos) if (*ppos)
bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len); bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);
else else
memcpy(bitmap, tmp_bitmap, bitmap_copy(bitmap, tmp_bitmap, bitmap_len);
BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long));
} }
kfree(tmp_bitmap); kfree(tmp_bitmap);
*lenp -= left; *lenp -= left;
......
...@@ -88,6 +88,10 @@ choice ...@@ -88,6 +88,10 @@ choice
prompt "CRC32 implementation" prompt "CRC32 implementation"
depends on CRC32 depends on CRC32
default CRC32_SLICEBY8 default CRC32_SLICEBY8
help
This option allows a kernel builder to override the default choice
of CRC32 algorithm. Choose the default ("slice by 8") unless you
know that you need one of the others.
config CRC32_SLICEBY8 config CRC32_SLICEBY8
bool "Slice by 8 bytes" bool "Slice by 8 bytes"
......
...@@ -26,18 +26,6 @@ int __next_cpu_nr(int n, const cpumask_t *srcp) ...@@ -26,18 +26,6 @@ int __next_cpu_nr(int n, const cpumask_t *srcp)
EXPORT_SYMBOL(__next_cpu_nr); EXPORT_SYMBOL(__next_cpu_nr);
#endif #endif
int __any_online_cpu(const cpumask_t *mask)
{
int cpu;
for_each_cpu(cpu, mask) {
if (cpu_online(cpu))
break;
}
return cpu;
}
EXPORT_SYMBOL(__any_online_cpu);
/** /**
* cpumask_next_and - get the next cpu in *src1p & *src2p * cpumask_next_and - get the next cpu in *src1p & *src2p
* @n: the cpu prior to the place to search (ie. return will be > @n) * @n: the cpu prior to the place to search (ie. return will be > @n)
......
This diff is collapsed.
...@@ -813,20 +813,19 @@ EXPORT_SYMBOL(find_or_create_page); ...@@ -813,20 +813,19 @@ EXPORT_SYMBOL(find_or_create_page);
unsigned find_get_pages(struct address_space *mapping, pgoff_t start, unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
unsigned int nr_pages, struct page **pages) unsigned int nr_pages, struct page **pages)
{ {
unsigned int i; struct radix_tree_iter iter;
unsigned int ret; void **slot;
unsigned int nr_found, nr_skip; unsigned ret = 0;
if (unlikely(!nr_pages))
return 0;
rcu_read_lock(); rcu_read_lock();
restart: restart:
nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
(void ***)pages, NULL, start, nr_pages);
ret = 0;
nr_skip = 0;
for (i = 0; i < nr_found; i++) {
struct page *page; struct page *page;
repeat: repeat:
page = radix_tree_deref_slot((void **)pages[i]); page = radix_tree_deref_slot(slot);
if (unlikely(!page)) if (unlikely(!page))
continue; continue;
...@@ -837,7 +836,7 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, ...@@ -837,7 +836,7 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
* when entry at index 0 moves out of or back * when entry at index 0 moves out of or back
* to root: none yet gotten, safe to restart. * to root: none yet gotten, safe to restart.
*/ */
WARN_ON(start | i); WARN_ON(iter.index);
goto restart; goto restart;
} }
/* /*
...@@ -845,7 +844,6 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, ...@@ -845,7 +844,6 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
* here as an exceptional entry: so skip over it - * here as an exceptional entry: so skip over it -
* we only reach this from invalidate_mapping_pages(). * we only reach this from invalidate_mapping_pages().
*/ */
nr_skip++;
continue; continue;
} }
...@@ -853,21 +851,16 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, ...@@ -853,21 +851,16 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
goto repeat; goto repeat;
/* Has the page moved? */ /* Has the page moved? */
if (unlikely(page != *((void **)pages[i]))) { if (unlikely(page != *slot)) {
page_cache_release(page); page_cache_release(page);
goto repeat; goto repeat;
} }
pages[ret] = page; pages[ret] = page;
ret++; if (++ret == nr_pages)
break;
} }
/*
* If all entries were removed before we could secure them,
* try again, because callers stop trying once 0 is returned.
*/
if (unlikely(!ret && nr_found > nr_skip))
goto restart;
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
} }
...@@ -887,21 +880,22 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, ...@@ -887,21 +880,22 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
unsigned int nr_pages, struct page **pages) unsigned int nr_pages, struct page **pages)
{ {
unsigned int i; struct radix_tree_iter iter;
unsigned int ret; void **slot;
unsigned int nr_found; unsigned int ret = 0;
if (unlikely(!nr_pages))
return 0;
rcu_read_lock(); rcu_read_lock();
restart: restart:
nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) {
(void ***)pages, NULL, index, nr_pages);
ret = 0;
for (i = 0; i < nr_found; i++) {
struct page *page; struct page *page;
repeat: repeat:
page = radix_tree_deref_slot((void **)pages[i]); page = radix_tree_deref_slot(slot);
/* The hole, there no reason to continue */
if (unlikely(!page)) if (unlikely(!page))
continue; break;
if (radix_tree_exception(page)) { if (radix_tree_exception(page)) {
if (radix_tree_deref_retry(page)) { if (radix_tree_deref_retry(page)) {
...@@ -924,7 +918,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, ...@@ -924,7 +918,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
goto repeat; goto repeat;
/* Has the page moved? */ /* Has the page moved? */
if (unlikely(page != *((void **)pages[i]))) { if (unlikely(page != *slot)) {
page_cache_release(page); page_cache_release(page);
goto repeat; goto repeat;
} }
...@@ -934,14 +928,14 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, ...@@ -934,14 +928,14 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
* otherwise we can get both false positives and false * otherwise we can get both false positives and false
* negatives, which is just confusing to the caller. * negatives, which is just confusing to the caller.
*/ */
if (page->mapping == NULL || page->index != index) { if (page->mapping == NULL || page->index != iter.index) {
page_cache_release(page); page_cache_release(page);
break; break;
} }
pages[ret] = page; pages[ret] = page;
ret++; if (++ret == nr_pages)
index++; break;
} }
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
...@@ -962,19 +956,20 @@ EXPORT_SYMBOL(find_get_pages_contig); ...@@ -962,19 +956,20 @@ EXPORT_SYMBOL(find_get_pages_contig);
unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
int tag, unsigned int nr_pages, struct page **pages) int tag, unsigned int nr_pages, struct page **pages)
{ {
unsigned int i; struct radix_tree_iter iter;
unsigned int ret; void **slot;
unsigned int nr_found; unsigned ret = 0;
if (unlikely(!nr_pages))
return 0;
rcu_read_lock(); rcu_read_lock();
restart: restart:
nr_found = radix_tree_gang_lookup_tag_slot(&mapping->page_tree, radix_tree_for_each_tagged(slot, &mapping->page_tree,
(void ***)pages, *index, nr_pages, tag); &iter, *index, tag) {
ret = 0;
for (i = 0; i < nr_found; i++) {
struct page *page; struct page *page;
repeat: repeat:
page = radix_tree_deref_slot((void **)pages[i]); page = radix_tree_deref_slot(slot);
if (unlikely(!page)) if (unlikely(!page))
continue; continue;
...@@ -998,21 +993,16 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, ...@@ -998,21 +993,16 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
goto repeat; goto repeat;
/* Has the page moved? */ /* Has the page moved? */
if (unlikely(page != *((void **)pages[i]))) { if (unlikely(page != *slot)) {
page_cache_release(page); page_cache_release(page);
goto repeat; goto repeat;
} }
pages[ret] = page; pages[ret] = page;
ret++; if (++ret == nr_pages)
break;
} }
/*
* If all entries were removed before we could secure them,
* try again, because callers stop trying once 0 is returned.
*/
if (unlikely(!ret && nr_found))
goto restart;
rcu_read_unlock(); rcu_read_unlock();
if (ret) if (ret)
......
...@@ -5306,6 +5306,8 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd, ...@@ -5306,6 +5306,8 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
return 0; return 0;
} }
if (pmd_trans_unstable(pmd))
return 0;
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
for (; addr != end; pte++, addr += PAGE_SIZE) for (; addr != end; pte++, addr += PAGE_SIZE)
if (get_mctgt_type(vma, addr, *pte, NULL)) if (get_mctgt_type(vma, addr, *pte, NULL))
...@@ -5502,6 +5504,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd, ...@@ -5502,6 +5504,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
return 0; return 0;
} }
if (pmd_trans_unstable(pmd))
return 0;
retry: retry:
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
for (; addr != end; addr += PAGE_SIZE) { for (; addr != end; addr += PAGE_SIZE) {
......
...@@ -1161,11 +1161,47 @@ void drain_local_pages(void *arg) ...@@ -1161,11 +1161,47 @@ void drain_local_pages(void *arg)
} }
/* /*
* Spill all the per-cpu pages from all CPUs back into the buddy allocator * Spill all the per-cpu pages from all CPUs back into the buddy allocator.
*
* Note that this code is protected against sending an IPI to an offline
* CPU but does not guarantee sending an IPI to newly hotplugged CPUs:
* on_each_cpu_mask() blocks hotplug and won't talk to offlined CPUs but
* nothing keeps CPUs from showing up after we populated the cpumask and
* before the call to on_each_cpu_mask().
*/ */
void drain_all_pages(void) void drain_all_pages(void)
{ {
on_each_cpu(drain_local_pages, NULL, 1); int cpu;
struct per_cpu_pageset *pcp;
struct zone *zone;
/*
* Allocate in the BSS so we wont require allocation in
* direct reclaim path for CONFIG_CPUMASK_OFFSTACK=y
*/
static cpumask_t cpus_with_pcps;
/*
* We don't care about racing with CPU hotplug event
* as offline notification will cause the notified
* cpu to drain that CPU pcps and on_each_cpu_mask
* disables preemption as part of its processing
*/
for_each_online_cpu(cpu) {
bool has_pcps = false;
for_each_populated_zone(zone) {
pcp = per_cpu_ptr(zone->pageset, cpu);
if (pcp->pcp.count) {
has_pcps = true;
break;
}
}
if (has_pcps)
cpumask_set_cpu(cpu, &cpus_with_pcps);
else
cpumask_clear_cpu(cpu, &cpus_with_pcps);
}
on_each_cpu_mask(&cpus_with_pcps, drain_local_pages, NULL, 1);
} }
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
...@@ -2308,6 +2344,10 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, ...@@ -2308,6 +2344,10 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
if (oom_killer_disabled) if (oom_killer_disabled)
goto nopage; goto nopage;
/* Coredumps can quickly deplete all memory reserves */
if ((current->flags & PF_DUMPCORE) &&
!(gfp_mask & __GFP_NOFAIL))
goto nopage;
page = __alloc_pages_may_oom(gfp_mask, order, page = __alloc_pages_may_oom(gfp_mask, order,
zonelist, high_zoneidx, zonelist, high_zoneidx,
nodemask, preferred_zone, nodemask, preferred_zone,
......
...@@ -2035,9 +2035,17 @@ static void flush_cpu_slab(void *d) ...@@ -2035,9 +2035,17 @@ static void flush_cpu_slab(void *d)
__flush_cpu_slab(s, smp_processor_id()); __flush_cpu_slab(s, smp_processor_id());
} }
static bool has_cpu_slab(int cpu, void *info)
{
struct kmem_cache *s = info;
struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
return !!(c->page);
}
static void flush_all(struct kmem_cache *s) static void flush_all(struct kmem_cache *s)
{ {
on_each_cpu(flush_cpu_slab, s, 1); on_each_cpu_cond(has_cpu_slab, flush_cpu_slab, s, 1, GFP_ATOMIC);
} }
/* /*
......
...@@ -2022,6 +2022,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) ...@@ -2022,6 +2022,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
struct page *page = NULL; struct page *page = NULL;
struct inode *inode = NULL; struct inode *inode = NULL;
if (swap_flags & ~SWAP_FLAGS_VALID)
return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -626,3 +626,43 @@ int vmtruncate_range(struct inode *inode, loff_t lstart, loff_t lend) ...@@ -626,3 +626,43 @@ int vmtruncate_range(struct inode *inode, loff_t lstart, loff_t lend)
return 0; return 0;
} }
/**
* truncate_pagecache_range - unmap and remove pagecache that is hole-punched
* @inode: inode
* @lstart: offset of beginning of hole
* @lend: offset of last byte of hole
*
* This function should typically be called before the filesystem
* releases resources associated with the freed range (eg. deallocates
* blocks). This way, pagecache will always stay logically coherent
* with on-disk format, and the filesystem would not have to deal with
* situations such as writepage being called for a page that has already
* had its underlying blocks deallocated.
*/
void truncate_pagecache_range(struct inode *inode, loff_t lstart, loff_t lend)
{
struct address_space *mapping = inode->i_mapping;
loff_t unmap_start = round_up(lstart, PAGE_SIZE);
loff_t unmap_end = round_down(1 + lend, PAGE_SIZE) - 1;
/*
* This rounding is currently just for example: unmap_mapping_range
* expands its hole outwards, whereas we want it to contract the hole
* inwards. However, existing callers of truncate_pagecache_range are
* doing their own page rounding first; and truncate_inode_pages_range
* currently BUGs if lend is not pagealigned-1 (it handles partial
* page at start of hole, but not partial page at end of hole). Note
* unmap_mapping_range allows holelen 0 for all, and we allow lend -1.
*/
/*
* Unlike in truncate_pagecache, unmap_mapping_range is called only
* once (before truncating pagecache), and without "even_cows" flag:
* hole-punching should not remove private COWed pages from the hole.
*/
if ((u64)unmap_end > (u64)unmap_start)
unmap_mapping_range(mapping, unmap_start,
1 + unmap_end - unmap_start, 0);
truncate_inode_pages_range(mapping, lstart, lend);
}
EXPORT_SYMBOL(truncate_pagecache_range);
TARGETS = breakpoints TARGETS = breakpoints vm
all: all:
for TARGET in $(TARGETS); do \ for TARGET in $(TARGETS); do \
make -C $$TARGET; \ make -C $$TARGET; \
done; done;
run_tests: all
for TARGET in $(TARGETS); do \
make -C $$TARGET run_tests; \
done;
clean: clean:
for TARGET in $(TARGETS); do \ for TARGET in $(TARGETS); do \
make -C $$TARGET clean; \ make -C $$TARGET clean; \
......
...@@ -11,10 +11,13 @@ endif ...@@ -11,10 +11,13 @@ endif
all: all:
ifeq ($(ARCH),x86) ifeq ($(ARCH),x86)
gcc breakpoint_test.c -o run_test gcc breakpoint_test.c -o breakpoint_test
else else
echo "Not an x86 target, can't build breakpoints selftests" echo "Not an x86 target, can't build breakpoints selftests"
endif endif
run_tests:
./breakpoint_test
clean: clean:
rm -fr run_test rm -fr breakpoint_test
#!/bin/bash
TARGETS=breakpoints
for TARGET in $TARGETS
do
$TARGET/run_test
done
# Makefile for vm selftests
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall -Wextra
all: hugepage-mmap hugepage-shm map_hugetlb
%: %.c
$(CC) $(CFLAGS) -o $@ $^
run_tests: all
/bin/sh ./run_vmtests
clean:
$(RM) hugepage-mmap hugepage-shm map_hugetlb
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h> #include <fcntl.h>
#define FILE_NAME "/mnt/hugepagefile" #define FILE_NAME "huge/hugepagefile"
#define LENGTH (256UL*1024*1024) #define LENGTH (256UL*1024*1024)
#define PROTECTION (PROT_READ | PROT_WRITE) #define PROTECTION (PROT_READ | PROT_WRITE)
...@@ -48,7 +48,7 @@ static void write_bytes(char *addr) ...@@ -48,7 +48,7 @@ static void write_bytes(char *addr)
*(addr + i) = (char)i; *(addr + i) = (char)i;
} }
static void read_bytes(char *addr) static int read_bytes(char *addr)
{ {
unsigned long i; unsigned long i;
...@@ -56,14 +56,15 @@ static void read_bytes(char *addr) ...@@ -56,14 +56,15 @@ static void read_bytes(char *addr)
for (i = 0; i < LENGTH; i++) for (i = 0; i < LENGTH; i++)
if (*(addr + i) != (char)i) { if (*(addr + i) != (char)i) {
printf("Mismatch at %lu\n", i); printf("Mismatch at %lu\n", i);
break; return 1;
} }
return 0;
} }
int main(void) int main(void)
{ {
void *addr; void *addr;
int fd; int fd, ret;
fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755); fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
if (fd < 0) { if (fd < 0) {
...@@ -81,11 +82,11 @@ int main(void) ...@@ -81,11 +82,11 @@ int main(void)
printf("Returned address is %p\n", addr); printf("Returned address is %p\n", addr);
check_bytes(addr); check_bytes(addr);
write_bytes(addr); write_bytes(addr);
read_bytes(addr); ret = read_bytes(addr);
munmap(addr, LENGTH); munmap(addr, LENGTH);
close(fd); close(fd);
unlink(FILE_NAME); unlink(FILE_NAME);
return 0; return ret;
} }
...@@ -57,8 +57,8 @@ int main(void) ...@@ -57,8 +57,8 @@ int main(void)
unsigned long i; unsigned long i;
char *shmaddr; char *shmaddr;
if ((shmid = shmget(2, LENGTH, shmid = shmget(2, LENGTH, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) { if (shmid < 0) {
perror("shmget"); perror("shmget");
exit(1); exit(1);
} }
...@@ -82,14 +82,16 @@ int main(void) ...@@ -82,14 +82,16 @@ int main(void)
dprintf("Starting the Check..."); dprintf("Starting the Check...");
for (i = 0; i < LENGTH; i++) for (i = 0; i < LENGTH; i++)
if (shmaddr[i] != (char)i) if (shmaddr[i] != (char)i) {
printf("\nIndex %lu mismatched\n", i); printf("\nIndex %lu mismatched\n", i);
exit(3);
}
dprintf("Done.\n"); dprintf("Done.\n");
if (shmdt((const void *)shmaddr) != 0) { if (shmdt((const void *)shmaddr) != 0) {
perror("Detach failure"); perror("Detach failure");
shmctl(shmid, IPC_RMID, NULL); shmctl(shmid, IPC_RMID, NULL);
exit(3); exit(4);
} }
shmctl(shmid, IPC_RMID, NULL); shmctl(shmid, IPC_RMID, NULL);
......
...@@ -44,7 +44,7 @@ static void write_bytes(char *addr) ...@@ -44,7 +44,7 @@ static void write_bytes(char *addr)
*(addr + i) = (char)i; *(addr + i) = (char)i;
} }
static void read_bytes(char *addr) static int read_bytes(char *addr)
{ {
unsigned long i; unsigned long i;
...@@ -52,13 +52,15 @@ static void read_bytes(char *addr) ...@@ -52,13 +52,15 @@ static void read_bytes(char *addr)
for (i = 0; i < LENGTH; i++) for (i = 0; i < LENGTH; i++)
if (*(addr + i) != (char)i) { if (*(addr + i) != (char)i) {
printf("Mismatch at %lu\n", i); printf("Mismatch at %lu\n", i);
break; return 1;
} }
return 0;
} }
int main(void) int main(void)
{ {
void *addr; void *addr;
int ret;
addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0); addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
...@@ -69,9 +71,9 @@ int main(void) ...@@ -69,9 +71,9 @@ int main(void)
printf("Returned address is %p\n", addr); printf("Returned address is %p\n", addr);
check_bytes(addr); check_bytes(addr);
write_bytes(addr); write_bytes(addr);
read_bytes(addr); ret = read_bytes(addr);
munmap(addr, LENGTH); munmap(addr, LENGTH);
return 0; return ret;
} }
#!/bin/bash
#please run as root
#we need 256M, below is the size in kB
needmem=262144
mnt=./huge
#get pagesize and freepages from /proc/meminfo
while read name size unit; do
if [ "$name" = "HugePages_Free:" ]; then
freepgs=$size
fi
if [ "$name" = "Hugepagesize:" ]; then
pgsize=$size
fi
done < /proc/meminfo
#set proper nr_hugepages
if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
needpgs=`expr $needmem / $pgsize`
if [ $freepgs -lt $needpgs ]; then
lackpgs=$(( $needpgs - $freepgs ))
echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
if [ $? -ne 0 ]; then
echo "Please run this test as root"
exit 1
fi
fi
else
echo "no hugetlbfs support in kernel?"
exit 1
fi
mkdir $mnt
mount -t hugetlbfs none $mnt
echo "--------------------"
echo "runing hugepage-mmap"
echo "--------------------"
./hugepage-mmap
if [ $? -ne 0 ]; then
echo "[FAIL]"
else
echo "[PASS]"
fi
shmmax=`cat /proc/sys/kernel/shmmax`
shmall=`cat /proc/sys/kernel/shmall`
echo 268435456 > /proc/sys/kernel/shmmax
echo 4194304 > /proc/sys/kernel/shmall
echo "--------------------"
echo "runing hugepage-shm"
echo "--------------------"
./hugepage-shm
if [ $? -ne 0 ]; then
echo "[FAIL]"
else
echo "[PASS]"
fi
echo $shmmax > /proc/sys/kernel/shmmax
echo $shmall > /proc/sys/kernel/shmall
echo "--------------------"
echo "runing map_hugetlb"
echo "--------------------"
./map_hugetlb
if [ $? -ne 0 ]; then
echo "[FAIL]"
else
echo "[PASS]"
fi
#cleanup
umount $mnt
rm -rf $mnt
echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
# Makefile for vm tools
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall -Wextra
all: page-types slabinfo
%: %.c
$(CC) $(CFLAGS) -o $@ $^
clean:
$(RM) page-types slabinfo
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
#define BIT(name) (1ULL << KPF_##name) #define BIT(name) (1ULL << KPF_##name)
#define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL)) #define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
static const char *page_flag_names[] = { static const char * const page_flag_names[] = {
[KPF_LOCKED] = "L:locked", [KPF_LOCKED] = "L:locked",
[KPF_ERROR] = "E:error", [KPF_ERROR] = "E:error",
[KPF_REFERENCED] = "R:referenced", [KPF_REFERENCED] = "R:referenced",
...@@ -166,7 +166,7 @@ static const char *page_flag_names[] = { ...@@ -166,7 +166,7 @@ static const char *page_flag_names[] = {
}; };
static const char *debugfs_known_mountpoints[] = { static const char * const debugfs_known_mountpoints[] = {
"/sys/kernel/debug", "/sys/kernel/debug",
"/debug", "/debug",
0, 0,
......
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