blob: 8c3fab04a0f16f820409e471dde1b42e97c04b82 [file] [log] [blame]
Colin Cross28fa5bc2012-05-20 13:28:05 -07001/*
2 * Copyright (C) 2010 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
Colin Crossb55dcee2012-04-24 23:07:49 -070017#include <assert.h>
18#include <errno.h>
19#include <stdint.h>
Colin Cross28fa5bc2012-05-20 13:28:05 -070020#include <stdlib.h>
21#include <string.h>
22
23#include "backed_block.h"
Colin Cross28fa5bc2012-05-20 13:28:05 -070024
Colin Crossb55dcee2012-04-24 23:07:49 -070025struct backed_block {
26 unsigned int block;
27 unsigned int len;
28 enum backed_block_type type;
29 union {
30 struct {
31 void *data;
32 } data;
33 struct {
34 char *filename;
35 int64_t offset;
36 } file;
37 struct {
Colin Cross9e1f17e2012-04-25 18:31:39 -070038 int fd;
39 int64_t offset;
40 } fd;
41 struct {
Colin Crossb55dcee2012-04-24 23:07:49 -070042 uint32_t val;
43 } fill;
44 };
45 struct backed_block *next;
Colin Cross28fa5bc2012-05-20 13:28:05 -070046};
47
Colin Cross411619e2012-04-24 18:51:42 -070048struct backed_block_list {
Colin Crossb55dcee2012-04-24 23:07:49 -070049 struct backed_block *data_blocks;
50 struct backed_block *last_used;
Colin Cross411619e2012-04-24 18:51:42 -070051};
Colin Cross28fa5bc2012-05-20 13:28:05 -070052
Colin Crossb55dcee2012-04-24 23:07:49 -070053struct backed_block *backed_block_iter_new(struct backed_block_list *bbl)
54{
55 return bbl->data_blocks;
56}
57
58struct backed_block *backed_block_iter_next(struct backed_block *bb)
59{
60 return bb->next;
61}
62
63unsigned int backed_block_len(struct backed_block *bb)
64{
65 return bb->len;
66}
67
68unsigned int backed_block_block(struct backed_block *bb)
69{
70 return bb->block;
71}
72
73void *backed_block_data(struct backed_block *bb)
74{
75 assert(bb->type == BACKED_BLOCK_DATA);
76 return bb->data.data;
77}
78
79const char *backed_block_filename(struct backed_block *bb)
80{
81 assert(bb->type == BACKED_BLOCK_FILE);
82 return bb->file.filename;
83}
84
Colin Cross9e1f17e2012-04-25 18:31:39 -070085int backed_block_fd(struct backed_block *bb)
86{
87 assert(bb->type == BACKED_BLOCK_FD);
88 return bb->fd.fd;
89}
90
Colin Crossb55dcee2012-04-24 23:07:49 -070091int64_t backed_block_file_offset(struct backed_block *bb)
92{
Colin Cross9e1f17e2012-04-25 18:31:39 -070093 assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD);
94 if (bb->type == BACKED_BLOCK_FILE) {
95 return bb->file.offset;
96 } else { /* bb->type == BACKED_BLOCK_FD */
97 return bb->fd.offset;
98 }
Colin Crossb55dcee2012-04-24 23:07:49 -070099}
100
101uint32_t backed_block_fill_val(struct backed_block *bb)
102{
103 assert(bb->type == BACKED_BLOCK_FILL);
104 return bb->fill.val;
105}
106
107enum backed_block_type backed_block_type(struct backed_block *bb)
108{
109 return bb->type;
110}
111
Colin Cross411619e2012-04-24 18:51:42 -0700112struct backed_block_list *backed_block_list_new(void)
113{
114 struct backed_block_list *b = calloc(sizeof(struct backed_block_list), 1);
115
116 return b;
117}
118
Colin Crossb55dcee2012-04-24 23:07:49 -0700119void backed_block_list_destroy(struct backed_block_list *bbl)
Colin Cross411619e2012-04-24 18:51:42 -0700120{
Colin Crossb55dcee2012-04-24 23:07:49 -0700121 if (bbl->data_blocks) {
122 struct backed_block *bb = bbl->data_blocks;
123 while (bb) {
124 struct backed_block *next = bb->next;
125 if (bb->type == BACKED_BLOCK_FILE) {
126 free(bb->file.filename);
127 }
Colin Cross411619e2012-04-24 18:51:42 -0700128
Colin Crossb55dcee2012-04-24 23:07:49 -0700129 free(bb);
130 bb = next;
Colin Cross411619e2012-04-24 18:51:42 -0700131 }
132 }
133
Colin Crossb55dcee2012-04-24 23:07:49 -0700134 free(bbl);
Colin Cross411619e2012-04-24 18:51:42 -0700135}
136
Colin Crossb55dcee2012-04-24 23:07:49 -0700137static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb)
Colin Cross28fa5bc2012-05-20 13:28:05 -0700138{
Colin Crossb55dcee2012-04-24 23:07:49 -0700139 struct backed_block *bb;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700140
Colin Crossb55dcee2012-04-24 23:07:49 -0700141 if (bbl->data_blocks == NULL) {
142 bbl->data_blocks = new_bb;
143 return 0;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700144 }
145
Colin Crossb55dcee2012-04-24 23:07:49 -0700146 if (bbl->data_blocks->block > new_bb->block) {
147 new_bb->next = bbl->data_blocks;
148 bbl->data_blocks = new_bb;
149 return 0;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700150 }
151
152 /* Optimization: blocks are mostly queued in sequence, so save the
Colin Crossb55dcee2012-04-24 23:07:49 -0700153 pointer to the last bb that was added, and start searching from
Colin Cross28fa5bc2012-05-20 13:28:05 -0700154 there if the next block number is higher */
Colin Crossb55dcee2012-04-24 23:07:49 -0700155 if (bbl->last_used && new_bb->block > bbl->last_used->block)
156 bb = bbl->last_used;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700157 else
Colin Crossb55dcee2012-04-24 23:07:49 -0700158 bb = bbl->data_blocks;
159 bbl->last_used = new_bb;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700160
Colin Crossb55dcee2012-04-24 23:07:49 -0700161 for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
Colin Cross28fa5bc2012-05-20 13:28:05 -0700162 ;
163
Colin Crossb55dcee2012-04-24 23:07:49 -0700164 if (bb->next == NULL) {
165 bb->next = new_bb;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700166 } else {
Colin Crossb55dcee2012-04-24 23:07:49 -0700167 new_bb->next = bb->next;
168 bb->next = new_bb;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700169 }
Colin Crossb55dcee2012-04-24 23:07:49 -0700170
171 return 0;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700172}
173
174/* Queues a fill block of memory to be written to the specified data blocks */
Colin Crossb55dcee2012-04-24 23:07:49 -0700175int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val,
Colin Cross411619e2012-04-24 18:51:42 -0700176 unsigned int len, unsigned int block)
Colin Cross28fa5bc2012-05-20 13:28:05 -0700177{
Colin Crossb55dcee2012-04-24 23:07:49 -0700178 struct backed_block *bb = calloc(1, sizeof(struct backed_block));
179 if (bb == NULL) {
180 return -ENOMEM;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700181 }
182
Colin Crossb55dcee2012-04-24 23:07:49 -0700183 bb->block = block;
184 bb->len = len;
185 bb->type = BACKED_BLOCK_FILL;
186 bb->fill.val = fill_val;
187 bb->next = NULL;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700188
Colin Crossb55dcee2012-04-24 23:07:49 -0700189 return queue_bb(bbl, bb);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700190}
191
192/* Queues a block of memory to be written to the specified data blocks */
Colin Crossb55dcee2012-04-24 23:07:49 -0700193int backed_block_add_data(struct backed_block_list *bbl, void *data,
194 unsigned int len, unsigned int block)
Colin Cross28fa5bc2012-05-20 13:28:05 -0700195{
Colin Crossb55dcee2012-04-24 23:07:49 -0700196 struct backed_block *bb = calloc(1, sizeof(struct backed_block));
197 if (bb == NULL) {
198 return -ENOMEM;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700199 }
200
Colin Crossb55dcee2012-04-24 23:07:49 -0700201 bb->block = block;
202 bb->len = len;
203 bb->type = BACKED_BLOCK_DATA;
204 bb->data.data = data;
205 bb->next = NULL;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700206
Colin Crossb55dcee2012-04-24 23:07:49 -0700207 return queue_bb(bbl, bb);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700208}
209
210/* Queues a chunk of a file on disk to be written to the specified data blocks */
Colin Crossb55dcee2012-04-24 23:07:49 -0700211int backed_block_add_file(struct backed_block_list *bbl, const char *filename,
Colin Cross411619e2012-04-24 18:51:42 -0700212 int64_t offset, unsigned int len, unsigned int block)
Colin Cross28fa5bc2012-05-20 13:28:05 -0700213{
Colin Crossb55dcee2012-04-24 23:07:49 -0700214 struct backed_block *bb = calloc(1, sizeof(struct backed_block));
215 if (bb == NULL) {
216 return -ENOMEM;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700217 }
218
Colin Crossb55dcee2012-04-24 23:07:49 -0700219 bb->block = block;
220 bb->len = len;
221 bb->type = BACKED_BLOCK_FILE;
222 bb->file.filename = strdup(filename);
223 bb->file.offset = offset;
224 bb->next = NULL;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700225
Colin Crossb55dcee2012-04-24 23:07:49 -0700226 return queue_bb(bbl, bb);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700227}
Colin Cross9e1f17e2012-04-25 18:31:39 -0700228
229/* Queues a chunk of a fd to be written to the specified data blocks */
230int backed_block_add_fd(struct backed_block_list *bbl, int fd, int64_t offset,
231 unsigned int len, unsigned int block)
232{
233 struct backed_block *bb = calloc(1, sizeof(struct backed_block));
234 if (bb == NULL) {
235 return -ENOMEM;
236 }
237
238 bb->block = block;
239 bb->len = len;
240 bb->type = BACKED_BLOCK_FD;
241 bb->fd.fd = fd;
242 bb->fd.offset = offset;
243 bb->next = NULL;
244
245 return queue_bb(bbl, bb);
246}