/*************************************************************************** * Copyright (c) 2003-2010, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * * ***************************************************************************/ #include "bstd.h" #include "bkni.h" #include "bdbg.h" #include "bfdb.h" BDBG_MODULE(bfdb); #define BFDB_MAGIC 0xBFDBBABE #define BFDB_TUPLE_HEAD_SIZE 2 #define BFDB_LOG_SIZE 8 /* Number of reserved sectors used to move records before erasing empty space. More reseved sectors would allow to reclaim more space and faster operation. At least one sector must be reserved. */ #define BFDB_RESERVED_SECTORS 1 #define BFDB_PAGE_OVERLAP 0x10 /* Log flags definitions. These define bit positions since actual flags have value of 0 when set and 1 when not set due to the properties of flash */ #define BFDB_LF_LOG_START 1 struct bfdb_log { uint8_t flags; uint8_t dummy; uint32_t checksum; } __attribute__((packed)); enum bfdb_rec_state_t { brs_start, brs_id, brs_size, brs_data, brs_data2 }; static struct bfdb_state dbs; static void bfdb_tuple_put_head( void * buf, uint8_t id, uint8_t size ); static bfdb_err bfdb_db_load(bfdb_handle handle); static bfdb_err bfdb_db_load_log(bfdb_handle handle, uint32_t offset); static uint32_t bfdb_tuple_get_size(void * tuple); static uint32_t bfdb_tuple_get_id(void * tuple); static bfdb_err bfdb_log_walk(bfdb_handle handle, uint32_t start, uint8_t id); static bfdb_err bfdb_log_add(bfdb_handle handle, uint8_t * tuple, size_t tsize); static bfdb_err bfdb_log_pad_sector(bfdb_handle handle, size_t * padded_size); static bfdb_err bfdb_log_open_sector(bfdb_handle handle); static uint32_t bfdb_mod_sum(uint32_t sum, uint8_t * data, size_t dsize); bfdb_err bfdb_open(struct bfdb_settings * settings, bfdb_handle * handle) { bfdb_err dberr; BDBG_ASSERT(NULL != settings); BKNI_Memset(&dbs, 0, sizeof(struct bfdb_state)); /* check parameters for consistency */ if(0 != (settings->db_offset % settings->sector_size)){ dberr = BFDB_INVALID_PARAMETER; goto ExitFunc; } if(0 != (settings->db_size % settings->sector_size)){ dberr = BFDB_INVALID_PARAMETER; goto ExitFunc; } dbs.magic = BFDB_MAGIC; dbs.page_size = settings->page_size; dbs.sector_size = settings->sector_size; dbs.fl_start = settings->db_offset; dbs.fl_end = settings->db_offset + settings->db_size; dberr = bfds_open(&dbs.store); if(BFDS_OK != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } dbs.pb_size = dbs.page_size * 2; dbs.page_buffer = BKNI_Malloc(dbs.pb_size+BFDB_PAGE_OVERLAP); if(NULL == dbs.page_buffer){ dberr = BFDB_INTERNAL_ERROR; goto ExitFunc; } dbs.page_buffer2 = BKNI_Malloc(dbs.pb_size+BFDB_PAGE_OVERLAP); if(NULL == dbs.page_buffer2){ dberr = BFDB_INTERNAL_ERROR; BKNI_Free(dbs.page_buffer); goto ExitFunc; } dberr = bfdb_db_load(&dbs); *handle = &dbs; ExitFunc: return dberr; } bfdb_err bfdb_rewind(bfdb_handle handle, uint8_t id) { return bfdb_log_walk(handle, handle->db_head, id); } bfdb_err bfdb_next(bfdb_handle handle, uint8_t id) { bfdb_err dberr; uint8_t * tuple; size_t tu_size; tuple = handle->page_buffer; dberr = bfds_read(handle->store, handle->cursor, handle->page_buffer, BFDB_TUPLE_HEAD_SIZE); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } tu_size = BFDB_TUPLE_HEAD_SIZE + bfdb_tuple_get_size(tuple); /* look for required id starting with next tuple */ dberr = bfdb_log_walk(handle, handle->cursor + tu_size, id); ExitFunc: return dberr; } bfdb_err bfdb_get(bfdb_handle handle, uint8_t * data, size_t size) { bfdb_err dberr; size_t tu_size; dberr = bfds_read(handle->store, handle->cursor, handle->page_buffer, BFDB_TUPLE_HEAD_SIZE); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } tu_size = bfdb_tuple_get_size(handle->page_buffer); if(size < tu_size){ tu_size = size; } if (tu_size == 0) { dberr = BFDB_STORE_ERROR; goto ExitFunc; } dberr = bfds_read(handle->store, handle->cursor+BFDB_TUPLE_HEAD_SIZE, data, tu_size); if(0 != dberr){ dberr = BFDB_STORE_ERROR; } ExitFunc: return dberr; } /* Start writing from db_tail and write up to amount of data in the tuple. We may have to execute 2 page program operation is data spans across 2 pages. */ bfdb_err bfdb_add(bfdb_handle handle, uint8_t id, uint8_t * data, size_t size) { uint32_t o_size; uint32_t sector_mask; uint32_t empty_size; bfdb_err dberr; sector_mask = handle->sector_size - 1; /* sector size must be power of 2 */ /* check if database is full before adding any more data */ if(handle->db_head < handle->db_tail){ empty_size = handle->fl_end - handle->db_tail + handle->db_head - handle->fl_start; }else{ empty_size = handle->db_head - handle->db_tail; } if(empty_size <= BFDB_RESERVED_SECTORS * handle->sector_size){ dberr = BFDB_LOG_FULL; goto ExitFunc; } /* check if new write will cros sector boundary including extra log tuple */ o_size = (handle->db_tail & sector_mask) + BFDB_TUPLE_HEAD_SIZE + size + BFDB_LOG_SIZE; if(0 < (o_size & (~sector_mask))){ BDBG_ASSERT((BFDB_DATA_MAX+BFDB_TUPLE_HEAD_SIZE) <= o_size); dberr = bfdb_log_pad_sector(handle, &o_size); if(0 != dberr){ goto ExitFunc; } /* update empty space size computed earlier and check if log is full */ empty_size -= o_size; if(empty_size <= BFDB_RESERVED_SECTORS * handle->sector_size){ dberr = BFDB_LOG_FULL; goto ExitFunc; } } if(0 == (handle->db_tail & sector_mask)){ /* if we are on the sector boundary write log tuple */ dberr = bfdb_log_open_sector(handle); if(0 != dberr){ goto ExitFunc; } } /* form tuple from the data */ bfdb_tuple_put_head(handle->page_buffer, id, size); BKNI_Memcpy(&(handle->page_buffer[BFDB_TUPLE_HEAD_SIZE]), data, size); handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, data, size); dberr = bfdb_log_add(handle, handle->page_buffer, (BFDB_TUPLE_HEAD_SIZE + size)); ExitFunc: return dberr; } bfdb_err bfdb_delete(bfdb_handle handle) { bfdb_err dberr; uint32_t small_buffer; small_buffer = BFDB_TUPLE_ERASED; dberr = bfds_page_program(handle->store, handle->cursor, &small_buffer, 1); if(0 != dberr){ dberr = BFDB_STORE_ERROR; } return dberr; } /** Starting from the beginning of the log find all non erased and non log tuples. Move them one by one to the end of the log. After sector is free, mark next sector as beginning of the log and erase the sector. */ bfdb_err bfdb_compact(bfdb_handle handle) { bfdb_err dberr; uint8_t * pb_walker; size_t tu_size; uint8_t tu_id; uint32_t page_mask; uint32_t page_addr; uint32_t sector_mask; uint32_t o_size; uint32_t moved_size, erased_size; page_mask = handle->pb_size - 1; /* pb_size must be pow of 2 */ sector_mask = handle->sector_size - 1; /* sector size must be power of 2 */ page_addr = handle->db_head & ~page_mask; pb_walker = handle->page_buffer2 + (handle->db_head & page_mask); if(page_addr == (handle->db_tail & ~sector_mask)){ /* head is in the same sector as tail No need to compact */ dberr = BFDB_ALREADY_COMPACT; goto ExitFunc; } moved_size = erased_size = 0; do { /* fill page buffer */ dberr = bfds_read(handle->store, page_addr, handle->page_buffer2, handle->pb_size); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } tu_id = BFDB_TUPLE_ERASED; while(BFDB_TUPLE_BLANK != tu_id){ tu_id = bfdb_tuple_get_id(pb_walker); tu_size = bfdb_tuple_get_size(pb_walker) + BFDB_TUPLE_HEAD_SIZE; switch(tu_id){ case BFDB_TUPLE_ERASED: case BFDB_TUPLE_LOG: /* skip this tuple */ erased_size += tu_size; break; case BFDB_TUPLE_BLANK: /* break out of the loop */ continue; default: /* check for sector boundary crossing */ o_size = (handle->db_tail & sector_mask) + tu_size + BFDB_LOG_SIZE; if(0 < (o_size & (~sector_mask))){ BDBG_ASSERT((BFDB_DATA_MAX+BFDB_TUPLE_HEAD_SIZE) <= o_size); dberr = bfdb_log_pad_sector(handle, &o_size); if(0 != dberr){ goto ExitFunc; } } /* starting new sector */ if(0 == (handle->db_tail & sector_mask)){ dberr = bfdb_log_open_sector(handle); if(0 != dberr){ goto ExitFunc; } } /* copy this tuple to the end of the log.*/ if((pb_walker + tu_size) <= (handle->page_buffer2 + handle->pb_size)) { dberr = bfdb_log_add(handle, pb_walker, tu_size); if(BFDB_OK != dberr){ goto ExitFunc; } handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, (pb_walker + BFDB_TUPLE_HEAD_SIZE), (tu_size - BFDB_TUPLE_HEAD_SIZE)); }else{ /* entire tuple is not in memory, we need to write out part in memory and then page in and write out remaining part */ o_size = (handle->page_buffer2 + handle->pb_size) - pb_walker; /* page in next page if needed */ if(o_size < BFDB_TUPLE_HEAD_SIZE){ dberr = bfds_read(handle->store, (page_addr+handle->pb_size), (handle->page_buffer2 + handle->pb_size), BFDB_PAGE_OVERLAP); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } o_size = BFDB_TUPLE_HEAD_SIZE; } dberr = bfdb_log_add(handle, pb_walker, o_size); if(BFDB_OK != dberr){ goto ExitFunc; } /* tuple head is always in the first section so skip it for checksum */ handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, (pb_walker + BFDB_TUPLE_HEAD_SIZE), (o_size - BFDB_TUPLE_HEAD_SIZE)); pb_walker += o_size - handle->pb_size; o_size = tu_size - o_size; /* page in the next page */ page_addr += handle->pb_size; /* fill page buffer */ dberr = bfds_read(handle->store, page_addr, handle->page_buffer2, handle->pb_size); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } dberr = bfdb_log_add(handle, pb_walker, o_size); if(BFDB_OK != dberr){ goto ExitFunc; } /* checksum remaining portion */ handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, pb_walker, o_size); /* adjust walker so it will be pointed correctly later */ pb_walker = pb_walker + o_size - tu_size; } moved_size += tu_size; break; } pb_walker += tu_size; if(pb_walker >= (handle->page_buffer2 + handle->pb_size)){ /* read in next page buffer */ break; } /* make sure we are away from the end of page_buffer, if not read a little more data so tuple head is in memory */ if((pb_walker - handle->page_buffer2) > (handle->pb_size - 3)){ dberr = bfds_read(handle->store, (page_addr+handle->pb_size), (handle->page_buffer2 + handle->pb_size), BFDB_PAGE_OVERLAP); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } } } /* prepare to refill next page */ pb_walker = pb_walker - handle->pb_size; page_addr += handle->pb_size; }while(0 != (page_addr & sector_mask)); if(page_addr == handle->fl_end){ page_addr = handle->fl_start; /* wrap */ } BDBG_ERR(("mov %u era %u pa %08x", moved_size, erased_size, page_addr)); /* write log start flag and erase previous sector */ dberr = bfds_read(handle->store, page_addr, handle->page_buffer2, BFDB_LOG_SIZE); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } /* make sure this is a log or blank tuple */ tu_id = bfdb_tuple_get_id(handle->page_buffer2); if((BFDB_TUPLE_LOG == tu_id) || (BFDB_TUPLE_BLANK == tu_id)){ if(BFDB_TUPLE_BLANK == tu_id){ /* the next sector is blank, start new log */ dberr = bfdb_log_open_sector(handle); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } handle->page_buffer2[2] = 0xff; } handle->page_buffer2[2] &= ~(BFDB_LF_LOG_START); dberr = bfds_page_program(handle->store, (page_addr+BFDB_TUPLE_HEAD_SIZE), &handle->page_buffer2[2], 1); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } dberr = bfds_sector_erase(handle->store, handle->db_head); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } handle->db_head = page_addr; }else{ BKNI_Fail(); dberr = BFDB_LOG_ERROR; } if(BFDB_DATA_MAX > erased_size){ dberr = BFDB_ALREADY_COMPACT; } ExitFunc: return dberr; } /** Iterate over all database sectors erasing each one. Then reload database. */ bfdb_err bfdb_erase(bfdb_handle handle) { uint32_t sector_addr; bfdb_err dberr; sector_addr = handle->fl_start; for(sector_addr = handle->fl_start; sector_addr < handle->fl_end; sector_addr += handle->sector_size){ dberr = bfds_sector_erase(handle->store, sector_addr); if(0 != dberr){ goto ExitFunc; } } dberr = bfdb_db_load(handle); ExitFunc: return dberr; } /** Find log entry point and validate db structures. Log entry must be at sector boundary so we check start of every sector for start database marker. Every sector contains 0xff that means flash is empty. */ bfdb_err bfdb_db_load(bfdb_handle handle) { bfdb_err dberr; unsigned read_offset; read_offset = handle->fl_start; do{ dberr = bfds_read(handle->store, read_offset, handle->page_buffer, BFDB_LOG_SIZE); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } if(BFDB_TUPLE_LOG == handle->page_buffer[0]){ break; } read_offset += handle->sector_size; }while(read_offset < handle->fl_end); if(read_offset < handle->fl_end){ /* we found log data, now we need to find head and tail of the log */ dberr = bfdb_db_load_log(handle, read_offset); }else{ /* we did not find log entry anywhere so that means flash is blank */ /* read first page and create log tuple in it */ read_offset = handle->db_head = handle->db_tail = handle->fl_start; bfds_read(handle->store, read_offset, handle->page_buffer, handle->page_size); bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, sizeof(struct bfdb_log)); handle->page_buffer[2] = ~(BFDB_LF_LOG_START); dberr = bfdb_log_add(handle, handle->page_buffer, sizeof(struct bfdb_log) + BFDB_TUPLE_HEAD_SIZE); } ExitFunc: return dberr; } bfdb_err bfdb_db_load_log(bfdb_handle handle, uint32_t offset) { bfdb_err dberr; uint8_t * pb_walker; size_t tu_size; uint8_t tu_id; uint32_t checksum; uint8_t * tu_data; uint8_t *pb_end; enum bfdb_rec_state_t rs; uint32_t need_data; uint32_t rcount; /* first we need to find head. This is done by looking at log tuples and checking for a head flag. Since buffer is prescanned we only need to go from the offset to the end of the buffer */ do { dberr = bfds_read(handle->store, offset, handle->page_buffer, BFDB_LOG_SIZE); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } if(BFDB_TUPLE_LOG == handle->page_buffer[0]){ /* found log entry in the sector, check flags for log start */ if(0 == (handle->page_buffer[2] & BFDB_LF_LOG_START)){ break; } } offset += handle->sector_size; } while(offset < handle->fl_end); if(offset == handle->fl_end){ /* Not found log entry */ dberr = BFDB_LOG_ERROR; goto ExitFunc; } /* Found beginning of the log. Walk tuples to find the end */ handle->db_head = offset; pb_walker = handle->page_buffer; pb_end = handle->page_buffer + handle->pb_size; checksum = 0; tu_data = NULL; tu_size = 0; tu_id = 0; rcount = 0; rs = brs_start; need_data = 0; /* do first buffer fill */ dberr = bfds_read(handle->store, offset, handle->page_buffer, handle->pb_size); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } while(1){ if(1 == need_data){ offset += handle->pb_size; if(offset == handle->fl_end){ /* wrap */ offset = handle->fl_start; } pb_walker = pb_walker - handle->pb_size; BDBG_ASSERT(offset < handle->fl_end); dberr = bfds_read(handle->store, offset, handle->page_buffer, handle->pb_size); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } need_data = 0; } switch(rs){ case brs_start: if(pb_walker < pb_end){ tu_id = bfdb_tuple_get_id(pb_walker); rs = brs_id; }else{ need_data = 1; continue; } case brs_id: if((pb_walker+1) < pb_end){ tu_size = bfdb_tuple_get_size(pb_walker); rs = brs_size; }else{ need_data = 1; continue; } case brs_size: if((pb_walker + BFDB_TUPLE_HEAD_SIZE) < pb_end){ tu_data = pb_walker + BFDB_TUPLE_HEAD_SIZE; rs = brs_data; }else{ need_data = 1; continue; } default: break; } if(BFDB_TUPLE_LOG == tu_id){ /* log entries never cross page boundaries so they are safe */ uint32_t log_sum; log_sum = ((struct bfdb_log*)tu_data)->checksum; if((log_sum != checksum) && (log_sum != 0xffffffff)){ dberr = BFDB_LOG_ERROR; goto ExitFunc; } checksum = 0; }else if(BFDB_TUPLE_BLANK == tu_id){ /* found end of log */ handle->db_tail = offset + (pb_walker - handle->page_buffer); handle->sector_sum32 = checksum; dberr = BFDB_OK; goto ExitFunc; }else{ /* regular tuple, can be all in this page, part in this page or all in the next page */ switch(rs){ case brs_data: if(((tu_data + tu_size) < pb_end)){ checksum = bfdb_mod_sum(checksum, tu_data, tu_size); rcount++; }else{ checksum = bfdb_mod_sum(checksum, tu_data, (pb_end - tu_data)); pb_walker += (pb_end - tu_data); tu_size = tu_size - (pb_end - tu_data); tu_data = handle->page_buffer; need_data = 1; rs = brs_data2; continue; } break; case brs_data2: /* second part of the tuple */ checksum = bfdb_mod_sum(checksum, tu_data, tu_size); rcount++; break; default: BKNI_Fail(); } } pb_walker += tu_size + BFDB_TUPLE_HEAD_SIZE; rs = brs_start; } ExitFunc: return dberr; } /* Tuple operations */ /* Create tuple head in given buffer */ void bfdb_tuple_put_head( void * buf, uint8_t id, uint8_t size ) { ((uint8_t *)buf)[0] = id; ((uint8_t *)buf)[1] = size; } /* get tuple size */ uint32_t bfdb_tuple_get_size(void * tuple) { return (uint32_t)(((uint8_t *)tuple)[1]); } /* get tuple id */ uint32_t bfdb_tuple_get_id(void * tuple) { return (uint32_t)(((uint8_t *)tuple)[0]); } /* Iterate through database looking for a tuple with given "id" startting at position "start". Function will return BFDB_OK if such tuple found or error code if no tuple with given id was found. The actual tuple position will be placed in to handle->cursor; */ bfdb_err bfdb_log_walk(bfdb_handle handle, uint32_t start, uint8_t id) { bfdb_err dberr; uint8_t * pb_walker; size_t tu_size; uint8_t tu_id; uint32_t page_mask; uint32_t page_addr; uint8_t * pb_end; enum bfdb_rec_state_t rs; uint32_t need_data; uint32_t wrap_check; page_mask = handle->pb_size - 1; /* pb_size must be pow of 2 */ page_addr = (start & ~page_mask) - handle->pb_size; pb_end = handle->page_buffer + handle->pb_size; pb_walker = pb_end + (start & page_mask); need_data = 1; rs = brs_start; wrap_check = 0; tu_size = 0; tu_id = 0; while(start != handle->db_tail){ if(1 == need_data){ page_addr += handle->pb_size; if(page_addr == handle->fl_end){ /* wrap */ start = start - page_addr + handle->fl_start; if(start == handle->db_tail){ continue; /* terminate loop */ } page_addr = handle->fl_start; BDBG_ASSERT(start >= handle->fl_start); BDBG_ASSERT(start < handle->fl_end); wrap_check++; BDBG_ASSERT(wrap_check < 2); } pb_walker = pb_walker - handle->pb_size; BDBG_ASSERT(page_addr < handle->fl_end); dberr = bfds_read(handle->store, page_addr, handle->page_buffer, handle->pb_size); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } need_data = 0; } switch(rs){ case brs_start: if(pb_walker < pb_end){ tu_id = bfdb_tuple_get_id(pb_walker); rs = brs_id; }else{ need_data = 1; continue; } case brs_id: if((pb_walker+1) < pb_end){ tu_size = bfdb_tuple_get_size(pb_walker); rs = brs_size; }else{ need_data = 1; continue; } case brs_size: default: break; } BDBG_ASSERT(id != BFDB_TUPLE_BLANK); /* we got id and size, now compare and advance */ if(id == tu_id){ /* found desired tuple */ handle->cursor = page_addr + (pb_walker - handle->page_buffer); dberr = BFDB_OK; goto ExitFunc; }else{ pb_walker += tu_size + BFDB_TUPLE_HEAD_SIZE; start += tu_size + BFDB_TUPLE_HEAD_SIZE; rs = brs_start; } } dberr = BFDB_RECORD_NOT_FOUND; ExitFunc: return dberr; } /** Add data at the end of the log. bfdb_log_add will add data to the end of the log. It operates within sector boundaries but across page boundaries. Calling code must make sure that tuple will not cross sector boundaries. Call will advance database tail by the amount of added data. */ bfdb_err bfdb_log_add(bfdb_handle handle, uint8_t * data, size_t dsize) { bfdb_err dberr; uint32_t o_size1; uint32_t o_size2; uint32_t page_mask; /* locate pages to load in the buffer */ page_mask = handle->page_size - 1; /* page size must be power of 2 */ /* calculate transfer sizes */ o_size1 = (handle->db_tail & page_mask) + dsize; if(0 < (o_size1 & (~page_mask))){ /* we cross page boundary */ o_size1 = handle->page_size - (handle->db_tail & page_mask); o_size2 = dsize - o_size1; }else{ o_size1 = dsize; o_size2 = 0; } do { uint32_t sector_mask; sector_mask = handle->sector_size - 1; if(0 == (handle->db_tail & sector_mask)){ if(BFDB_TUPLE_LOG != data[0]) BKNI_Fail(); } } while(0); dberr = bfds_page_program(handle->store, handle->db_tail, data, o_size1); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } handle->db_tail += o_size1; if(0 != o_size2){ BDBG_ASSERT(0 == (handle->db_tail & page_mask)); dberr = bfds_page_program(handle->store, handle->db_tail, data+o_size1, o_size2); if(0 != dberr){ dberr = BFDB_STORE_ERROR; goto ExitFunc; } handle->db_tail += o_size2; } dberr = BFDB_OK; ExitFunc: return dberr; } /** Pad log with log tuple to the sector boundary. */ bfdb_err bfdb_log_pad_sector(bfdb_handle handle, size_t * padded_size) { uint32_t o_size; uint32_t o_size1; uint32_t sector_mask; bfdb_err dberr; struct bfdb_log * plog; sector_mask = handle->sector_size - 1; /* sector size must be power of 2 */ o_size = handle->sector_size - (handle->db_tail & sector_mask); BDBG_ASSERT(o_size >= BFDB_LOG_SIZE); o_size1 = 0; if(o_size >= (BFDB_TUPLE_HEAD_SIZE + BFDB_DATA_MAX)){ /* we need to pad with two tuples */ o_size1 = o_size / 2; BKNI_Memset(handle->page_buffer, 0xff, o_size1); bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, (o_size1 - BFDB_TUPLE_HEAD_SIZE)); dberr = bfdb_log_add(handle, handle->page_buffer, o_size1); if(0 != dberr){ goto ExitFunc; } } o_size = o_size - o_size1; BKNI_Memset(handle->page_buffer, 0xff, o_size); bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, (o_size - BFDB_TUPLE_HEAD_SIZE)); plog = (struct bfdb_log*)&handle->page_buffer[2]; plog->checksum = handle->sector_sum32; dberr = bfdb_log_add(handle, handle->page_buffer, o_size); if(0 != dberr){ goto ExitFunc; } if(handle->fl_end <= handle->db_tail){ BDBG_ASSERT(handle->fl_end == handle->db_tail); handle->db_tail = handle->fl_start; } BDBG_ASSERT(0 == (handle->db_tail & sector_mask)); *padded_size = o_size + o_size1; ExitFunc: return dberr; } /** Create log entry in the new sector. Wrap in the log if required. */ bfdb_err bfdb_log_open_sector(bfdb_handle handle) { bfdb_err dberr; /* check if we must wrap */ if(handle->fl_end <= handle->db_tail){ BDBG_ASSERT(handle->fl_end == handle->db_tail); handle->db_tail = handle->fl_start; } BKNI_Memset(handle->page_buffer, 0xff, 8); bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, sizeof(struct bfdb_log)); dberr = bfdb_log_add(handle, handle->page_buffer, (sizeof(struct bfdb_log) + BFDB_TUPLE_HEAD_SIZE)); handle->sector_sum32 = 0; return dberr; } uint32_t bfdb_mod_sum(uint32_t sum, uint8_t * data, size_t dsize) { size_t i; if(dsize > 0xff){ BKNI_Fail(); } for(i = 0 ; i < dsize; i++){ sum += data[i]; } return sum; } /* Please do not remove! */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: t */ /* End: */