backed_block.c revision b55dceea986ab24f8b836b5116b389ed619c816e
1/* 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 17#include <assert.h> 18#include <errno.h> 19#include <stdint.h> 20#include <stdlib.h> 21#include <string.h> 22 23#include "backed_block.h" 24 25struct 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 { 38 uint32_t val; 39 } fill; 40 }; 41 struct backed_block *next; 42}; 43 44struct backed_block_list { 45 struct backed_block *data_blocks; 46 struct backed_block *last_used; 47}; 48 49struct backed_block *backed_block_iter_new(struct backed_block_list *bbl) 50{ 51 return bbl->data_blocks; 52} 53 54struct backed_block *backed_block_iter_next(struct backed_block *bb) 55{ 56 return bb->next; 57} 58 59unsigned int backed_block_len(struct backed_block *bb) 60{ 61 return bb->len; 62} 63 64unsigned int backed_block_block(struct backed_block *bb) 65{ 66 return bb->block; 67} 68 69void *backed_block_data(struct backed_block *bb) 70{ 71 assert(bb->type == BACKED_BLOCK_DATA); 72 return bb->data.data; 73} 74 75const char *backed_block_filename(struct backed_block *bb) 76{ 77 assert(bb->type == BACKED_BLOCK_FILE); 78 return bb->file.filename; 79} 80 81int64_t backed_block_file_offset(struct backed_block *bb) 82{ 83 assert(bb->type == BACKED_BLOCK_FILE); 84 return bb->file.offset; 85} 86 87uint32_t backed_block_fill_val(struct backed_block *bb) 88{ 89 assert(bb->type == BACKED_BLOCK_FILL); 90 return bb->fill.val; 91} 92 93enum backed_block_type backed_block_type(struct backed_block *bb) 94{ 95 return bb->type; 96} 97 98struct backed_block_list *backed_block_list_new(void) 99{ 100 struct backed_block_list *b = calloc(sizeof(struct backed_block_list), 1); 101 102 return b; 103} 104 105void backed_block_list_destroy(struct backed_block_list *bbl) 106{ 107 if (bbl->data_blocks) { 108 struct backed_block *bb = bbl->data_blocks; 109 while (bb) { 110 struct backed_block *next = bb->next; 111 if (bb->type == BACKED_BLOCK_FILE) { 112 free(bb->file.filename); 113 } 114 115 free(bb); 116 bb = next; 117 } 118 } 119 120 free(bbl); 121} 122 123static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb) 124{ 125 struct backed_block *bb; 126 127 if (bbl->data_blocks == NULL) { 128 bbl->data_blocks = new_bb; 129 return 0; 130 } 131 132 if (bbl->data_blocks->block > new_bb->block) { 133 new_bb->next = bbl->data_blocks; 134 bbl->data_blocks = new_bb; 135 return 0; 136 } 137 138 /* Optimization: blocks are mostly queued in sequence, so save the 139 pointer to the last bb that was added, and start searching from 140 there if the next block number is higher */ 141 if (bbl->last_used && new_bb->block > bbl->last_used->block) 142 bb = bbl->last_used; 143 else 144 bb = bbl->data_blocks; 145 bbl->last_used = new_bb; 146 147 for (; bb->next && bb->next->block < new_bb->block; bb = bb->next) 148 ; 149 150 if (bb->next == NULL) { 151 bb->next = new_bb; 152 } else { 153 new_bb->next = bb->next; 154 bb->next = new_bb; 155 } 156 157 return 0; 158} 159 160/* Queues a fill block of memory to be written to the specified data blocks */ 161int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val, 162 unsigned int len, unsigned int block) 163{ 164 struct backed_block *bb = calloc(1, sizeof(struct backed_block)); 165 if (bb == NULL) { 166 return -ENOMEM; 167 } 168 169 bb->block = block; 170 bb->len = len; 171 bb->type = BACKED_BLOCK_FILL; 172 bb->fill.val = fill_val; 173 bb->next = NULL; 174 175 return queue_bb(bbl, bb); 176} 177 178/* Queues a block of memory to be written to the specified data blocks */ 179int backed_block_add_data(struct backed_block_list *bbl, void *data, 180 unsigned int len, unsigned int block) 181{ 182 struct backed_block *bb = calloc(1, sizeof(struct backed_block)); 183 if (bb == NULL) { 184 return -ENOMEM; 185 } 186 187 bb->block = block; 188 bb->len = len; 189 bb->type = BACKED_BLOCK_DATA; 190 bb->data.data = data; 191 bb->next = NULL; 192 193 return queue_bb(bbl, bb); 194} 195 196/* Queues a chunk of a file on disk to be written to the specified data blocks */ 197int backed_block_add_file(struct backed_block_list *bbl, const char *filename, 198 int64_t offset, unsigned int len, unsigned int block) 199{ 200 struct backed_block *bb = calloc(1, sizeof(struct backed_block)); 201 if (bb == NULL) { 202 return -ENOMEM; 203 } 204 205 bb->block = block; 206 bb->len = len; 207 bb->type = BACKED_BLOCK_FILE; 208 bb->file.filename = strdup(filename); 209 bb->file.offset = offset; 210 bb->next = NULL; 211 212 return queue_bb(bbl, bb); 213} 214