summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.com>2017-05-08 18:57:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-08 20:15:12 -0400
commita7c3e901a46ff54c016d040847eda598a9e3e653 (patch)
treed149d70d420ff19586daa827db47a2e26a5598fe /security
parent60f3e00d25b44e3aa51846590d1e10f408466a83 (diff)
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>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/apparmorfs.c2
-rw-r--r--security/apparmor/include/lib.h11
-rw-r--r--security/apparmor/lib.c30
-rw-r--r--security/apparmor/match.c2
-rw-r--r--security/apparmor/policy_unpack.c2
5 files changed, 3 insertions, 44 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 41073f70eb41..be0b49897a67 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -98,7 +98,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
98 return ERR_PTR(-ESPIPE); 98 return ERR_PTR(-ESPIPE);
99 99
100 /* freed by caller to simple_write_to_buffer */ 100 /* freed by caller to simple_write_to_buffer */
101 data = kvmalloc(sizeof(*data) + alloc_size); 101 data = kvmalloc(sizeof(*data) + alloc_size, GFP_KERNEL);
102 if (data == NULL) 102 if (data == NULL)
103 return ERR_PTR(-ENOMEM); 103 return ERR_PTR(-ENOMEM);
104 kref_init(&data->count); 104 kref_init(&data->count);
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 0291ff3902f9..550a700563b4 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -64,17 +64,6 @@ char *aa_split_fqname(char *args, char **ns_name);
64const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 64const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
65 size_t *ns_len); 65 size_t *ns_len);
66void aa_info_message(const char *str); 66void aa_info_message(const char *str);
67void *__aa_kvmalloc(size_t size, gfp_t flags);
68
69static inline void *kvmalloc(size_t size)
70{
71 return __aa_kvmalloc(size, 0);
72}
73
74static inline void *kvzalloc(size_t size)
75{
76 return __aa_kvmalloc(size, __GFP_ZERO);
77}
78 67
79/** 68/**
80 * aa_strneq - compare null terminated @str to a non null terminated substring 69 * aa_strneq - compare null terminated @str to a non null terminated substring
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 32cafc12593e..7cd788a9445b 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -129,36 +129,6 @@ void aa_info_message(const char *str)
129} 129}
130 130
131/** 131/**
132 * __aa_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
133 * @size: how many bytes of memory are required
134 * @flags: the type of memory to allocate (see kmalloc).
135 *
136 * Return: allocated buffer or NULL if failed
137 *
138 * It is possible that policy being loaded from the user is larger than
139 * what can be allocated by kmalloc, in those cases fall back to vmalloc.
140 */
141void *__aa_kvmalloc(size_t size, gfp_t flags)
142{
143 void *buffer = NULL;
144
145 if (size == 0)
146 return NULL;
147
148 /* do not attempt kmalloc if we need more than 16 pages at once */
149 if (size <= (16*PAGE_SIZE))
150 buffer = kmalloc(size, flags | GFP_KERNEL | __GFP_NORETRY |
151 __GFP_NOWARN);
152 if (!buffer) {
153 if (flags & __GFP_ZERO)
154 buffer = vzalloc(size);
155 else
156 buffer = vmalloc(size);
157 }
158 return buffer;
159}
160
161/**
162 * aa_policy_init - initialize a policy structure 132 * aa_policy_init - initialize a policy structure
163 * @policy: policy to initialize (NOT NULL) 133 * @policy: policy to initialize (NOT NULL)
164 * @prefix: prefix name if any is required. (MAYBE NULL) 134 * @prefix: prefix name if any is required. (MAYBE NULL)
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index eb0efef746f5..960c913381e2 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -88,7 +88,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
88 if (bsize < tsize) 88 if (bsize < tsize)
89 goto out; 89 goto out;
90 90
91 table = kvzalloc(tsize); 91 table = kvzalloc(tsize, GFP_KERNEL);
92 if (table) { 92 if (table) {
93 table->td_id = th.td_id; 93 table->td_id = th.td_id;
94 table->td_flags = th.td_flags; 94 table->td_flags = th.td_flags;
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 2e37c9c26bbd..f3422a91353c 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -487,7 +487,7 @@ fail:
487 487
488static void *kvmemdup(const void *src, size_t len) 488static void *kvmemdup(const void *src, size_t len)
489{ 489{
490 void *p = kvmalloc(len); 490 void *p = kvmalloc(len, GFP_KERNEL);
491 491
492 if (p) 492 if (p)
493 memcpy(p, src, len); 493 memcpy(p, src, len);