capsules_extra/
virtual_kv.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2023.
4
5//! Tock Key-Value virtualizer.
6//!
7//! This capsule provides a virtualized Key-Value store interface.
8//!
9//! ```text
10//! +-------------------------+
11//! |  Capsule using K-V      |
12//! +-------------------------+
13//!
14//!    hil::kv::KVPermissions
15//!
16//! +-------------------------+
17//! | Virtualizer (this file) |
18//! +-------------------------+
19//!
20//!    hil::kv::KVPermissions
21//!
22//! +-------------------------+
23//! |  K-V store Permissions  |
24//! +-------------------------+
25//!
26//!    hil::kv::KV
27//!
28//! +-------------------------+
29//! |  K-V library            |
30//! +-------------------------+
31//!
32//!    hil::flash
33//! ```
34
35use kernel::collections::list::{List, ListLink, ListNode};
36
37use kernel::hil::kv;
38use kernel::hil::kv::KVPermissions;
39use kernel::storage_permissions::StoragePermissions;
40use kernel::utilities::cells::{MapCell, OptionalCell};
41use kernel::utilities::leasable_buffer::SubSliceMut;
42use kernel::ErrorCode;
43
44#[derive(Clone, Copy, PartialEq, Debug)]
45enum Operation {
46    Get,
47    Set,
48    Delete,
49    Add,
50    Update,
51    GarbageCollect,
52}
53
54pub struct VirtualKVPermissions<'a, V: kv::KVPermissions<'a>> {
55    mux_kv: &'a MuxKVPermissions<'a, V>,
56    next: ListLink<'a, VirtualKVPermissions<'a, V>>,
57
58    client: OptionalCell<&'a dyn kv::KVClient>,
59    operation: OptionalCell<Operation>,
60
61    key: MapCell<SubSliceMut<'static, u8>>,
62    value: MapCell<SubSliceMut<'static, u8>>,
63    valid_ids: OptionalCell<StoragePermissions>,
64}
65
66impl<'a, V: kv::KVPermissions<'a>> ListNode<'a, VirtualKVPermissions<'a, V>>
67    for VirtualKVPermissions<'a, V>
68{
69    fn next(&self) -> &'a ListLink<VirtualKVPermissions<'a, V>> {
70        &self.next
71    }
72}
73
74impl<'a, V: kv::KVPermissions<'a>> VirtualKVPermissions<'a, V> {
75    pub fn new(mux_kv: &'a MuxKVPermissions<'a, V>) -> VirtualKVPermissions<'a, V> {
76        Self {
77            mux_kv,
78            next: ListLink::empty(),
79            client: OptionalCell::empty(),
80            operation: OptionalCell::empty(),
81            key: MapCell::empty(),
82            value: MapCell::empty(),
83            valid_ids: OptionalCell::empty(),
84        }
85    }
86
87    pub fn setup(&'a self) {
88        self.mux_kv.users.push_head(self);
89    }
90
91    fn insert(
92        &self,
93        key: SubSliceMut<'static, u8>,
94        value: SubSliceMut<'static, u8>,
95        permissions: StoragePermissions,
96        operation: Operation,
97    ) -> Result<
98        (),
99        (
100            SubSliceMut<'static, u8>,
101            SubSliceMut<'static, u8>,
102            ErrorCode,
103        ),
104    > {
105        match permissions.get_write_id() {
106            Some(_write_id) => {}
107            None => return Err((key, value, ErrorCode::INVAL)),
108        }
109
110        if self.operation.is_some() {
111            return Err((key, value, ErrorCode::BUSY));
112        }
113
114        // The caller must ensure there is space for the header.
115        if value.len() < self.header_size() {
116            return Err((key, value, ErrorCode::SIZE));
117        }
118
119        self.operation.set(operation);
120        self.valid_ids.set(permissions);
121        self.key.replace(key);
122        self.value.replace(value);
123
124        self.mux_kv
125            .do_next_op(false)
126            .map_err(|e| (self.key.take().unwrap(), self.value.take().unwrap(), e))
127    }
128}
129
130impl<'a, V: kv::KVPermissions<'a>> kv::KVPermissions<'a> for VirtualKVPermissions<'a, V> {
131    fn set_client(&self, client: &'a dyn kv::KVClient) {
132        self.client.set(client);
133    }
134
135    fn get(
136        &self,
137        key: SubSliceMut<'static, u8>,
138        value: SubSliceMut<'static, u8>,
139        permissions: StoragePermissions,
140    ) -> Result<
141        (),
142        (
143            SubSliceMut<'static, u8>,
144            SubSliceMut<'static, u8>,
145            ErrorCode,
146        ),
147    > {
148        if self.operation.is_some() {
149            return Err((key, value, ErrorCode::BUSY));
150        }
151
152        self.operation.set(Operation::Get);
153        self.valid_ids.set(permissions);
154        self.key.replace(key);
155        self.value.replace(value);
156
157        self.mux_kv
158            .do_next_op(false)
159            .map_err(|e| (self.key.take().unwrap(), self.value.take().unwrap(), e))
160    }
161
162    fn set(
163        &self,
164        key: SubSliceMut<'static, u8>,
165        value: SubSliceMut<'static, u8>,
166        permissions: StoragePermissions,
167    ) -> Result<
168        (),
169        (
170            SubSliceMut<'static, u8>,
171            SubSliceMut<'static, u8>,
172            ErrorCode,
173        ),
174    > {
175        self.insert(key, value, permissions, Operation::Set)
176    }
177
178    fn add(
179        &self,
180        key: SubSliceMut<'static, u8>,
181        value: SubSliceMut<'static, u8>,
182        permissions: StoragePermissions,
183    ) -> Result<
184        (),
185        (
186            SubSliceMut<'static, u8>,
187            SubSliceMut<'static, u8>,
188            ErrorCode,
189        ),
190    > {
191        self.insert(key, value, permissions, Operation::Add)
192    }
193
194    fn update(
195        &self,
196        key: SubSliceMut<'static, u8>,
197        value: SubSliceMut<'static, u8>,
198        permissions: StoragePermissions,
199    ) -> Result<
200        (),
201        (
202            SubSliceMut<'static, u8>,
203            SubSliceMut<'static, u8>,
204            ErrorCode,
205        ),
206    > {
207        self.insert(key, value, permissions, Operation::Update)
208    }
209
210    fn delete(
211        &self,
212        key: SubSliceMut<'static, u8>,
213        permissions: StoragePermissions,
214    ) -> Result<(), (SubSliceMut<'static, u8>, ErrorCode)> {
215        if self.operation.is_some() {
216            return Err((key, ErrorCode::BUSY));
217        }
218
219        self.operation.set(Operation::Delete);
220        self.valid_ids.set(permissions);
221        self.key.replace(key);
222
223        self.mux_kv
224            .do_next_op(false)
225            .map_err(|e| (self.key.take().unwrap(), e))
226    }
227
228    fn garbage_collect(&self) -> Result<(), ErrorCode> {
229        if self.operation.is_some() {
230            return Err(ErrorCode::BUSY);
231        }
232
233        self.operation.set(Operation::GarbageCollect);
234
235        self.mux_kv.do_next_op(false)
236    }
237
238    fn header_size(&self) -> usize {
239        self.mux_kv.kv.header_size()
240    }
241}
242
243pub struct MuxKVPermissions<'a, V: kv::KVPermissions<'a>> {
244    kv: &'a V,
245    users: List<'a, VirtualKVPermissions<'a, V>>,
246    inflight: OptionalCell<&'a VirtualKVPermissions<'a, V>>,
247}
248
249impl<'a, V: kv::KVPermissions<'a>> MuxKVPermissions<'a, V> {
250    pub fn new(kv: &'a V) -> MuxKVPermissions<'a, V> {
251        Self {
252            kv,
253            inflight: OptionalCell::empty(),
254            users: List::new(),
255        }
256    }
257
258    fn do_next_op(&self, async_op: bool) -> Result<(), ErrorCode> {
259        // Find a virtual device which has pending work.
260        let mnode = self.users.iter().find(|node| node.operation.is_some());
261
262        mnode.map_or(Ok(()), |node| {
263            node.operation.map_or(Ok(()), |op| {
264                // GarbageCollect doesn't have a key, so we check it above
265                // the match case below
266                if op == Operation::GarbageCollect {
267                    return match self.kv.garbage_collect() {
268                        Ok(()) => {
269                            self.inflight.set(node);
270                            Ok(())
271                        }
272                        Err(e) => {
273                            node.operation.clear();
274                            if async_op {
275                                node.client.map(move |cb| {
276                                    cb.garbage_collection_complete(Err(e));
277                                });
278                                Ok(())
279                            } else {
280                                Err(e)
281                            }
282                        }
283                    };
284                }
285
286                node.key.take().map_or(Ok(()), |key| match op {
287                    Operation::Get => node.value.take().map_or(Ok(()), |value| {
288                        node.valid_ids.map_or(Ok(()), |perms| {
289                            match self.kv.get(key, value, perms) {
290                                Ok(()) => {
291                                    self.inflight.set(node);
292                                    Ok(())
293                                }
294                                Err((key, value, e)) => {
295                                    node.operation.clear();
296                                    if async_op {
297                                        node.client.map(move |cb| {
298                                            cb.get_complete(Err(e), key, value);
299                                        });
300                                        Ok(())
301                                    } else {
302                                        node.key.replace(key);
303                                        node.value.replace(value);
304                                        Err(e)
305                                    }
306                                }
307                            }
308                        })
309                    }),
310                    Operation::Set => node.value.take().map_or(Ok(()), |value| {
311                        node.valid_ids.map_or(Ok(()), |perms| {
312                            match self.kv.set(key, value, perms) {
313                                Ok(()) => {
314                                    self.inflight.set(node);
315                                    Ok(())
316                                }
317                                Err((key, value, e)) => {
318                                    node.operation.clear();
319                                    if async_op {
320                                        node.client.map(move |cb| {
321                                            cb.set_complete(Err(e), key, value);
322                                        });
323                                        Ok(())
324                                    } else {
325                                        node.key.replace(key);
326                                        node.value.replace(value);
327                                        Err(e)
328                                    }
329                                }
330                            }
331                        })
332                    }),
333                    Operation::Add => node.value.take().map_or(Ok(()), |value| {
334                        node.valid_ids.map_or(Ok(()), |perms| {
335                            match self.kv.add(key, value, perms) {
336                                Ok(()) => {
337                                    self.inflight.set(node);
338                                    Ok(())
339                                }
340                                Err((key, value, e)) => {
341                                    node.operation.clear();
342                                    if async_op {
343                                        node.client.map(move |cb| {
344                                            cb.add_complete(Err(e), key, value);
345                                        });
346                                        Ok(())
347                                    } else {
348                                        node.key.replace(key);
349                                        node.value.replace(value);
350                                        Err(e)
351                                    }
352                                }
353                            }
354                        })
355                    }),
356                    Operation::Update => node.value.take().map_or(Ok(()), |value| {
357                        node.valid_ids.map_or(Ok(()), |perms| {
358                            match self.kv.update(key, value, perms) {
359                                Ok(()) => {
360                                    self.inflight.set(node);
361                                    Ok(())
362                                }
363                                Err((key, value, e)) => {
364                                    node.operation.clear();
365                                    if async_op {
366                                        node.client.map(move |cb| {
367                                            cb.update_complete(Err(e), key, value);
368                                        });
369                                        Ok(())
370                                    } else {
371                                        node.key.replace(key);
372                                        node.value.replace(value);
373                                        Err(e)
374                                    }
375                                }
376                            }
377                        })
378                    }),
379                    Operation::Delete => {
380                        node.valid_ids
381                            .map_or(Ok(()), |perms| match self.kv.delete(key, perms) {
382                                Ok(()) => {
383                                    self.inflight.set(node);
384                                    Ok(())
385                                }
386                                Err((key, e)) => {
387                                    node.operation.clear();
388                                    if async_op {
389                                        node.client.map(move |cb| {
390                                            cb.delete_complete(Err(e), key);
391                                        });
392                                        Ok(())
393                                    } else {
394                                        node.key.replace(key);
395                                        Err(e)
396                                    }
397                                }
398                            })
399                    }
400                    Operation::GarbageCollect => Err(ErrorCode::NOSUPPORT),
401                })
402            })
403        })
404    }
405}
406
407impl<'a, V: kv::KVPermissions<'a>> kv::KVClient for MuxKVPermissions<'a, V> {
408    fn get_complete(
409        &self,
410        result: Result<(), ErrorCode>,
411        key: SubSliceMut<'static, u8>,
412        value: SubSliceMut<'static, u8>,
413    ) {
414        self.inflight.take().map(|node| {
415            node.operation.clear();
416            node.client.map(move |cb| {
417                cb.get_complete(result, key, value);
418            });
419        });
420
421        let _ = self.do_next_op(true);
422    }
423
424    fn set_complete(
425        &self,
426        result: Result<(), ErrorCode>,
427        key: SubSliceMut<'static, u8>,
428        value: SubSliceMut<'static, u8>,
429    ) {
430        self.inflight.take().map(|node| {
431            node.operation.clear();
432            node.client.map(move |cb| {
433                cb.set_complete(result, key, value);
434            });
435        });
436
437        let _ = self.do_next_op(true);
438    }
439
440    fn add_complete(
441        &self,
442        result: Result<(), ErrorCode>,
443        key: SubSliceMut<'static, u8>,
444        value: SubSliceMut<'static, u8>,
445    ) {
446        self.inflight.take().map(|node| {
447            node.operation.clear();
448            node.client.map(move |cb| {
449                cb.add_complete(result, key, value);
450            });
451        });
452
453        let _ = self.do_next_op(true);
454    }
455
456    fn update_complete(
457        &self,
458        result: Result<(), ErrorCode>,
459        key: SubSliceMut<'static, u8>,
460        value: SubSliceMut<'static, u8>,
461    ) {
462        self.inflight.take().map(|node| {
463            node.operation.clear();
464            node.client.map(move |cb| {
465                cb.update_complete(result, key, value);
466            });
467        });
468
469        let _ = self.do_next_op(true);
470    }
471
472    fn delete_complete(&self, result: Result<(), ErrorCode>, key: SubSliceMut<'static, u8>) {
473        self.inflight.take().map(|node| {
474            node.operation.clear();
475            node.client.map(move |cb| {
476                cb.delete_complete(result, key);
477            });
478        });
479
480        let _ = self.do_next_op(true);
481    }
482
483    fn garbage_collection_complete(&self, result: Result<(), ErrorCode>) {
484        self.inflight.take().map(|node| {
485            node.operation.clear();
486            node.client.map(move |cb| {
487                cb.garbage_collection_complete(result);
488            });
489        });
490
491        let _ = self.do_next_op(true);
492    }
493}