libsparse: remove static variables
Removes static variables in backed_block.c to allow multiple sparse files to be open at the same time. Change-Id: I012d8a424c6e21a7352408416adb7c72ee8add21
This commit is contained in:
parent
28fa5bc347
commit
411619e921
|
@ -33,32 +33,57 @@ struct data_block {
|
|||
u16 pad2;
|
||||
};
|
||||
|
||||
static struct data_block *data_blocks = NULL;
|
||||
static struct data_block *last_used = NULL;
|
||||
struct backed_block_list {
|
||||
struct data_block *data_blocks;
|
||||
struct data_block *last_used;
|
||||
};
|
||||
|
||||
static void queue_db(struct data_block *new_db)
|
||||
struct backed_block_list *backed_block_list_new(void)
|
||||
{
|
||||
struct backed_block_list *b = calloc(sizeof(struct backed_block_list), 1);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void backed_block_list_destroy(struct backed_block_list *b)
|
||||
{
|
||||
if (b->data_blocks) {
|
||||
struct data_block *db = b->data_blocks;
|
||||
while (db) {
|
||||
struct data_block *next = db->next;
|
||||
free((void*)db->filename);
|
||||
|
||||
free(db);
|
||||
db = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(b);
|
||||
}
|
||||
|
||||
static void queue_db(struct backed_block_list *b, struct data_block *new_db)
|
||||
{
|
||||
struct data_block *db;
|
||||
|
||||
if (data_blocks == NULL) {
|
||||
data_blocks = new_db;
|
||||
if (b->data_blocks == NULL) {
|
||||
b->data_blocks = new_db;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_blocks->block > new_db->block) {
|
||||
new_db->next = data_blocks;
|
||||
data_blocks = new_db;
|
||||
if (b->data_blocks->block > new_db->block) {
|
||||
new_db->next = b->data_blocks;
|
||||
b->data_blocks = new_db;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Optimization: blocks are mostly queued in sequence, so save the
|
||||
pointer to the last db that was added, and start searching from
|
||||
there if the next block number is higher */
|
||||
if (last_used && new_db->block > last_used->block)
|
||||
db = last_used;
|
||||
if (b->last_used && new_db->block > b->last_used->block)
|
||||
db = b->last_used;
|
||||
else
|
||||
db = data_blocks;
|
||||
last_used = new_db;
|
||||
db = b->data_blocks;
|
||||
b->last_used = new_db;
|
||||
|
||||
for (; db->next && db->next->block < new_db->block; db = db->next)
|
||||
;
|
||||
|
@ -72,9 +97,10 @@ static void queue_db(struct data_block *new_db)
|
|||
}
|
||||
|
||||
/* Queues a fill block of memory to be written to the specified data blocks */
|
||||
void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int block)
|
||||
void queue_fill_block(struct backed_block_list *b, unsigned int fill_val,
|
||||
unsigned int len, unsigned int block)
|
||||
{
|
||||
struct data_block *db = malloc(sizeof(struct data_block));
|
||||
struct data_block *db = calloc(1, sizeof(struct data_block));
|
||||
if (db == NULL) {
|
||||
error_errno("malloc");
|
||||
return;
|
||||
|
@ -88,11 +114,12 @@ void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int bloc
|
|||
db->filename = NULL;
|
||||
db->next = NULL;
|
||||
|
||||
queue_db(db);
|
||||
queue_db(b, db);
|
||||
}
|
||||
|
||||
/* Queues a block of memory to be written to the specified data blocks */
|
||||
void queue_data_block(void *data, unsigned int len, unsigned int block)
|
||||
void queue_data_block(struct backed_block_list *b, void *data, unsigned int len,
|
||||
unsigned int block)
|
||||
{
|
||||
struct data_block *db = malloc(sizeof(struct data_block));
|
||||
if (db == NULL) {
|
||||
|
@ -107,12 +134,12 @@ void queue_data_block(void *data, unsigned int len, unsigned int block)
|
|||
db->fill = 0;
|
||||
db->next = NULL;
|
||||
|
||||
queue_db(db);
|
||||
queue_db(b, db);
|
||||
}
|
||||
|
||||
/* Queues a chunk of a file on disk to be written to the specified data blocks */
|
||||
void queue_data_file(const char *filename, int64_t offset, unsigned int len,
|
||||
unsigned int block)
|
||||
void queue_data_file(struct backed_block_list *b, const char *filename,
|
||||
int64_t offset, unsigned int len, unsigned int block)
|
||||
{
|
||||
struct data_block *db = malloc(sizeof(struct data_block));
|
||||
if (db == NULL) {
|
||||
|
@ -128,19 +155,21 @@ void queue_data_file(const char *filename, int64_t offset, unsigned int len,
|
|||
db->fill = 0;
|
||||
db->next = NULL;
|
||||
|
||||
queue_db(db);
|
||||
queue_db(b, db);
|
||||
}
|
||||
|
||||
/* Iterates over the queued data blocks, calling data_func for each contiguous
|
||||
data block, and file_func for each contiguous file block */
|
||||
void for_each_data_block(data_block_callback_t data_func,
|
||||
void for_each_data_block(struct backed_block_list *b,
|
||||
data_block_callback_t data_func,
|
||||
data_block_file_callback_t file_func,
|
||||
data_block_fill_callback_t fill_func, void *priv, unsigned int block_size)
|
||||
data_block_fill_callback_t fill_func,
|
||||
void *priv, unsigned int block_size)
|
||||
{
|
||||
struct data_block *db;
|
||||
u32 last_block = 0;
|
||||
|
||||
for (db = data_blocks; db; db = db->next) {
|
||||
for (db = b->data_blocks; db; db = db->next) {
|
||||
if (db->block < last_block)
|
||||
error("data blocks out of order: %u < %u", db->block, last_block);
|
||||
last_block = db->block + DIV_ROUND_UP(db->len, block_size) - 1;
|
||||
|
@ -153,27 +182,3 @@ void for_each_data_block(data_block_callback_t data_func,
|
|||
data_func(priv, (u64)db->block * block_size, db->data, db->len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Frees the memory used by the linked list of data blocks */
|
||||
void free_data_blocks()
|
||||
{
|
||||
if (!data_blocks) return;
|
||||
struct data_block *db = data_blocks;
|
||||
while (db) {
|
||||
struct data_block *next = db->next;
|
||||
free((void*)db->filename);
|
||||
|
||||
// There used to be a free() of db->data here, but it
|
||||
// made the function crash since queue_data_block() is
|
||||
// sometimes passed pointers it can't take ownership of
|
||||
// (like a pointer into the middle of an allocated
|
||||
// block). It's not clear what the queue_data_block
|
||||
// contract is supposed to be, but we'd rather leak
|
||||
// memory than crash.
|
||||
|
||||
free(db);
|
||||
db = next;
|
||||
}
|
||||
data_blocks = NULL;
|
||||
last_used = NULL;
|
||||
}
|
||||
|
|
|
@ -17,23 +17,29 @@
|
|||
#ifndef _BACKED_BLOCK_H_
|
||||
#define _BACKED_BLOCK_H_
|
||||
|
||||
#include <sparse/sparse.h>
|
||||
struct backed_block_list;
|
||||
|
||||
typedef void (*data_block_callback_t)(void *priv, int64_t off, void *data, int len);
|
||||
typedef void (*data_block_fill_callback_t)(void *priv, int64_t off, unsigned int fill_val, int len);
|
||||
typedef void (*data_block_callback_t)(void *priv, int64_t off, void *data,
|
||||
int len);
|
||||
typedef void (*data_block_fill_callback_t)(void *priv, int64_t off,
|
||||
unsigned int fill_val, int len);
|
||||
typedef void (*data_block_file_callback_t)(void *priv, int64_t off,
|
||||
const char *file, int64_t offset,
|
||||
int len);
|
||||
const char *file, int64_t offset, int len);
|
||||
|
||||
void for_each_data_block(data_block_callback_t data_func,
|
||||
void for_each_data_block(struct backed_block_list *b,
|
||||
data_block_callback_t data_func,
|
||||
data_block_file_callback_t file_func,
|
||||
data_block_fill_callback_t fill_func, void *priv, unsigned int);
|
||||
data_block_fill_callback_t fill_func,
|
||||
void *priv, unsigned int);
|
||||
|
||||
void queue_data_block(void *data, unsigned int len, unsigned int block);
|
||||
void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int block);
|
||||
void queue_data_file(const char *filename, int64_t offset, unsigned int len,
|
||||
void queue_data_block(struct backed_block_list *b,void *data, unsigned int len,
|
||||
unsigned int block);
|
||||
void queue_fill_block(struct backed_block_list *b,unsigned int fill_val,
|
||||
unsigned int len, unsigned int block);
|
||||
void queue_data_file(struct backed_block_list *b,const char *filename,
|
||||
int64_t offset, unsigned int len, unsigned int block);
|
||||
|
||||
void free_data_blocks();
|
||||
struct backed_block_list *backed_block_list_new(void);
|
||||
void backed_block_list_destroy(struct backed_block_list *b);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,7 +32,11 @@ struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO: allocate backed block list */
|
||||
s->backed_block_list = backed_block_list_new();
|
||||
if (!s->backed_block_list) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->block_size = block_size;
|
||||
s->len = len;
|
||||
|
@ -42,14 +46,14 @@ struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len)
|
|||
|
||||
void sparse_file_destroy(struct sparse_file *s)
|
||||
{
|
||||
free_data_blocks();
|
||||
backed_block_list_destroy(s->backed_block_list);
|
||||
free(s);
|
||||
}
|
||||
|
||||
int sparse_file_add_data(struct sparse_file *s,
|
||||
void *data, unsigned int len, unsigned int block)
|
||||
{
|
||||
queue_data_block(data, len, block);
|
||||
queue_data_block(s->backed_block_list, data, len, block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,7 +61,7 @@ int sparse_file_add_data(struct sparse_file *s,
|
|||
int sparse_file_add_fill(struct sparse_file *s,
|
||||
uint32_t fill_val, unsigned int len, unsigned int block)
|
||||
{
|
||||
queue_fill_block(fill_val, len, block);
|
||||
queue_fill_block(s->backed_block_list, fill_val, len, block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,7 +70,7 @@ int sparse_file_add_file(struct sparse_file *s,
|
|||
const char *filename, int64_t file_offset, unsigned int len,
|
||||
unsigned int block)
|
||||
{
|
||||
queue_data_file(filename, file_offset, len, block);
|
||||
queue_data_file(s->backed_block_list, filename, file_offset, len, block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -105,11 +109,13 @@ static void count_file_block(void *priv, int64_t off, const char *file,
|
|||
count_chunks->chunks++;
|
||||
}
|
||||
|
||||
static int count_sparse_chunks(unsigned int block_size, int64_t len)
|
||||
static int count_sparse_chunks(struct backed_block_list *b,
|
||||
unsigned int block_size, int64_t len)
|
||||
{
|
||||
struct count_chunks count_chunks = {0, 0, block_size};
|
||||
|
||||
for_each_data_block(count_data_block, count_file_block, count_fill_block, &count_chunks, block_size);
|
||||
for_each_data_block(b, count_data_block, count_file_block,
|
||||
count_fill_block, &count_chunks, block_size);
|
||||
|
||||
if (count_chunks.cur_ptr != len)
|
||||
count_chunks.chunks++;
|
||||
|
@ -136,14 +142,16 @@ static void ext4_write_data_file(void *priv, int64_t off, const char *file,
|
|||
int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
|
||||
bool crc)
|
||||
{
|
||||
int chunks = count_sparse_chunks(s->block_size, s->len);
|
||||
int chunks = count_sparse_chunks(s->backed_block_list, s->block_size,
|
||||
s->len);
|
||||
struct output_file *out = open_output_fd(fd, s->block_size, s->len,
|
||||
gz, sparse, chunks, crc);
|
||||
|
||||
if (!out)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_data_block(ext4_write_data_block, ext4_write_data_file, ext4_write_fill_block, out, s->block_size);
|
||||
for_each_data_block(s->backed_block_list, ext4_write_data_block,
|
||||
ext4_write_data_file, ext4_write_fill_block, out, s->block_size);
|
||||
|
||||
if (s->len)
|
||||
pad_output_file(out, s->len);
|
||||
|
|
|
@ -23,6 +23,7 @@ struct sparse_file {
|
|||
unsigned int block_size;
|
||||
int64_t len;
|
||||
|
||||
struct backed_block_list *backed_block_list;
|
||||
struct output_file *out;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue