BeRTOS
kblock.c
Go to the documentation of this file.
00001 
00039 #include "kblock.h"
00040 
00041 #define LOG_LEVEL   LOG_LVL_ERR
00042 #define LOG_FORMAT  LOG_FMT_VERBOSE
00043 
00044 #include <cfg/log.h>
00045 #include <string.h>
00046 
00047 INLINE size_t kblock_readDirect(struct KBlock *b, block_idx_t index, void *buf, size_t offset, size_t size)
00048 {
00049     KB_ASSERT_METHOD(b, readDirect);
00050     ASSERT(index < b->blk_cnt);
00051     return b->priv.vt->readDirect(b, b->priv.blk_start + index, buf, offset, size);
00052 }
00053 
00054 INLINE size_t kblock_writeDirect(struct KBlock *b, block_idx_t index, const void *buf, size_t offset, size_t size)
00055 {
00056     KB_ASSERT_METHOD(b, writeDirect);
00057     ASSERT(index < b->blk_cnt);
00058     return b->priv.vt->writeDirect(b, b->priv.blk_start + index, buf, offset, size);
00059 }
00060 
00061 INLINE size_t kblock_readBuf(struct KBlock *b, void *buf, size_t offset, size_t size)
00062 {
00063     KB_ASSERT_METHOD(b, readBuf);
00064     ASSERT(offset + size <= b->blk_size);
00065 
00066     return b->priv.vt->readBuf(b, buf, offset, size);
00067 }
00068 
00069 INLINE size_t kblock_writeBuf(struct KBlock *b, const void *buf, size_t offset, size_t size)
00070 {
00071     KB_ASSERT_METHOD(b, writeBuf);
00072     ASSERT(offset + size <= b->blk_size);
00073     return b->priv.vt->writeBuf(b, buf, offset, size);
00074 }
00075 
00076 INLINE int kblock_load(struct KBlock *b, block_idx_t index)
00077 {
00078     KB_ASSERT_METHOD(b, load);
00079     ASSERT(index < b->blk_cnt);
00080 
00081     LOG_INFO("index %ld\n", index);
00082     return b->priv.vt->load(b, b->priv.blk_start + index);
00083 }
00084 
00085 INLINE int kblock_store(struct KBlock *b, block_idx_t index)
00086 {
00087     KB_ASSERT_METHOD(b, store);
00088     ASSERT(index < b->blk_cnt);
00089 
00090     LOG_INFO("index %ld\n", index);
00091     return b->priv.vt->store(b, b->priv.blk_start + index);
00092 }
00093 
00094 INLINE void kblock_setDirty(struct KBlock *b, bool dirty)
00095 {
00096     if (dirty)
00097         b->priv.flags |= KB_CACHE_DIRTY;
00098     else
00099         b->priv.flags &= ~KB_CACHE_DIRTY;
00100 }
00101 
00102 
00103 size_t kblock_read(struct KBlock *b, block_idx_t idx, void *buf, size_t offset, size_t size)
00104 {
00105     ASSERT(b);
00106     ASSERT(buf);
00107     ASSERT(offset + size <= b->blk_size);
00108     LOG_INFO("blk_idx %ld, offset %u, size %u\n", idx, offset, size);
00109 
00110     if (kblock_buffered(b) && idx == b->priv.curr_blk)
00111         return kblock_readBuf(b, buf, offset, size);
00112     else
00113         return kblock_readDirect(b, idx, buf, offset, size);
00114 }
00115 
00116 
00117 int kblock_flush(struct KBlock *b)
00118 {
00119     ASSERT(b);
00120 
00121     if (!kblock_buffered(b))
00122         return 0;
00123 
00124     if (kblock_cacheDirty(b))
00125     {
00126         LOG_INFO("flushing block %ld\n", b->priv.curr_blk);
00127         if (kblock_store(b, b->priv.curr_blk) == 0)
00128             kblock_setDirty(b, false);
00129         else
00130             return EOF;
00131     }
00132     return 0;
00133 }
00134 
00135 
00136 static bool kblock_loadPage(struct KBlock *b, block_idx_t idx)
00137 {
00138     ASSERT(b);
00139 
00140     if (idx != b->priv.curr_blk)
00141     {
00142         LOG_INFO("loading block %ld\n", idx);
00143         if (kblock_flush(b) != 0 || kblock_load(b, idx) != 0)
00144                 return false;
00145 
00146         b->priv.curr_blk = idx;
00147     }
00148     return true;
00149 }
00150 
00151 
00152 int kblock_trim(struct KBlock *b, block_idx_t start, block_idx_t count)
00153 {
00154     ASSERT(start + count <= b->blk_cnt);
00155 
00156     if (kblock_buffered(b))
00157     {
00158         if (!kblock_loadPage(b, start))
00159             return EOF;
00160     }
00161 
00162     b->priv.blk_start += start;
00163     b->priv.curr_blk = 0; // adjust logical address
00164     b->blk_cnt = count;
00165     return 0;
00166 }
00167 
00168 
00169 size_t kblock_write(struct KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size)
00170 {
00171     ASSERT(b);
00172     ASSERT(buf);
00173     ASSERT(idx < b->blk_cnt);
00174     ASSERT(offset + size <= b->blk_size);
00175 
00176     LOG_INFO("blk_idx %ld, offset %u, size %u\n", idx, offset, size);
00177 
00178     if (kblock_buffered(b))
00179     {
00180         if (!kblock_loadPage(b, idx))
00181             return 0;
00182 
00183         kblock_setDirty(b, true);
00184         return kblock_writeBuf(b, buf, offset, size);
00185     }
00186     else
00187     {
00188         #ifdef _DEBUG
00189         if (offset != 0 || size != b->blk_size)
00190             ASSERT(kblock_partialWrite(b));
00191         #endif
00192         return kblock_writeDirect(b, idx, buf, offset, size);
00193     }
00194 }
00195 
00196 int kblock_copy(struct KBlock *b, block_idx_t src, block_idx_t dest)
00197 {
00198     ASSERT(b);
00199     ASSERT(src < b->blk_cnt);
00200     ASSERT(dest < b->blk_cnt);
00201 
00202     if (kblock_buffered(b))
00203     {
00204         if (!kblock_loadPage(b, src))
00205             return EOF;
00206 
00207         b->priv.curr_blk = dest;
00208         kblock_setDirty(b, true);
00209         return 0;
00210     }
00211     else if (kblock_partialWrite(b))
00212     {
00213         uint8_t buf[16];
00214         size_t blk_size = b->blk_size;
00215         size_t offset = 0;
00216 
00217         while (blk_size)
00218         {
00219             size_t size = MIN(sizeof(buf), blk_size);
00220             if (kblock_readDirect(b, src, buf, offset, size) != size)
00221                 return EOF;
00222             if (kblock_writeDirect(b, dest, buf, offset, size) != size)
00223                 return EOF;
00224 
00225             blk_size -= size;
00226             offset += size;
00227         }
00228         return 0;
00229     }
00230     else
00231     {
00232         ASSERT(0);
00233         return EOF;
00234     }
00235 }
00236 
00237 int kblock_swLoad(struct KBlock *b, block_idx_t index)
00238 {
00239     /*
00240      * Since this is a low level API, the index here is a fisical index.
00241      * If we call another low level API, logical to fisical translation
00242      * would be applied twice.
00243      * In order to avoid this we subtract the start block index.
00244      */
00245     ASSERT(index >= b->priv.blk_start);
00246     return (kblock_readDirect(b, index - b->priv.blk_start, b->priv.buf, 0, b->blk_size) == b->blk_size) ? 0 : EOF;
00247 }
00248 
00249 int kblock_swStore(struct KBlock *b, block_idx_t index)
00250 {
00251     /*
00252      * Since this is a low level API, the index here is a fisical index.
00253      * If we call another low level API, logical to fisical translation
00254      * would be applied twice.
00255      * In order to avoid this we subtract the start block index.
00256      */
00257     ASSERT(index >= b->priv.blk_start);
00258     return (kblock_writeDirect(b, index - b->priv.blk_start, b->priv.buf, 0, b->blk_size) == b->blk_size) ? 0 : EOF;
00259 }
00260 
00261 size_t kblock_swReadBuf(struct KBlock *b, void *buf, size_t offset, size_t size)
00262 {
00263     ASSERT(buf);
00264     ASSERT(offset + size <= b->blk_size);
00265 
00266     memcpy(buf, (uint8_t *)b->priv.buf + offset, size);
00267     return size;
00268 }
00269 
00270 size_t kblock_swWriteBuf(struct KBlock *b, const void *buf, size_t offset, size_t size)
00271 {
00272     ASSERT(buf);
00273     ASSERT(offset + size <= b->blk_size);
00274     memcpy((uint8_t *)b->priv.buf + offset, buf, size);
00275     return size;
00276 }
00277 
00278 int kblock_swClose(UNUSED_ARG(struct KBlock, *b))
00279 {
00280     return 0;
00281 }