-
Notifications
You must be signed in to change notification settings - Fork 147
Task local data #9315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: bpf-next_base
Are you sure you want to change the base?
Task local data #9315
Conversation
Upstream branch: 0768e98 |
1c89975
to
2bf6e60
Compare
Upstream branch: 0768e98 |
32efc6b
to
b135040
Compare
2bf6e60
to
63bd3e4
Compare
Upstream branch: 0ee30d9 |
b135040
to
d32b562
Compare
63bd3e4
to
1c4f46e
Compare
Upstream branch: 0ee30d9 |
d32b562
to
3f9cb47
Compare
1c4f46e
to
b5a617e
Compare
Upstream branch: beb1097 |
3f9cb47
to
eeae154
Compare
b5a617e
to
ffefc6d
Compare
Upstream branch: 42be23e |
eeae154
to
166f1e1
Compare
ffefc6d
to
4ccf98a
Compare
Upstream branch: 42be23e |
166f1e1
to
54f5646
Compare
4ccf98a
to
95edab2
Compare
Upstream branch: 95993dc |
54f5646
to
87a21dd
Compare
95edab2
to
b70a88e
Compare
Upstream branch: 9ea0691 |
30b3e47
to
b5fabf3
Compare
Upstream branch: 5345e64 |
c7eacbe
to
078d8e3
Compare
b5fabf3
to
c883dca
Compare
Upstream branch: 5b4c54a |
078d8e3
to
746a93e
Compare
Upstream branch: 5b4c54a |
746a93e
to
c3d2d90
Compare
Upstream branch: 5b4c54a |
c3d2d90
to
b6916e1
Compare
c883dca
to
c82c120
Compare
Upstream branch: cd7c97f |
b6916e1
to
c1536a0
Compare
Upstream branch: cd7c97f |
c1536a0
to
8ec0906
Compare
c82c120
to
d97a5de
Compare
Upstream branch: e8d780d |
8ec0906
to
77f5db0
Compare
Allow syscall programs to call non-recur helpers too since syscall bpf programs runs in process context through bpf syscall, BPF_PROG_TEST_RUN, and cannot run recursively. bpf_task_storage_{get,set} have "_recur" versions that call trylock instead of taking the lock directly to avoid deadlock when called by bpf programs that run recursively. Currently, only bpf_lsm, bpf_iter, struct_ops without private stack are allow to call the non-recur helpers since they cannot be recursively called in another bpf program. Signed-off-by: Amery Hung <[email protected]> Reviewed-by: Emil Tsalapatis <[email protected]>
Task local data defines an abstract storage type for storing task- specific data (TLD). This patch provides user space and bpf implementation as header-only libraries for accessing task local data. Task local data is a bpf task local storage map with two UPTRs: - tld_meta_u, shared by all tasks of a process, consists of the total count and size of TLDs and an array of metadata of TLDs. A TLD metadata contains the size and name. The name is used to identify a specific TLD in bpf programs. - u_tld_data points to a task-specific memory. It stores TLD data and the starting offset of data in a page. Task local design decouple user space and bpf programs. Since bpf program does not know the size of TLDs in compile time, u_tld_data is declared as a page to accommodate TLDs up to a page. As a result, while user space will likely allocate memory smaller than a page for actual TLDs, it needs to pin a page to kernel. It will pin the page that contains enough memory if the allocated memory spans across the page boundary. The library also creates another task local storage map, tld_key_map, to cache keys for bpf programs to speed up the access. Below are the core task local data API: User space BPF Define TLD TLD_DEFINE_KEY(), tld_create_key() - Init TLD object - tld_object_init() Get TLD data tld_get_data() tld_get_data() - TLD_DEFINE_KEY(), tld_create_key() A TLD is first defined by the user space with TLD_DEFINE_KEY() or tld_create_key(). TLD_DEFINE_KEY() defines a TLD statically and allocates just enough memory during initialization. tld_create_key() allows creating TLDs on the fly, but has a fix memory budget, TLD_DYN_DATA_SIZE. Internally, they all call __tld_create_key(), which iterates tld_meta_u->metadata to check if a TLD can be added. The total TLD size needs to fit into a page (limit of UPTR), and no two TLDs can have the same name. If a TLD can be added, u_tld_meta->cnt is increased using cmpxchg as there may be other concurrent __tld_create_key(). After a successful cmpxchg, the last available tld_meta_u->metadata now belongs to the calling thread. To prevent other threads from reading incomplete metadata while it is being updated, tld_meta_u->metadata->size is used to signal the completion. Finally, the offset, derived from adding up prior TLD sizes is then encapsulated as an opaque object key to prevent user misuse. The offset is guaranteed to be 8-byte aligned to prevent load/store tearing and allow atomic operations on it. - tld_get_data() User space programs can pass the key to tld_get_data() to get a pointer to the associated TLD. The pointer will remain valid for the lifetime of the thread. tld_data_u is lazily allocated on the first call to tld_get_data(). Trying to read task local data from bpf will result in -ENODATA during tld_object_init(). The task-specific memory need to be freed manually by calling tld_free() on thread exit to prevent memory leak or use TLD_FREE_DATA_ON_THREAD_EXIT. - tld_object_init() (BPF) BPF programs need to call tld_object_init() before calling tld_get_data(). This is to avoid redundant map lookup in tld_get_data() by storing pointers to the map values on stack. The pointers are encapsulated as tld_object. tld_key_map is also created on the first time tld_object_init() is called to cache TLD keys successfully fetched by tld_get_data(). bpf_task_storage_get(.., F_CREATE) needs to be retried since it may fail when another thread has already taken the percpu counter lock for the task local storage. - tld_get_data() (BPF) BPF programs can also get a pointer to a TLD with tld_get_data(). It uses the cached key in tld_key_map to locate the data in tld_data_u->data. If the cached key is not set yet (<= 0), __tld_fetch_key() will be called to iterate tld_meta_u->metadata and find the TLD by name. To prevent redundant string comparison in the future when the search fail, the tld_meta_u->cnt is stored in the non-positive range of the key. Next time, __tld_fetch_key() will be called only if there are new TLDs and the search will start from the newly added tld_meta_u->metadata using the old tld_meta_u-cnt. Signed-off-by: Amery Hung <[email protected]> Reviewed-by: Emil Tsalapatis <[email protected]>
Test basic operations of task local data with valid and invalid tld_create_key(). For invalid calls, make sure they return the right error code and check that the TLDs are not inserted by running tld_get_data(" value_not_exists") on the bpf side. The call should a null pointer. For valid calls, first make sure the TLDs are created by calling tld_get_data() on the bpf side. The call should return a valid pointer. Finally, verify that the TLDs are indeed task-specific (i.e., their addresses do not overlap) with multiple user threads. This done by writing values unique to each thread, reading them from both user space and bpf, and checking if the value read back matches the value written. Signed-off-by: Amery Hung <[email protected]> Reviewed-by: Emil Tsalapatis <[email protected]>
Test thread-safety of tld_create_key(). Since tld_create_key() does not rely on locks but memory barriers and atomic operations to protect the shared metadata, the thread-safety of the function is non-trivial. Make sure concurrent tld_key_create(), both valid and invalid, can not race and corrupt metatada, which may leads to TLDs not being thread- specific or duplicate TLDs with the same name. Signed-off-by: Amery Hung <[email protected]> Reviewed-by: Emil Tsalapatis <[email protected]>
Upstream branch: e8d780d |
77f5db0
to
5c1000f
Compare
Pull request for series with
subject: Task local data
version: 6
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=983442