1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <lk/reflist.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 
23 #include "block_device.h"
24 #include "crypt.h"
25 
26 #ifdef APP_STORAGE_BLOCK_CACHE_SIZE
27 #define BLOCK_CACHE_SIZE (APP_STORAGE_BLOCK_CACHE_SIZE)
28 #else
29 #define BLOCK_CACHE_SIZE (64)
30 #endif
31 #ifdef APP_STORAGE_MAIN_BLOCK_SIZE
32 #define MAX_BLOCK_SIZE (APP_STORAGE_MAIN_BLOCK_SIZE)
33 #else
34 #define MAX_BLOCK_SIZE (2048)
35 #endif
36 
37 /**
38  * enum block_cache_entry_data_state - State of a block cache entry's data
39  * @BLOCK_ENTRY_DATA_INVALID:     Block entry does not contain valid data.
40  * @BLOCK_ENTRY_DATA_LOADING:     Block entry data load is pending. State will
41  *                                be updated when the load operation completes.
42  * @BLOCK_ENTRY_DATA_LOAD_FAILED: Block data could not be loaded from the disk.
43  *                                This may be caused by a transient I/O error.
44  * @BLOCK_ENTRY_DATA_NOT_FOUND:   Block does not exist on disk.
45  * @BLOCK_ENTRY_DATA_CLEAN_DECRYPTED: Block entry contains valid plaintext data
46  *                                    that is either on disk or queued to be
47  *                                    written to disk
48  * @BLOCK_ENTRY_DATA_CLEAN_ENCRYPTED: Block entry contains valid ciphertext data
49  *                                    that is either on disk or queued to be
50  *                                    written to disk.
51  * @BLOCK_ENTRY_DATA_DIRTY_DECRYPTED: Block entry contains valid plaintext data
52  *                                    that has not yet been queued for write
53  *                                    back to disk. Data must be encrypted and
54  *                                    written back or discarded before the cache
55  *                                    entry can be reused.
56  * @BLOCK_ENTRY_DATA_DIRTY_ENCRYPTED: Block entry contains valid ciphertext data
57  *                                    that has not yet been queued for write
58  *                                    back to disk. Data must be written back or
59  *                                    discarded before the cache entry can be
60  *                                    reused.
61  */
62 enum block_cache_entry_data_state {
63     BLOCK_ENTRY_DATA_INVALID = 0,
64     BLOCK_ENTRY_DATA_LOADING,
65     BLOCK_ENTRY_DATA_LOAD_FAILED,
66     BLOCK_ENTRY_DATA_NOT_FOUND,
67     BLOCK_ENTRY_DATA_CLEAN_DECRYPTED,
68     BLOCK_ENTRY_DATA_CLEAN_ENCRYPTED,
69     BLOCK_ENTRY_DATA_DIRTY_DECRYPTED,
70     BLOCK_ENTRY_DATA_DIRTY_ENCRYPTED,
71 };
72 
73 /**
74  * struct block_cache_entry - block cache entry
75  * @guard1:                 Set to BLOCK_CACHE_GUARD_1 to detect out of bound
76  *                          writes to data.
77  * @data:                   Decrypted block data.
78  * @guard2:                 Set to BLOCK_CACHE_GUARD_2 to detect out of bound
79  *                          writes to data.
80  * @key:                    Key to use for encrypt, decrypt and calculate_mac.
81  * @dev:                    Device that block was read from and will be written
82  *                          to.
83  * @block:                  Block number in dev.
84  * @block_size:             Size of block, but match dev->block_size.
85  * @mac:                    Last calculated mac of encrypted block data.
86  * @state:                  Current state of @data, indicating if data has been
87  *                          loaded from disk or written into this cache entry.
88  *                          This state is reset to %BLOCK_ENTRY_INVALID when a
89  *                          cache entry previously containing a different block
90  *                          is selected for reuse. See &enum
91  *                          block_cache_entry_state for details.
92  * @encrypted:              %true if @data is currently encrypted.
93  * @dirty_ref:              Data is currently being modified. Only a single
94  *                          reference should be allowed.
95  * @dirty_mac:              Data has been modified. Mac needs to be updated
96  *                          after encrypting block.
97  * @dirty_tmp:              Data can be discarded by
98  *                          block_cache_discard_transaction.
99  * @pinned:                 Block cannot be reused if it fails to write.
100  * @is_superblock:          Block is used as a superblock and files should be
101  *                          synced before it is written.
102  * @dirty_tr:               Transaction that modified block.
103  * @obj:                    Reference tracking struct.
104  * @lru_node:               List node for tracking least recently used cache
105  *                          entries.
106  * @io_op_node:             List node for tracking active read and write
107  *                          operations.
108  * @io_op:                  Currently active io operation.
109  *
110  * @dirty_ref, @dirty_mac, @dirty_tmp, and @dirty_tr are only relevant if @state
111  * is %BLOCK_ENTRY_DATA_DIRTY, i.e. @data has been modified and not yet queued
112  * for write or discarded.
113  */
114 struct block_cache_entry {
115     uint64_t guard1;
116     uint8_t data[MAX_BLOCK_SIZE];
117     uint64_t guard2;
118 
119     const struct key* key;
120     struct block_device* dev;
121     data_block_t block;
122     size_t block_size;
123     struct mac mac;
124     enum block_cache_entry_data_state state;
125     bool dirty_ref;
126     bool dirty_mac;
127     bool dirty_tmp;
128     bool pinned;
129     bool is_superblock;
130     struct transaction* dirty_tr;
131 
132     struct obj obj;
133     struct list_node lru_node;
134     struct list_node io_op_node;
135     enum {
136         BLOCK_CACHE_IO_OP_NONE,
137         BLOCK_CACHE_IO_OP_READ,
138         BLOCK_CACHE_IO_OP_WRITE,
139     } io_op;
140 };
141 
142 #define BLOCK_CACHE_SIZE_BYTES \
143     (sizeof(struct block_cache_entry[BLOCK_CACHE_SIZE]))
144