BACKPORT: mm: introduce kv[mz]alloc helpers
Patch series "kvmalloc", v5. There are many open coded kmalloc with vmalloc fallback instances in the tree. Most of them are not careful enough or simply do not care about the underlying semantic of the kmalloc/page allocator which means that a) some vmalloc fallbacks are basically unreachable because the kmalloc part will keep retrying until it succeeds b) the page allocator can invoke a really disruptive steps like the OOM killer to move forward which doesn't sound appropriate when we consider that the vmalloc fallback is available. As it can be seen implementing kvmalloc requires quite an intimate knowledge if the page allocator and the memory reclaim internals which strongly suggests that a helper should be implemented in the memory subsystem proper. Most callers, I could find, have been converted to use the helper instead. This is patch 6. There are some more relying on __GFP_REPEAT in the networking stack which I have converted as well and Eric Dumazet was not opposed [2] to convert them as well. [1] http://lkml.kernel.org/r/20170130094940.13546-1-mhocko@kernel.org [2] http://lkml.kernel.org/r/1485273626.16328.301.camel@edumazet-glaptop3.roam.corp.google.com This patch (of 9): Using kmalloc with the vmalloc fallback for larger allocations is a common pattern in the kernel code. Yet we do not have any common helper for that and so users have invented their own helpers. Some of them are really creative when doing so. Let's just add kv[mz]alloc and make sure it is implemented properly. This implementation makes sure to not make a large memory pressure for > PAGE_SZE requests (__GFP_NORETRY) and also to not warn about allocation failures. This also rules out the OOM killer as the vmalloc is a more approapriate fallback than a disruptive user visible action. This patch also changes some existing users and removes helpers which are specific for them. In some cases this is not possible (e.g. ext4_kvmalloc, libcfs_kvzalloc) because those seems to be broken and require GFP_NO{FS,IO} context which is not vmalloc compatible in general (note that the page table allocation is GFP_KERNEL). Those need to be fixed separately. While we are at it, document that __vmalloc{_node} about unsupported gfp mask because there seems to be a lot of confusion out there. kvmalloc_node will warn about GFP_KERNEL incompatible (which are not superset) flags to catch new abusers. Existing ones would have to die slowly. [sfr@canb.auug.org.au: f2fs fixup] Link: http://lkml.kernel.org/r/20170320163735.332e64b7@canb.auug.org.au Link: http://lkml.kernel.org/r/20170306103032.2540-2-mhocko@kernel.org Signed-off-by: Michal Hocko <mhocko@suse.com> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Reviewed-by: Andreas Dilger <adilger@dilger.ca> [ext4 part] Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: John Hubbard <jhubbard@nvidia.com> Cc: David Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Angelo G. Del Regno <kholk11@gmail.com> Signed-off-by: Yousef Algadri <yusufgadrie@gmail.com> Signed-off-by: DennySPB <dennyspb@gmail.com> ,
This commit is contained in:
parent
10f7a32390
commit
f372ac0415
13 changed files with 17 additions and 80 deletions
|
@ -168,8 +168,8 @@ static void recalculate_apic_map(struct kvm *kvm)
|
|||
if (kvm_apic_present(vcpu))
|
||||
max_id = max(max_id, kvm_apic_id(vcpu->arch.apic));
|
||||
|
||||
new = kvm_kvzalloc(sizeof(struct kvm_apic_map) +
|
||||
sizeof(struct kvm_lapic *) * ((u64)max_id + 1));
|
||||
new = kvzalloc(sizeof(struct kvm_apic_map) +
|
||||
sizeof(struct kvm_lapic *) * ((u64)max_id + 1), GFP_KERNEL);
|
||||
|
||||
if (!new)
|
||||
goto out;
|
||||
|
|
|
@ -38,8 +38,8 @@ int kvm_page_track_create_memslot(struct kvm_memory_slot *slot,
|
|||
int i;
|
||||
|
||||
for (i = 0; i < KVM_PAGE_TRACK_MAX; i++) {
|
||||
slot->arch.gfn_track[i] = kvm_kvzalloc(npages *
|
||||
sizeof(*slot->arch.gfn_track[i]));
|
||||
slot->arch.gfn_track[i] = kvzalloc(npages *
|
||||
sizeof(*slot->arch.gfn_track[i]), GFP_KERNEL);
|
||||
if (!slot->arch.gfn_track[i])
|
||||
goto track_free;
|
||||
}
|
||||
|
|
|
@ -8329,13 +8329,13 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
|
|||
slot->base_gfn, level) + 1;
|
||||
|
||||
slot->arch.rmap[i] =
|
||||
kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap[i]));
|
||||
kvzalloc(lpages * sizeof(*slot->arch.rmap[i]), GFP_KERNEL);
|
||||
if (!slot->arch.rmap[i])
|
||||
goto out_free;
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
linfo = kvm_kvzalloc(lpages * sizeof(*linfo));
|
||||
linfo = kvzalloc(lpages * sizeof(*linfo), GFP_KERNEL);
|
||||
if (!linfo)
|
||||
goto out_free;
|
||||
|
||||
|
|
|
@ -146,12 +146,7 @@ static void *dm_kvzalloc(size_t alloc_size, int node)
|
|||
if (!claim_shared_memory(alloc_size))
|
||||
return NULL;
|
||||
|
||||
if (alloc_size <= KMALLOC_MAX_SIZE) {
|
||||
p = kzalloc_node(alloc_size, GFP_KERNEL | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN, node);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
p = vzalloc_node(alloc_size, node);
|
||||
p = kvzalloc_node(alloc_size, GFP_KERNEL | __GFP_NOMEMALLOC, node);
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
|
|
|
@ -2448,7 +2448,7 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
|
|||
return 0;
|
||||
|
||||
size = roundup_pow_of_two(sizeof(*sbi->s_group_info) * size);
|
||||
new_groupinfo = ext4_kvzalloc(size, GFP_KERNEL);
|
||||
new_groupinfo = kvzalloc(size, GFP_KERNEL);
|
||||
if (!new_groupinfo) {
|
||||
ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group");
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -2212,7 +2212,7 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
|
|||
if (size <= sbi->s_flex_groups_allocated)
|
||||
return 0;
|
||||
|
||||
new_groups = ext4_kvzalloc(roundup_pow_of_two(size *
|
||||
new_groups = kvzalloc(roundup_pow_of_two(size *
|
||||
sizeof(*sbi->s_flex_groups)), GFP_KERNEL);
|
||||
if (!new_groups) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
|
@ -4069,8 +4069,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
goto failed_mount;
|
||||
}
|
||||
}
|
||||
rcu_assign_pointer(sbi->s_group_desc,
|
||||
ext4_kvmalloc(db_count *
|
||||
rcu_assign_pointer( sbi->s_group_desc,
|
||||
kvmalloc(db_count *
|
||||
sizeof(struct buffer_head *),
|
||||
GFP_KERNEL));
|
||||
if (sbi->s_group_desc == NULL) {
|
||||
|
|
|
@ -761,8 +761,6 @@ void kvm_arch_check_processor_compat(void *rtn);
|
|||
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
|
||||
int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
|
||||
|
||||
void *kvm_kvzalloc(unsigned long size);
|
||||
|
||||
#ifndef __KVM_HAVE_ARCH_VM_ALLOC
|
||||
static inline struct kvm *kvm_arch_alloc_vm(void)
|
||||
{
|
||||
|
|
|
@ -403,12 +403,7 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
|
|||
*/
|
||||
void *ipc_alloc(int size)
|
||||
{
|
||||
void *out;
|
||||
if (size > PAGE_SIZE)
|
||||
out = vmalloc(size);
|
||||
else
|
||||
out = kmalloc(size, GFP_KERNEL);
|
||||
return out;
|
||||
return kvmalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -100,7 +100,7 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
|
|||
return ERR_PTR(-EACCES);
|
||||
|
||||
/* freed by caller to simple_write_to_buffer */
|
||||
data = kvmalloc(alloc_size);
|
||||
data = kvmalloc(alloc_size, GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
|
@ -66,17 +66,6 @@ extern int apparmor_initialized __initdata;
|
|||
/* fn's in lib */
|
||||
char *aa_split_fqname(char *args, char **ns_name);
|
||||
void aa_info_message(const char *str);
|
||||
void *__aa_kvmalloc(size_t size, gfp_t flags);
|
||||
|
||||
static inline void *kvmalloc(size_t size)
|
||||
{
|
||||
return __aa_kvmalloc(size, 0);
|
||||
}
|
||||
|
||||
static inline void *kvzalloc(size_t size)
|
||||
{
|
||||
return __aa_kvmalloc(size, __GFP_ZERO);
|
||||
}
|
||||
|
||||
/* returns 0 if kref not incremented */
|
||||
static inline int kref_get_not0(struct kref *kref)
|
||||
|
|
|
@ -76,31 +76,3 @@ void aa_info_message(const char *str)
|
|||
printk(KERN_INFO "AppArmor: %s\n", str);
|
||||
}
|
||||
|
||||
/**
|
||||
* __aa_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
|
||||
* @size: how many bytes of memory are required
|
||||
* @flags: the type of memory to allocate (see kmalloc).
|
||||
*
|
||||
* Return: allocated buffer or NULL if failed
|
||||
*
|
||||
* It is possible that policy being loaded from the user is larger than
|
||||
* what can be allocated by kmalloc, in those cases fall back to vmalloc.
|
||||
*/
|
||||
void *__aa_kvmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
void *buffer = NULL;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
/* do not attempt kmalloc if we need more than 16 pages at once */
|
||||
if (size <= (16*PAGE_SIZE))
|
||||
buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN);
|
||||
if (!buffer) {
|
||||
if (flags & __GFP_ZERO)
|
||||
buffer = vzalloc(size);
|
||||
else
|
||||
buffer = vmalloc(size);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
|
|||
if (bsize < tsize)
|
||||
goto out;
|
||||
|
||||
table = kvzalloc(tsize);
|
||||
table = kvzalloc(tsize, GFP_KERNEL);
|
||||
if (table) {
|
||||
table->td_id = th.td_id;
|
||||
table->td_flags = th.td_flags;
|
||||
|
|
|
@ -528,7 +528,7 @@ static struct kvm_memslots *kvm_alloc_memslots(void)
|
|||
int i;
|
||||
struct kvm_memslots *slots;
|
||||
|
||||
slots = kvm_kvzalloc(sizeof(struct kvm_memslots));
|
||||
slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
|
||||
if (!slots)
|
||||
return NULL;
|
||||
|
||||
|
@ -737,18 +737,6 @@ out_err_no_disable:
|
|||
return ERR_PTR(r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid using vmalloc for a small buffer.
|
||||
* Should not be used when the size is statically known.
|
||||
*/
|
||||
void *kvm_kvzalloc(unsigned long size)
|
||||
{
|
||||
if (size > PAGE_SIZE)
|
||||
return vzalloc(size);
|
||||
else
|
||||
return kzalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void kvm_destroy_devices(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_device *dev, *tmp;
|
||||
|
@ -832,7 +820,7 @@ static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
|
|||
{
|
||||
unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot);
|
||||
|
||||
memslot->dirty_bitmap = kvm_kvzalloc(dirty_bytes);
|
||||
memslot->dirty_bitmap = kvzalloc(dirty_bytes, GFP_KERNEL);
|
||||
if (!memslot->dirty_bitmap)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1051,7 +1039,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
slots = kvm_kvzalloc(sizeof(struct kvm_memslots));
|
||||
slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
|
||||
if (!slots)
|
||||
goto out_free;
|
||||
memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue