Skip to content

Commit ef07c4b

Browse files
Danilo Krummrichfbq
authored andcommitted
rust: alloc: implement KVmalloc allocator
Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to allocate memory wth `kmalloc` first and, on failure, falls back to `vmalloc`. All memory allocations made with `KVmalloc` end up in `kvrealloc_noprof()`; all frees in `kvfree()`. Reviewed-by: Alice Ryhl <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> Link: https://lore.kernel.org/r/[email protected] [boqun: Resolve conflict with helper split]
1 parent 865d50e commit ef07c4b

File tree

4 files changed

+385
-0
lines changed

4 files changed

+385
-0
lines changed

rust/helpers.c

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Non-trivial C macros cannot be used in Rust. Similarly, inlined C functions
4+
* cannot be called either. This file explicitly creates functions ("helpers")
5+
* that wrap those so that they can be called from Rust.
6+
*
7+
* Even though Rust kernel modules should never use the bindings directly, some
8+
* of these helpers need to be exported because Rust generics and inlined
9+
* functions may not get their code generated in the crate where they are
10+
* defined. Other helpers, called from non-inline functions, may not be
11+
* exported, in principle. However, in general, the Rust compiler does not
12+
* guarantee codegen will be performed for a non-inline function either.
13+
* Therefore, this file exports all the helpers. In the future, this may be
14+
* revisited to reduce the number of exports after the compiler is informed
15+
* about the places codegen is required.
16+
*
17+
* All symbols are exported as GPL-only to guarantee no GPL-only feature is
18+
* accidentally exposed.
19+
*
20+
* Sorted alphabetically.
21+
*/
22+
23+
#include <kunit/test-bug.h>
24+
#include <linux/bug.h>
25+
#include <linux/build_bug.h>
26+
#include <linux/cred.h>
27+
#include <linux/device.h>
28+
#include <linux/err.h>
29+
#include <linux/errname.h>
30+
#include <linux/fs.h>
31+
#include <linux/gfp.h>
32+
#include <linux/highmem.h>
33+
#include <linux/mutex.h>
34+
#include <linux/refcount.h>
35+
#include <linux/sched/signal.h>
36+
#include <linux/security.h>
37+
#include <linux/slab.h>
38+
#include <linux/spinlock.h>
39+
#include <linux/vmalloc.h>
40+
#include <linux/wait.h>
41+
#include <linux/workqueue.h>
42+
43+
__noreturn void rust_helper_BUG(void)
44+
{
45+
BUG();
46+
}
47+
EXPORT_SYMBOL_GPL(rust_helper_BUG);
48+
49+
unsigned long rust_helper_copy_from_user(void *to, const void __user *from,
50+
unsigned long n)
51+
{
52+
return copy_from_user(to, from, n);
53+
}
54+
EXPORT_SYMBOL_GPL(rust_helper_copy_from_user);
55+
56+
unsigned long rust_helper_copy_to_user(void __user *to, const void *from,
57+
unsigned long n)
58+
{
59+
return copy_to_user(to, from, n);
60+
}
61+
EXPORT_SYMBOL_GPL(rust_helper_copy_to_user);
62+
63+
void rust_helper_mutex_lock(struct mutex *lock)
64+
{
65+
mutex_lock(lock);
66+
}
67+
EXPORT_SYMBOL_GPL(rust_helper_mutex_lock);
68+
69+
void rust_helper___spin_lock_init(spinlock_t *lock, const char *name,
70+
struct lock_class_key *key)
71+
{
72+
#ifdef CONFIG_DEBUG_SPINLOCK
73+
__raw_spin_lock_init(spinlock_check(lock), name, key, LD_WAIT_CONFIG);
74+
#else
75+
spin_lock_init(lock);
76+
#endif
77+
}
78+
EXPORT_SYMBOL_GPL(rust_helper___spin_lock_init);
79+
80+
void rust_helper_spin_lock(spinlock_t *lock)
81+
{
82+
spin_lock(lock);
83+
}
84+
EXPORT_SYMBOL_GPL(rust_helper_spin_lock);
85+
86+
void rust_helper_spin_unlock(spinlock_t *lock)
87+
{
88+
spin_unlock(lock);
89+
}
90+
EXPORT_SYMBOL_GPL(rust_helper_spin_unlock);
91+
92+
void rust_helper_init_wait(struct wait_queue_entry *wq_entry)
93+
{
94+
init_wait(wq_entry);
95+
}
96+
EXPORT_SYMBOL_GPL(rust_helper_init_wait);
97+
98+
int rust_helper_signal_pending(struct task_struct *t)
99+
{
100+
return signal_pending(t);
101+
}
102+
EXPORT_SYMBOL_GPL(rust_helper_signal_pending);
103+
104+
struct page *rust_helper_alloc_pages(gfp_t gfp_mask, unsigned int order)
105+
{
106+
return alloc_pages(gfp_mask, order);
107+
}
108+
EXPORT_SYMBOL_GPL(rust_helper_alloc_pages);
109+
110+
void *rust_helper_kmap_local_page(struct page *page)
111+
{
112+
return kmap_local_page(page);
113+
}
114+
EXPORT_SYMBOL_GPL(rust_helper_kmap_local_page);
115+
116+
void rust_helper_kunmap_local(const void *addr)
117+
{
118+
kunmap_local(addr);
119+
}
120+
EXPORT_SYMBOL_GPL(rust_helper_kunmap_local);
121+
122+
refcount_t rust_helper_REFCOUNT_INIT(int n)
123+
{
124+
return (refcount_t)REFCOUNT_INIT(n);
125+
}
126+
EXPORT_SYMBOL_GPL(rust_helper_REFCOUNT_INIT);
127+
128+
void rust_helper_refcount_inc(refcount_t *r)
129+
{
130+
refcount_inc(r);
131+
}
132+
EXPORT_SYMBOL_GPL(rust_helper_refcount_inc);
133+
134+
bool rust_helper_refcount_dec_and_test(refcount_t *r)
135+
{
136+
return refcount_dec_and_test(r);
137+
}
138+
EXPORT_SYMBOL_GPL(rust_helper_refcount_dec_and_test);
139+
140+
__force void *rust_helper_ERR_PTR(long err)
141+
{
142+
return ERR_PTR(err);
143+
}
144+
EXPORT_SYMBOL_GPL(rust_helper_ERR_PTR);
145+
146+
bool rust_helper_IS_ERR(__force const void *ptr)
147+
{
148+
return IS_ERR(ptr);
149+
}
150+
EXPORT_SYMBOL_GPL(rust_helper_IS_ERR);
151+
152+
long rust_helper_PTR_ERR(__force const void *ptr)
153+
{
154+
return PTR_ERR(ptr);
155+
}
156+
EXPORT_SYMBOL_GPL(rust_helper_PTR_ERR);
157+
158+
const char *rust_helper_errname(int err)
159+
{
160+
return errname(err);
161+
}
162+
EXPORT_SYMBOL_GPL(rust_helper_errname);
163+
164+
struct task_struct *rust_helper_get_current(void)
165+
{
166+
return current;
167+
}
168+
EXPORT_SYMBOL_GPL(rust_helper_get_current);
169+
170+
void rust_helper_get_task_struct(struct task_struct *t)
171+
{
172+
get_task_struct(t);
173+
}
174+
EXPORT_SYMBOL_GPL(rust_helper_get_task_struct);
175+
176+
void rust_helper_put_task_struct(struct task_struct *t)
177+
{
178+
put_task_struct(t);
179+
}
180+
EXPORT_SYMBOL_GPL(rust_helper_put_task_struct);
181+
182+
kuid_t rust_helper_task_uid(struct task_struct *task)
183+
{
184+
return task_uid(task);
185+
}
186+
EXPORT_SYMBOL_GPL(rust_helper_task_uid);
187+
188+
kuid_t rust_helper_task_euid(struct task_struct *task)
189+
{
190+
return task_euid(task);
191+
}
192+
EXPORT_SYMBOL_GPL(rust_helper_task_euid);
193+
194+
#ifndef CONFIG_USER_NS
195+
uid_t rust_helper_from_kuid(struct user_namespace *to, kuid_t uid)
196+
{
197+
return from_kuid(to, uid);
198+
}
199+
EXPORT_SYMBOL_GPL(rust_helper_from_kuid);
200+
#endif /* CONFIG_USER_NS */
201+
202+
bool rust_helper_uid_eq(kuid_t left, kuid_t right)
203+
{
204+
return uid_eq(left, right);
205+
}
206+
EXPORT_SYMBOL_GPL(rust_helper_uid_eq);
207+
208+
kuid_t rust_helper_current_euid(void)
209+
{
210+
return current_euid();
211+
}
212+
EXPORT_SYMBOL_GPL(rust_helper_current_euid);
213+
214+
struct user_namespace *rust_helper_current_user_ns(void)
215+
{
216+
return current_user_ns();
217+
}
218+
EXPORT_SYMBOL_GPL(rust_helper_current_user_ns);
219+
220+
pid_t rust_helper_task_tgid_nr_ns(struct task_struct *tsk,
221+
struct pid_namespace *ns)
222+
{
223+
return task_tgid_nr_ns(tsk, ns);
224+
}
225+
EXPORT_SYMBOL_GPL(rust_helper_task_tgid_nr_ns);
226+
227+
struct kunit *rust_helper_kunit_get_current_test(void)
228+
{
229+
return kunit_get_current_test();
230+
}
231+
EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test);
232+
233+
void rust_helper_init_work_with_key(struct work_struct *work, work_func_t func,
234+
bool onstack, const char *name,
235+
struct lock_class_key *key)
236+
{
237+
__init_work(work, onstack);
238+
work->data = (atomic_long_t)WORK_DATA_INIT();
239+
lockdep_init_map(&work->lockdep_map, name, key, 0);
240+
INIT_LIST_HEAD(&work->entry);
241+
work->func = func;
242+
}
243+
EXPORT_SYMBOL_GPL(rust_helper_init_work_with_key);
244+
245+
void * __must_check __realloc_size(2)
246+
rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
247+
{
248+
return krealloc(objp, new_size, flags);
249+
}
250+
EXPORT_SYMBOL_GPL(rust_helper_krealloc);
251+
252+
void * __must_check __realloc_size(2)
253+
rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
254+
{
255+
return vrealloc(p, size, flags);
256+
}
257+
EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
258+
259+
void * __must_check __realloc_size(2)
260+
rust_helper_kvrealloc(const void *p, size_t size, gfp_t flags)
261+
{
262+
return kvrealloc(p, size, flags);
263+
}
264+
EXPORT_SYMBOL_GPL(rust_helper_kvrealloc);
265+
266+
void rust_helper_rb_link_node(struct rb_node *node, struct rb_node *parent,
267+
struct rb_node **rb_link)
268+
{
269+
rb_link_node(node, parent, rb_link);
270+
}
271+
EXPORT_SYMBOL_GPL(rust_helper_rb_link_node);
272+
273+
struct file *rust_helper_get_file(struct file *f)
274+
{
275+
return get_file(f);
276+
}
277+
EXPORT_SYMBOL_GPL(rust_helper_get_file);
278+
279+
const struct cred *rust_helper_get_cred(const struct cred *cred)
280+
{
281+
return get_cred(cred);
282+
}
283+
EXPORT_SYMBOL_GPL(rust_helper_get_cred);
284+
285+
void rust_helper_put_cred(const struct cred *cred)
286+
{
287+
put_cred(cred);
288+
}
289+
EXPORT_SYMBOL_GPL(rust_helper_put_cred);
290+
291+
#ifndef CONFIG_SECURITY
292+
void rust_helper_security_cred_getsecid(const struct cred *c, u32 *secid)
293+
{
294+
security_cred_getsecid(c, secid);
295+
}
296+
EXPORT_SYMBOL_GPL(rust_helper_security_cred_getsecid);
297+
298+
int rust_helper_security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
299+
{
300+
return security_secid_to_secctx(secid, secdata, seclen);
301+
}
302+
EXPORT_SYMBOL_GPL(rust_helper_security_secid_to_secctx);
303+
304+
void rust_helper_security_release_secctx(char *secdata, u32 seclen)
305+
{
306+
security_release_secctx(secdata, seclen);
307+
}
308+
EXPORT_SYMBOL_GPL(rust_helper_security_release_secctx);
309+
#endif
310+
311+
/*
312+
* `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
313+
* use it in contexts where Rust expects a `usize` like slice (array) indices.
314+
* `usize` is defined to be the same as C's `uintptr_t` type (can hold any
315+
* pointer) but not necessarily the same as `size_t` (can hold the size of any
316+
* single object). Most modern platforms use the same concrete integer type for
317+
* both of them, but in case we find ourselves on a platform where
318+
* that's not true, fail early instead of risking ABI or
319+
* integer-overflow issues.
320+
*
321+
* If your platform fails this assertion, it means that you are in
322+
* danger of integer-overflow bugs (even if you attempt to add
323+
* `--no-size_t-is-usize`). It may be easiest to change the kernel ABI on
324+
* your platform such that `size_t` matches `uintptr_t` (i.e., to increase
325+
* `size_t`, because `uintptr_t` has to be at least as big as `size_t`).
326+
*/
327+
static_assert(
328+
sizeof(size_t) == sizeof(uintptr_t) &&
329+
__alignof__(size_t) == __alignof__(uintptr_t),
330+
"Rust code expects C `size_t` to match Rust `usize`"
331+
);
332+
333+
// This will soon be moved to a separate file, so no need to merge with above.
334+
#include <linux/blk-mq.h>
335+
#include <linux/blkdev.h>
336+
337+
void *rust_helper_blk_mq_rq_to_pdu(struct request *rq)
338+
{
339+
return blk_mq_rq_to_pdu(rq);
340+
}
341+
EXPORT_SYMBOL_GPL(rust_helper_blk_mq_rq_to_pdu);
342+
343+
struct request *rust_helper_blk_mq_rq_from_pdu(void *pdu)
344+
{
345+
return blk_mq_rq_from_pdu(pdu);
346+
}
347+
EXPORT_SYMBOL_GPL(rust_helper_blk_mq_rq_from_pdu);

rust/helpers/slab.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
1616
{
1717
return vrealloc(p, size, flags);
1818
}
19+
20+
void * __must_check __realloc_size(2)
21+
rust_helper_kvrealloc(const void *p, size_t size, gfp_t flags)
22+
{
23+
return kvrealloc(p, size, flags);
24+
}

0 commit comments

Comments
 (0)