You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'linus' into cpumask-for-linus
Conflicts: arch/x86/kernel/cpu/common.c
This commit is contained in:
+1
-1
@@ -120,7 +120,7 @@ void *__alloc_percpu(size_t size, size_t align)
|
||||
* on it. Larger alignment should only be used for module
|
||||
* percpu sections on SMP for which this path isn't used.
|
||||
*/
|
||||
WARN_ON_ONCE(align > __alignof__(unsigned long long));
|
||||
WARN_ON_ONCE(align > SMP_CACHE_BYTES);
|
||||
|
||||
if (unlikely(!pdata))
|
||||
return NULL;
|
||||
|
||||
+25
-1
@@ -2,11 +2,24 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL(default_unplug_io_fn);
|
||||
|
||||
struct backing_dev_info default_backing_dev_info = {
|
||||
.ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE,
|
||||
.state = 0,
|
||||
.capabilities = BDI_CAP_MAP_COPY,
|
||||
.unplug_io_fn = default_unplug_io_fn,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(default_backing_dev_info);
|
||||
|
||||
static struct class *bdi_class;
|
||||
|
||||
@@ -166,9 +179,20 @@ static __init int bdi_class_init(void)
|
||||
bdi_debug_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
postcore_initcall(bdi_class_init);
|
||||
|
||||
static int __init default_bdi_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bdi_init(&default_backing_dev_info);
|
||||
if (!err)
|
||||
bdi_register(&default_backing_dev_info, NULL, "default");
|
||||
|
||||
return err;
|
||||
}
|
||||
subsys_initcall(default_bdi_init);
|
||||
|
||||
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
|
||||
+57
-8
@@ -67,6 +67,25 @@ pte_t * pkmap_page_table;
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
|
||||
|
||||
/*
|
||||
* Most architectures have no use for kmap_high_get(), so let's abstract
|
||||
* the disabling of IRQ out of the locking in that case to save on a
|
||||
* potential useless overhead.
|
||||
*/
|
||||
#ifdef ARCH_NEEDS_KMAP_HIGH_GET
|
||||
#define lock_kmap() spin_lock_irq(&kmap_lock)
|
||||
#define unlock_kmap() spin_unlock_irq(&kmap_lock)
|
||||
#define lock_kmap_any(flags) spin_lock_irqsave(&kmap_lock, flags)
|
||||
#define unlock_kmap_any(flags) spin_unlock_irqrestore(&kmap_lock, flags)
|
||||
#else
|
||||
#define lock_kmap() spin_lock(&kmap_lock)
|
||||
#define unlock_kmap() spin_unlock(&kmap_lock)
|
||||
#define lock_kmap_any(flags) \
|
||||
do { spin_lock(&kmap_lock); (void)(flags); } while (0)
|
||||
#define unlock_kmap_any(flags) \
|
||||
do { spin_unlock(&kmap_lock); (void)(flags); } while (0)
|
||||
#endif
|
||||
|
||||
static void flush_all_zero_pkmaps(void)
|
||||
{
|
||||
int i;
|
||||
@@ -113,9 +132,9 @@ static void flush_all_zero_pkmaps(void)
|
||||
*/
|
||||
void kmap_flush_unused(void)
|
||||
{
|
||||
spin_lock(&kmap_lock);
|
||||
lock_kmap();
|
||||
flush_all_zero_pkmaps();
|
||||
spin_unlock(&kmap_lock);
|
||||
unlock_kmap();
|
||||
}
|
||||
|
||||
static inline unsigned long map_new_virtual(struct page *page)
|
||||
@@ -145,10 +164,10 @@ start:
|
||||
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&pkmap_map_wait, &wait);
|
||||
spin_unlock(&kmap_lock);
|
||||
unlock_kmap();
|
||||
schedule();
|
||||
remove_wait_queue(&pkmap_map_wait, &wait);
|
||||
spin_lock(&kmap_lock);
|
||||
lock_kmap();
|
||||
|
||||
/* Somebody else might have mapped it while we slept */
|
||||
if (page_address(page))
|
||||
@@ -184,29 +203,59 @@ void *kmap_high(struct page *page)
|
||||
* For highmem pages, we can't trust "virtual" until
|
||||
* after we have the lock.
|
||||
*/
|
||||
spin_lock(&kmap_lock);
|
||||
lock_kmap();
|
||||
vaddr = (unsigned long)page_address(page);
|
||||
if (!vaddr)
|
||||
vaddr = map_new_virtual(page);
|
||||
pkmap_count[PKMAP_NR(vaddr)]++;
|
||||
BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
|
||||
spin_unlock(&kmap_lock);
|
||||
unlock_kmap();
|
||||
return (void*) vaddr;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(kmap_high);
|
||||
|
||||
#ifdef ARCH_NEEDS_KMAP_HIGH_GET
|
||||
/**
|
||||
* kmap_high_get - pin a highmem page into memory
|
||||
* @page: &struct page to pin
|
||||
*
|
||||
* Returns the page's current virtual memory address, or NULL if no mapping
|
||||
* exists. When and only when a non null address is returned then a
|
||||
* matching call to kunmap_high() is necessary.
|
||||
*
|
||||
* This can be called from any context.
|
||||
*/
|
||||
void *kmap_high_get(struct page *page)
|
||||
{
|
||||
unsigned long vaddr, flags;
|
||||
|
||||
lock_kmap_any(flags);
|
||||
vaddr = (unsigned long)page_address(page);
|
||||
if (vaddr) {
|
||||
BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1);
|
||||
pkmap_count[PKMAP_NR(vaddr)]++;
|
||||
}
|
||||
unlock_kmap_any(flags);
|
||||
return (void*) vaddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* kunmap_high - map a highmem page into memory
|
||||
* @page: &struct page to unmap
|
||||
*
|
||||
* If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called
|
||||
* only from user context.
|
||||
*/
|
||||
void kunmap_high(struct page *page)
|
||||
{
|
||||
unsigned long vaddr;
|
||||
unsigned long nr;
|
||||
unsigned long flags;
|
||||
int need_wakeup;
|
||||
|
||||
spin_lock(&kmap_lock);
|
||||
lock_kmap_any(flags);
|
||||
vaddr = (unsigned long)page_address(page);
|
||||
BUG_ON(!vaddr);
|
||||
nr = PKMAP_NR(vaddr);
|
||||
@@ -232,7 +281,7 @@ void kunmap_high(struct page *page)
|
||||
*/
|
||||
need_wakeup = waitqueue_active(&pkmap_map_wait);
|
||||
}
|
||||
spin_unlock(&kmap_lock);
|
||||
unlock_kmap_any(flags);
|
||||
|
||||
/* do wake-up, if needed, race-free outside of the spin lock */
|
||||
if (need_wakeup)
|
||||
|
||||
+4
-2
@@ -1665,9 +1665,10 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
|
||||
* behaviour that some programs depend on. We mark the "original"
|
||||
* un-COW'ed pages by matching them up with "vma->vm_pgoff".
|
||||
*/
|
||||
if (addr == vma->vm_start && end == vma->vm_end)
|
||||
if (addr == vma->vm_start && end == vma->vm_end) {
|
||||
vma->vm_pgoff = pfn;
|
||||
else if (is_cow_mapping(vma->vm_flags))
|
||||
vma->vm_flags |= VM_PFN_AT_MMAP;
|
||||
} else if (is_cow_mapping(vma->vm_flags))
|
||||
return -EINVAL;
|
||||
|
||||
vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
|
||||
@@ -1679,6 +1680,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
|
||||
* needed from higher level routine calling unmap_vmas
|
||||
*/
|
||||
vma->vm_flags &= ~(VM_IO | VM_RESERVED | VM_PFNMAP);
|
||||
vma->vm_flags &= ~VM_PFN_AT_MMAP;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/module.h>
|
||||
@@ -1047,6 +1048,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
|
||||
}
|
||||
|
||||
error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
|
||||
if (error)
|
||||
return error;
|
||||
error = ima_file_mmap(file, prot);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
||||
+2
-2
@@ -66,7 +66,7 @@ static inline long sync_writeback_pages(void)
|
||||
/*
|
||||
* Start background writeback (via pdflush) at this percentage
|
||||
*/
|
||||
int dirty_background_ratio = 5;
|
||||
int dirty_background_ratio = 10;
|
||||
|
||||
/*
|
||||
* dirty_background_bytes starts at 0 (disabled) so that it is a function of
|
||||
@@ -83,7 +83,7 @@ int vm_highmem_is_dirtyable;
|
||||
/*
|
||||
* The generator of dirty data starts writeback at this percentage
|
||||
*/
|
||||
int vm_dirty_ratio = 10;
|
||||
int vm_dirty_ratio = 20;
|
||||
|
||||
/*
|
||||
* vm_dirty_bytes starts at 0 (disabled) so that it is a function of
|
||||
|
||||
+115
-15
@@ -46,7 +46,8 @@
|
||||
* - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
|
||||
*
|
||||
* - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
|
||||
* regular address to percpu pointer and back
|
||||
* regular address to percpu pointer and back if they need to be
|
||||
* different from the default
|
||||
*
|
||||
* - use pcpu_setup_first_chunk() during percpu area initialization to
|
||||
* setup the first chunk containing the kernel static percpu area
|
||||
@@ -67,11 +68,24 @@
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */
|
||||
#define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */
|
||||
|
||||
/* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */
|
||||
#ifndef __addr_to_pcpu_ptr
|
||||
#define __addr_to_pcpu_ptr(addr) \
|
||||
(void *)((unsigned long)(addr) - (unsigned long)pcpu_base_addr \
|
||||
+ (unsigned long)__per_cpu_start)
|
||||
#endif
|
||||
#ifndef __pcpu_ptr_to_addr
|
||||
#define __pcpu_ptr_to_addr(ptr) \
|
||||
(void *)((unsigned long)(ptr) + (unsigned long)pcpu_base_addr \
|
||||
- (unsigned long)__per_cpu_start)
|
||||
#endif
|
||||
|
||||
struct pcpu_chunk {
|
||||
struct list_head list; /* linked to pcpu_slot lists */
|
||||
struct rb_node rb_node; /* key is chunk->vm->addr */
|
||||
@@ -1013,8 +1027,8 @@ EXPORT_SYMBOL_GPL(free_percpu);
|
||||
* @get_page_fn: callback to fetch page pointer
|
||||
* @static_size: the size of static percpu area in bytes
|
||||
* @reserved_size: the size of reserved percpu area in bytes
|
||||
* @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
|
||||
* @dyn_size: free size for dynamic allocation in bytes, -1 for auto
|
||||
* @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
|
||||
* @base_addr: mapped address, NULL for auto
|
||||
* @populate_pte_fn: callback to allocate pagetable, NULL if unnecessary
|
||||
*
|
||||
@@ -1039,14 +1053,14 @@ EXPORT_SYMBOL_GPL(free_percpu);
|
||||
* limited offset range for symbol relocations to guarantee module
|
||||
* percpu symbols fall inside the relocatable range.
|
||||
*
|
||||
* @dyn_size, if non-negative, determines the number of bytes
|
||||
* available for dynamic allocation in the first chunk. Specifying
|
||||
* non-negative value makes percpu leave alone the area beyond
|
||||
* @static_size + @reserved_size + @dyn_size.
|
||||
*
|
||||
* @unit_size, if non-negative, specifies unit size and must be
|
||||
* aligned to PAGE_SIZE and equal to or larger than @static_size +
|
||||
* @reserved_size + @dyn_size.
|
||||
*
|
||||
* @dyn_size, if non-negative, limits the number of bytes available
|
||||
* for dynamic allocation in the first chunk. Specifying non-negative
|
||||
* value make percpu leave alone the area beyond @static_size +
|
||||
* @reserved_size + @dyn_size.
|
||||
* @reserved_size + if non-negative, @dyn_size.
|
||||
*
|
||||
* Non-null @base_addr means that the caller already allocated virtual
|
||||
* region for the first chunk and mapped it. percpu must not mess
|
||||
@@ -1069,12 +1083,14 @@ EXPORT_SYMBOL_GPL(free_percpu);
|
||||
*/
|
||||
size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
|
||||
size_t static_size, size_t reserved_size,
|
||||
ssize_t unit_size, ssize_t dyn_size,
|
||||
ssize_t dyn_size, ssize_t unit_size,
|
||||
void *base_addr,
|
||||
pcpu_populate_pte_fn_t populate_pte_fn)
|
||||
{
|
||||
static struct vm_struct first_vm;
|
||||
static int smap[2], dmap[2];
|
||||
size_t size_sum = static_size + reserved_size +
|
||||
(dyn_size >= 0 ? dyn_size : 0);
|
||||
struct pcpu_chunk *schunk, *dchunk = NULL;
|
||||
unsigned int cpu;
|
||||
int nr_pages;
|
||||
@@ -1085,20 +1101,18 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
|
||||
ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC);
|
||||
BUG_ON(!static_size);
|
||||
if (unit_size >= 0) {
|
||||
BUG_ON(unit_size < static_size + reserved_size +
|
||||
(dyn_size >= 0 ? dyn_size : 0));
|
||||
BUG_ON(unit_size < size_sum);
|
||||
BUG_ON(unit_size & ~PAGE_MASK);
|
||||
} else {
|
||||
BUG_ON(dyn_size >= 0);
|
||||
BUG_ON(unit_size < PCPU_MIN_UNIT_SIZE);
|
||||
} else
|
||||
BUG_ON(base_addr);
|
||||
}
|
||||
BUG_ON(base_addr && populate_pte_fn);
|
||||
|
||||
if (unit_size >= 0)
|
||||
pcpu_unit_pages = unit_size >> PAGE_SHIFT;
|
||||
else
|
||||
pcpu_unit_pages = max_t(int, PCPU_MIN_UNIT_SIZE >> PAGE_SHIFT,
|
||||
PFN_UP(static_size + reserved_size));
|
||||
PFN_UP(size_sum));
|
||||
|
||||
pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT;
|
||||
pcpu_chunk_size = num_possible_cpus() * pcpu_unit_size;
|
||||
@@ -1224,3 +1238,89 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
|
||||
pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0);
|
||||
return pcpu_unit_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Embedding first chunk setup helper.
|
||||
*/
|
||||
static void *pcpue_ptr __initdata;
|
||||
static size_t pcpue_size __initdata;
|
||||
static size_t pcpue_unit_size __initdata;
|
||||
|
||||
static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
|
||||
{
|
||||
size_t off = (size_t)pageno << PAGE_SHIFT;
|
||||
|
||||
if (off >= pcpue_size)
|
||||
return NULL;
|
||||
|
||||
return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcpu_embed_first_chunk - embed the first percpu chunk into bootmem
|
||||
* @static_size: the size of static percpu area in bytes
|
||||
* @reserved_size: the size of reserved percpu area in bytes
|
||||
* @dyn_size: free size for dynamic allocation in bytes, -1 for auto
|
||||
* @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
|
||||
*
|
||||
* This is a helper to ease setting up embedded first percpu chunk and
|
||||
* can be called where pcpu_setup_first_chunk() is expected.
|
||||
*
|
||||
* If this function is used to setup the first chunk, it is allocated
|
||||
* as a contiguous area using bootmem allocator and used as-is without
|
||||
* being mapped into vmalloc area. This enables the first chunk to
|
||||
* piggy back on the linear physical mapping which often uses larger
|
||||
* page size.
|
||||
*
|
||||
* When @dyn_size is positive, dynamic area might be larger than
|
||||
* specified to fill page alignment. Also, when @dyn_size is auto,
|
||||
* @dyn_size does not fill the whole first chunk but only what's
|
||||
* necessary for page alignment after static and reserved areas.
|
||||
*
|
||||
* If the needed size is smaller than the minimum or specified unit
|
||||
* size, the leftover is returned to the bootmem allocator.
|
||||
*
|
||||
* RETURNS:
|
||||
* The determined pcpu_unit_size which can be used to initialize
|
||||
* percpu access on success, -errno on failure.
|
||||
*/
|
||||
ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
|
||||
ssize_t dyn_size, ssize_t unit_size)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* determine parameters and allocate */
|
||||
pcpue_size = PFN_ALIGN(static_size + reserved_size +
|
||||
(dyn_size >= 0 ? dyn_size : 0));
|
||||
if (dyn_size != 0)
|
||||
dyn_size = pcpue_size - static_size - reserved_size;
|
||||
|
||||
if (unit_size >= 0) {
|
||||
BUG_ON(unit_size < pcpue_size);
|
||||
pcpue_unit_size = unit_size;
|
||||
} else
|
||||
pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE);
|
||||
|
||||
pcpue_ptr = __alloc_bootmem_nopanic(
|
||||
num_possible_cpus() * pcpue_unit_size,
|
||||
PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
|
||||
if (!pcpue_ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
/* return the leftover and copy */
|
||||
for_each_possible_cpu(cpu) {
|
||||
void *ptr = pcpue_ptr + cpu * pcpue_unit_size;
|
||||
|
||||
free_bootmem(__pa(ptr + pcpue_size),
|
||||
pcpue_unit_size - pcpue_size);
|
||||
memcpy(ptr, __per_cpu_load, static_size);
|
||||
}
|
||||
|
||||
/* we're ready, commit */
|
||||
pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n",
|
||||
pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size);
|
||||
|
||||
return pcpu_setup_first_chunk(pcpue_get_page, static_size,
|
||||
reserved_size, dyn_size,
|
||||
pcpue_unit_size, pcpue_ptr, NULL);
|
||||
}
|
||||
|
||||
@@ -17,19 +17,6 @@
|
||||
#include <linux/pagevec.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL(default_unplug_io_fn);
|
||||
|
||||
struct backing_dev_info default_backing_dev_info = {
|
||||
.ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE,
|
||||
.state = 0,
|
||||
.capabilities = BDI_CAP_MAP_COPY,
|
||||
.unplug_io_fn = default_unplug_io_fn,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(default_backing_dev_info);
|
||||
|
||||
/*
|
||||
* Initialise a struct file's readahead state. Assumes that the caller has
|
||||
* memset *ra to zero.
|
||||
@@ -233,18 +220,6 @@ unsigned long max_sane_readahead(unsigned long nr)
|
||||
+ node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2);
|
||||
}
|
||||
|
||||
static int __init readahead_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bdi_init(&default_backing_dev_info);
|
||||
if (!err)
|
||||
bdi_register(&default_backing_dev_info, NULL, "default");
|
||||
|
||||
return err;
|
||||
}
|
||||
subsys_initcall(readahead_init);
|
||||
|
||||
/*
|
||||
* Submit IO for the read-ahead request in file_ra_state.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
static struct vfsmount *shm_mnt;
|
||||
|
||||
@@ -2665,6 +2666,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
|
||||
if (IS_ERR(file))
|
||||
return PTR_ERR(file);
|
||||
|
||||
ima_shm_check(file);
|
||||
if (vma->vm_file)
|
||||
fput(vma->vm_file);
|
||||
vma->vm_file = file;
|
||||
|
||||
@@ -126,9 +126,9 @@ static LIST_HEAD(free_slob_medium);
|
||||
static LIST_HEAD(free_slob_large);
|
||||
|
||||
/*
|
||||
* slob_page: True for all slob pages (false for bigblock pages)
|
||||
* is_slob_page: True for all slob pages (false for bigblock pages)
|
||||
*/
|
||||
static inline int slob_page(struct slob_page *sp)
|
||||
static inline int is_slob_page(struct slob_page *sp)
|
||||
{
|
||||
return PageSlobPage((struct page *)sp);
|
||||
}
|
||||
@@ -143,6 +143,11 @@ static inline void clear_slob_page(struct slob_page *sp)
|
||||
__ClearPageSlobPage((struct page *)sp);
|
||||
}
|
||||
|
||||
static inline struct slob_page *slob_page(const void *addr)
|
||||
{
|
||||
return (struct slob_page *)virt_to_page(addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* slob_page_free: true for pages on free_slob_pages list.
|
||||
*/
|
||||
@@ -230,7 +235,7 @@ static int slob_last(slob_t *s)
|
||||
return !((unsigned long)slob_next(s) & ~PAGE_MASK);
|
||||
}
|
||||
|
||||
static void *slob_new_page(gfp_t gfp, int order, int node)
|
||||
static void *slob_new_pages(gfp_t gfp, int order, int node)
|
||||
{
|
||||
void *page;
|
||||
|
||||
@@ -247,12 +252,17 @@ static void *slob_new_page(gfp_t gfp, int order, int node)
|
||||
return page_address(page);
|
||||
}
|
||||
|
||||
static void slob_free_pages(void *b, int order)
|
||||
{
|
||||
free_pages((unsigned long)b, order);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a slob block within a given slob_page sp.
|
||||
*/
|
||||
static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
|
||||
{
|
||||
slob_t *prev, *cur, *aligned = 0;
|
||||
slob_t *prev, *cur, *aligned = NULL;
|
||||
int delta = 0, units = SLOB_UNITS(size);
|
||||
|
||||
for (prev = NULL, cur = sp->free; ; prev = cur, cur = slob_next(cur)) {
|
||||
@@ -349,10 +359,10 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
|
||||
|
||||
/* Not enough space: must allocate a new page */
|
||||
if (!b) {
|
||||
b = slob_new_page(gfp & ~__GFP_ZERO, 0, node);
|
||||
b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
|
||||
if (!b)
|
||||
return 0;
|
||||
sp = (struct slob_page *)virt_to_page(b);
|
||||
return NULL;
|
||||
sp = slob_page(b);
|
||||
set_slob_page(sp);
|
||||
|
||||
spin_lock_irqsave(&slob_lock, flags);
|
||||
@@ -384,7 +394,7 @@ static void slob_free(void *block, int size)
|
||||
return;
|
||||
BUG_ON(!size);
|
||||
|
||||
sp = (struct slob_page *)virt_to_page(block);
|
||||
sp = slob_page(block);
|
||||
units = SLOB_UNITS(size);
|
||||
|
||||
spin_lock_irqsave(&slob_lock, flags);
|
||||
@@ -393,10 +403,11 @@ static void slob_free(void *block, int size)
|
||||
/* Go directly to page allocator. Do not pass slob allocator */
|
||||
if (slob_page_free(sp))
|
||||
clear_slob_page_free(sp);
|
||||
spin_unlock_irqrestore(&slob_lock, flags);
|
||||
clear_slob_page(sp);
|
||||
free_slob_page(sp);
|
||||
free_page((unsigned long)b);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!slob_page_free(sp)) {
|
||||
@@ -476,7 +487,7 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node)
|
||||
} else {
|
||||
void *ret;
|
||||
|
||||
ret = slob_new_page(gfp | __GFP_COMP, get_order(size), node);
|
||||
ret = slob_new_pages(gfp | __GFP_COMP, get_order(size), node);
|
||||
if (ret) {
|
||||
struct page *page;
|
||||
page = virt_to_page(ret);
|
||||
@@ -494,8 +505,8 @@ void kfree(const void *block)
|
||||
if (unlikely(ZERO_OR_NULL_PTR(block)))
|
||||
return;
|
||||
|
||||
sp = (struct slob_page *)virt_to_page(block);
|
||||
if (slob_page(sp)) {
|
||||
sp = slob_page(block);
|
||||
if (is_slob_page(sp)) {
|
||||
int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
|
||||
unsigned int *m = (unsigned int *)(block - align);
|
||||
slob_free(m, *m + align);
|
||||
@@ -513,8 +524,8 @@ size_t ksize(const void *block)
|
||||
if (unlikely(block == ZERO_SIZE_PTR))
|
||||
return 0;
|
||||
|
||||
sp = (struct slob_page *)virt_to_page(block);
|
||||
if (slob_page(sp)) {
|
||||
sp = slob_page(block);
|
||||
if (is_slob_page(sp)) {
|
||||
int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
|
||||
unsigned int *m = (unsigned int *)(block - align);
|
||||
return SLOB_UNITS(*m) * SLOB_UNIT;
|
||||
@@ -573,7 +584,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
|
||||
if (c->size < PAGE_SIZE)
|
||||
b = slob_alloc(c->size, flags, c->align, node);
|
||||
else
|
||||
b = slob_new_page(flags, get_order(c->size), node);
|
||||
b = slob_new_pages(flags, get_order(c->size), node);
|
||||
|
||||
if (c->ctor)
|
||||
c->ctor(b);
|
||||
@@ -587,7 +598,7 @@ static void __kmem_cache_free(void *b, int size)
|
||||
if (size < PAGE_SIZE)
|
||||
slob_free(b, size);
|
||||
else
|
||||
free_pages((unsigned long)b, get_order(size));
|
||||
slob_free_pages(b, get_order(size));
|
||||
}
|
||||
|
||||
static void kmem_rcu_free(struct rcu_head *head)
|
||||
|
||||
@@ -374,14 +374,8 @@ static struct track *get_track(struct kmem_cache *s, void *object,
|
||||
static void set_track(struct kmem_cache *s, void *object,
|
||||
enum track_item alloc, unsigned long addr)
|
||||
{
|
||||
struct track *p;
|
||||
struct track *p = get_track(s, object, alloc);
|
||||
|
||||
if (s->offset)
|
||||
p = object + s->offset + sizeof(void *);
|
||||
else
|
||||
p = object + s->inuse;
|
||||
|
||||
p += alloc;
|
||||
if (addr) {
|
||||
p->addr = addr;
|
||||
p->cpu = smp_processor_id();
|
||||
@@ -1335,7 +1329,7 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
|
||||
n = get_node(s, zone_to_nid(zone));
|
||||
|
||||
if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
|
||||
n->nr_partial > n->min_partial) {
|
||||
n->nr_partial > s->min_partial) {
|
||||
page = get_partial_node(n);
|
||||
if (page)
|
||||
return page;
|
||||
@@ -1387,7 +1381,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
|
||||
slab_unlock(page);
|
||||
} else {
|
||||
stat(c, DEACTIVATE_EMPTY);
|
||||
if (n->nr_partial < n->min_partial) {
|
||||
if (n->nr_partial < s->min_partial) {
|
||||
/*
|
||||
* Adding an empty slab to the partial slabs in order
|
||||
* to avoid page allocator overhead. This slab needs
|
||||
@@ -1724,7 +1718,7 @@ static __always_inline void slab_free(struct kmem_cache *s,
|
||||
c = get_cpu_slab(s, smp_processor_id());
|
||||
debug_check_no_locks_freed(object, c->objsize);
|
||||
if (!(s->flags & SLAB_DEBUG_OBJECTS))
|
||||
debug_check_no_obj_freed(object, s->objsize);
|
||||
debug_check_no_obj_freed(object, c->objsize);
|
||||
if (likely(page == c->page && c->node >= 0)) {
|
||||
object[c->offset] = c->freelist;
|
||||
c->freelist = object;
|
||||
@@ -1844,6 +1838,7 @@ static inline int calculate_order(int size)
|
||||
int order;
|
||||
int min_objects;
|
||||
int fraction;
|
||||
int max_objects;
|
||||
|
||||
/*
|
||||
* Attempt to find best configuration for a slab. This
|
||||
@@ -1856,6 +1851,9 @@ static inline int calculate_order(int size)
|
||||
min_objects = slub_min_objects;
|
||||
if (!min_objects)
|
||||
min_objects = 4 * (fls(nr_cpu_ids) + 1);
|
||||
max_objects = (PAGE_SIZE << slub_max_order)/size;
|
||||
min_objects = min(min_objects, max_objects);
|
||||
|
||||
while (min_objects > 1) {
|
||||
fraction = 16;
|
||||
while (fraction >= 4) {
|
||||
@@ -1865,7 +1863,7 @@ static inline int calculate_order(int size)
|
||||
return order;
|
||||
fraction /= 2;
|
||||
}
|
||||
min_objects /= 2;
|
||||
min_objects --;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1928,17 +1926,6 @@ static void
|
||||
init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
|
||||
{
|
||||
n->nr_partial = 0;
|
||||
|
||||
/*
|
||||
* The larger the object size is, the more pages we want on the partial
|
||||
* list to avoid pounding the page allocator excessively.
|
||||
*/
|
||||
n->min_partial = ilog2(s->size);
|
||||
if (n->min_partial < MIN_PARTIAL)
|
||||
n->min_partial = MIN_PARTIAL;
|
||||
else if (n->min_partial > MAX_PARTIAL)
|
||||
n->min_partial = MAX_PARTIAL;
|
||||
|
||||
spin_lock_init(&n->list_lock);
|
||||
INIT_LIST_HEAD(&n->partial);
|
||||
#ifdef CONFIG_SLUB_DEBUG
|
||||
@@ -2181,6 +2168,15 @@ static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_min_partial(struct kmem_cache *s, unsigned long min)
|
||||
{
|
||||
if (min < MIN_PARTIAL)
|
||||
min = MIN_PARTIAL;
|
||||
else if (min > MAX_PARTIAL)
|
||||
min = MAX_PARTIAL;
|
||||
s->min_partial = min;
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate_sizes() determines the order and the distribution of data within
|
||||
* a slab object.
|
||||
@@ -2319,6 +2315,11 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
|
||||
if (!calculate_sizes(s, -1))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* The larger the object size is, the more pages we want on the partial
|
||||
* list to avoid pounding the page allocator excessively.
|
||||
*/
|
||||
set_min_partial(s, ilog2(s->size));
|
||||
s->refcount = 1;
|
||||
#ifdef CONFIG_NUMA
|
||||
s->remote_node_defrag_ratio = 1000;
|
||||
@@ -2475,7 +2476,7 @@ EXPORT_SYMBOL(kmem_cache_destroy);
|
||||
* Kmalloc subsystem
|
||||
*******************************************************************/
|
||||
|
||||
struct kmem_cache kmalloc_caches[PAGE_SHIFT + 1] __cacheline_aligned;
|
||||
struct kmem_cache kmalloc_caches[SLUB_PAGE_SHIFT] __cacheline_aligned;
|
||||
EXPORT_SYMBOL(kmalloc_caches);
|
||||
|
||||
static int __init setup_slub_min_order(char *str)
|
||||
@@ -2537,7 +2538,7 @@ panic:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT + 1];
|
||||
static struct kmem_cache *kmalloc_caches_dma[SLUB_PAGE_SHIFT];
|
||||
|
||||
static void sysfs_add_func(struct work_struct *w)
|
||||
{
|
||||
@@ -2658,7 +2659,7 @@ void *__kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
struct kmem_cache *s;
|
||||
|
||||
if (unlikely(size > PAGE_SIZE))
|
||||
if (unlikely(size > SLUB_MAX_SIZE))
|
||||
return kmalloc_large(size, flags);
|
||||
|
||||
s = get_slab(size, flags);
|
||||
@@ -2686,7 +2687,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
{
|
||||
struct kmem_cache *s;
|
||||
|
||||
if (unlikely(size > PAGE_SIZE))
|
||||
if (unlikely(size > SLUB_MAX_SIZE))
|
||||
return kmalloc_large_node(size, flags, node);
|
||||
|
||||
s = get_slab(size, flags);
|
||||
@@ -2986,7 +2987,7 @@ void __init kmem_cache_init(void)
|
||||
caches++;
|
||||
}
|
||||
|
||||
for (i = KMALLOC_SHIFT_LOW; i <= PAGE_SHIFT; i++) {
|
||||
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
|
||||
create_kmalloc_cache(&kmalloc_caches[i],
|
||||
"kmalloc", 1 << i, GFP_KERNEL);
|
||||
caches++;
|
||||
@@ -3023,7 +3024,7 @@ void __init kmem_cache_init(void)
|
||||
slab_state = UP;
|
||||
|
||||
/* Provide the correct kmalloc names now that the caches are up */
|
||||
for (i = KMALLOC_SHIFT_LOW; i <= PAGE_SHIFT; i++)
|
||||
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++)
|
||||
kmalloc_caches[i]. name =
|
||||
kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i);
|
||||
|
||||
@@ -3223,7 +3224,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
|
||||
{
|
||||
struct kmem_cache *s;
|
||||
|
||||
if (unlikely(size > PAGE_SIZE))
|
||||
if (unlikely(size > SLUB_MAX_SIZE))
|
||||
return kmalloc_large(size, gfpflags);
|
||||
|
||||
s = get_slab(size, gfpflags);
|
||||
@@ -3239,7 +3240,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
|
||||
{
|
||||
struct kmem_cache *s;
|
||||
|
||||
if (unlikely(size > PAGE_SIZE))
|
||||
if (unlikely(size > SLUB_MAX_SIZE))
|
||||
return kmalloc_large_node(size, gfpflags, node);
|
||||
|
||||
s = get_slab(size, gfpflags);
|
||||
@@ -3836,6 +3837,26 @@ static ssize_t order_show(struct kmem_cache *s, char *buf)
|
||||
}
|
||||
SLAB_ATTR(order);
|
||||
|
||||
static ssize_t min_partial_show(struct kmem_cache *s, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%lu\n", s->min_partial);
|
||||
}
|
||||
|
||||
static ssize_t min_partial_store(struct kmem_cache *s, const char *buf,
|
||||
size_t length)
|
||||
{
|
||||
unsigned long min;
|
||||
int err;
|
||||
|
||||
err = strict_strtoul(buf, 10, &min);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
set_min_partial(s, min);
|
||||
return length;
|
||||
}
|
||||
SLAB_ATTR(min_partial);
|
||||
|
||||
static ssize_t ctor_show(struct kmem_cache *s, char *buf)
|
||||
{
|
||||
if (s->ctor) {
|
||||
@@ -4151,6 +4172,7 @@ static struct attribute *slab_attrs[] = {
|
||||
&object_size_attr.attr,
|
||||
&objs_per_slab_attr.attr,
|
||||
&order_attr.attr,
|
||||
&min_partial_attr.attr,
|
||||
&objects_attr.attr,
|
||||
&objects_partial_attr.attr,
|
||||
&total_objects_attr.attr,
|
||||
|
||||
+1
-1
@@ -1262,7 +1262,6 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
|
||||
* Move the pages to the [file or anon] inactive list.
|
||||
*/
|
||||
pagevec_init(&pvec, 1);
|
||||
pgmoved = 0;
|
||||
lru = LRU_BASE + file * LRU_FILE;
|
||||
|
||||
spin_lock_irq(&zone->lru_lock);
|
||||
@@ -1274,6 +1273,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
|
||||
*/
|
||||
reclaim_stat->recent_rotated[!!file] += pgmoved;
|
||||
|
||||
pgmoved = 0;
|
||||
while (!list_empty(&l_inactive)) {
|
||||
page = lru_to_page(&l_inactive);
|
||||
prefetchw_prev_lru_page(page, &l_inactive, flags);
|
||||
|
||||
Reference in New Issue
Block a user