增加文件系统
This commit is contained in:
256
Lib/dhara/journal.h
Normal file
256
Lib/dhara/journal.h
Normal file
@@ -0,0 +1,256 @@
|
||||
/* Dhara - NAND flash management layer
|
||||
* Copyright (C) 2013 Daniel Beer <dlbeer@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DHARA_JOURNAL_H_
|
||||
#define DHARA_JOURNAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nand.h"
|
||||
|
||||
/* Number of bytes used by the journal checkpoint header. */
|
||||
#define DHARA_HEADER_SIZE 16
|
||||
|
||||
/* Global metadata available for a higher layer. This metadata is
|
||||
* persistent once the journal reaches a checkpoint, and is restored on
|
||||
* startup.
|
||||
*/
|
||||
#define DHARA_COOKIE_SIZE 4
|
||||
|
||||
/* This is the size of the metadata slice which accompanies each written
|
||||
* page. This is independent of the underlying page/OOB size.
|
||||
*/
|
||||
#define DHARA_META_SIZE 132
|
||||
|
||||
/* When a block fails, or garbage is encountered, we try again on the
|
||||
* next block/checkpoint. We can do this up to the given number of
|
||||
* times.
|
||||
*/
|
||||
#define DHARA_MAX_RETRIES 8
|
||||
|
||||
/* This is a page number which can be used to represent "no such page".
|
||||
* It's guaranteed to never be a valid user page.
|
||||
*/
|
||||
#define DHARA_PAGE_NONE ((dhara_page_t)0xffffffff)
|
||||
|
||||
/* State flags */
|
||||
#define DHARA_JOURNAL_F_DIRTY 0x01
|
||||
#define DHARA_JOURNAL_F_BAD_META 0x02
|
||||
#define DHARA_JOURNAL_F_RECOVERY 0x04
|
||||
#define DHARA_JOURNAL_F_ENUM_DONE 0x08
|
||||
|
||||
/* The journal layer presents the NAND pages as a double-ended queue.
|
||||
* Pages, with associated metadata may be pushed onto the end of the
|
||||
* queue, and pages may be popped from the end.
|
||||
*
|
||||
* Block erase, metadata storage are handled automatically. Bad blocks
|
||||
* are handled by relocating data to the next available non-bad page in
|
||||
* the sequence.
|
||||
*
|
||||
* It's up to the user to ensure that the queue doesn't grow beyond the
|
||||
* capacity of the NAND chip, but helper functions are provided to
|
||||
* assist with this. If the head meets the tail, the journal will refuse
|
||||
* to enqueue more pages.
|
||||
*/
|
||||
struct dhara_journal {
|
||||
const struct dhara_nand *nand;
|
||||
uint8_t *page_buf;
|
||||
|
||||
/* In the journal, user data is grouped into checkpoints of
|
||||
* 2**log2_ppc contiguous aligned pages.
|
||||
*
|
||||
* The last page of each checkpoint contains the journal header
|
||||
* and the metadata for the other pages in the period (the user
|
||||
* pages).
|
||||
*/
|
||||
uint8_t log2_ppc;
|
||||
|
||||
/* Epoch counter. This is incremented whenever the journal head
|
||||
* passes the end of the chip and wraps around.
|
||||
*/
|
||||
uint8_t epoch;
|
||||
|
||||
/* General purpose flags field */
|
||||
uint8_t flags;
|
||||
|
||||
/* Bad-block counters. bb_last is our best estimate of the
|
||||
* number of bad blocks in the chip as a whole. bb_current is
|
||||
* the number of bad blocks in all blocks before the current
|
||||
* head.
|
||||
*/
|
||||
dhara_block_t bb_current;
|
||||
dhara_block_t bb_last;
|
||||
|
||||
/* Log head and tail. The tail pointer points to the last user
|
||||
* page in the log, and the head pointer points to the next free
|
||||
* raw page. The root points to the last written user page.
|
||||
*/
|
||||
dhara_page_t tail_sync;
|
||||
dhara_page_t tail;
|
||||
dhara_page_t head;
|
||||
|
||||
/* This points to the last written user page in the journal */
|
||||
dhara_page_t root;
|
||||
|
||||
/* Recovery mode: recover_root points to the last valid user
|
||||
* page in the block requiring recovery. recover_next points to
|
||||
* the next user page needing recovery.
|
||||
*
|
||||
* If we had buffered metadata before recovery started, it will
|
||||
* have been dumped to a free page, indicated by recover_meta.
|
||||
* If this block later goes bad, we will have to defer bad-block
|
||||
* marking until recovery is complete (F_BAD_META).
|
||||
*/
|
||||
dhara_page_t recover_next;
|
||||
dhara_page_t recover_root;
|
||||
dhara_page_t recover_meta;
|
||||
};
|
||||
|
||||
/* Initialize a journal. You must supply a pointer to a NAND chip
|
||||
* driver, and a single page buffer. This page buffer will be used
|
||||
* exclusively by the journal, but you are responsible for allocating
|
||||
* it, and freeing it (if necessary) at the end.
|
||||
*
|
||||
* No NAND operations are performed at this point.
|
||||
*/
|
||||
void dhara_journal_init(struct dhara_journal *j,
|
||||
const struct dhara_nand *n,
|
||||
uint8_t *page_buf);
|
||||
|
||||
/* Start up the journal -- search the NAND for the journal head, or
|
||||
* initialize a blank journal if one isn't found. Returns 0 on success
|
||||
* or -1 if a (fatal) error occurs.
|
||||
*
|
||||
* This operation is O(log N), where N is the number of pages in the
|
||||
* NAND chip. All other operations are O(1).
|
||||
*
|
||||
* If this operation fails, the journal will be reset to an empty state.
|
||||
*/
|
||||
int dhara_journal_resume(struct dhara_journal *j, dhara_error_t *err);
|
||||
|
||||
/* Obtain an upper bound on the number of user pages storable in the
|
||||
* journal.
|
||||
*/
|
||||
dhara_page_t dhara_journal_capacity(const struct dhara_journal *j);
|
||||
|
||||
/* Obtain an upper bound on the number of user pages consumed by the
|
||||
* journal.
|
||||
*/
|
||||
dhara_page_t dhara_journal_size(const struct dhara_journal *j);
|
||||
|
||||
/* Obtain a pointer to the cookie data */
|
||||
static inline uint8_t *dhara_journal_cookie(const struct dhara_journal *j)
|
||||
{
|
||||
return j->page_buf + DHARA_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/* Obtain the locations of the first and last pages in the journal.
|
||||
*/
|
||||
static inline dhara_page_t dhara_journal_root(const struct dhara_journal *j)
|
||||
{
|
||||
return j->root;
|
||||
}
|
||||
|
||||
/* Read metadata associated with a page. This assumes that the page
|
||||
* provided is a valid data page. The actual page data is read via the
|
||||
* normal NAND interface.
|
||||
*/
|
||||
int dhara_journal_read_meta(struct dhara_journal *j, dhara_page_t p,
|
||||
uint8_t *buf, dhara_error_t *err);
|
||||
|
||||
/* Advance the tail to the next non-bad block and return the page that's
|
||||
* ready to read. If no page is ready, return DHARA_PAGE_NONE.
|
||||
*/
|
||||
dhara_page_t dhara_journal_peek(struct dhara_journal *j);
|
||||
|
||||
/* Remove the last page from the journal. This doesn't take permanent
|
||||
* effect until the next checkpoint.
|
||||
*/
|
||||
void dhara_journal_dequeue(struct dhara_journal *j);
|
||||
|
||||
/* Remove all pages form the journal. This doesn't take permanent effect
|
||||
* until the next checkpoint.
|
||||
*/
|
||||
void dhara_journal_clear(struct dhara_journal *j);
|
||||
|
||||
/* Append a page to the journal. Both raw page data and metadata must be
|
||||
* specified. The push operation is not persistent until a checkpoint is
|
||||
* reached.
|
||||
*
|
||||
* This operation may fail with the error code E_RECOVER. If this
|
||||
* occurs, the upper layer must complete the assisted recovery procedure
|
||||
* and then try again.
|
||||
*
|
||||
* This operation may be used as part of a recovery. If further errors
|
||||
* occur during recovery, E_RECOVER is returned, and the procedure must
|
||||
* be restarted.
|
||||
*/
|
||||
int dhara_journal_enqueue(struct dhara_journal *j,
|
||||
const uint8_t *data, const uint8_t *meta,
|
||||
dhara_error_t *err);
|
||||
|
||||
/* Copy an existing page to the front of the journal. New metadata must
|
||||
* be specified. This operation is not persistent until a checkpoint is
|
||||
* reached.
|
||||
*
|
||||
* This operation may fail with the error code E_RECOVER. If this
|
||||
* occurs, the upper layer must complete the assisted recovery procedure
|
||||
* and then try again.
|
||||
*
|
||||
* This operation may be used as part of a recovery. If further errors
|
||||
* occur during recovery, E_RECOVER is returned, and the procedure must
|
||||
* be restarted.
|
||||
*/
|
||||
int dhara_journal_copy(struct dhara_journal *j,
|
||||
dhara_page_t p, const uint8_t *meta,
|
||||
dhara_error_t *err);
|
||||
|
||||
/* Mark the journal dirty. */
|
||||
static inline void dhara_journal_mark_dirty(struct dhara_journal *j)
|
||||
{
|
||||
j->flags |= DHARA_JOURNAL_F_DIRTY;
|
||||
}
|
||||
|
||||
/* Is the journal checkpointed? If true, then all pages enqueued are now
|
||||
* persistent.
|
||||
*/
|
||||
static inline int dhara_journal_is_clean(const struct dhara_journal *j)
|
||||
{
|
||||
return !(j->flags & DHARA_JOURNAL_F_DIRTY);
|
||||
}
|
||||
|
||||
/* If an operation returns E_RECOVER, you must begin the recovery
|
||||
* procedure. You must then:
|
||||
*
|
||||
* - call dhara_journal_next_recoverable() to obtain the next block
|
||||
* to be recovered (if any). If there are no blocks remaining to be
|
||||
* recovered, DHARA_JOURNAL_PAGE_NONE is returned.
|
||||
*
|
||||
* - proceed to the next checkpoint. Once the journal is clean,
|
||||
* recovery will finish automatically.
|
||||
*
|
||||
* If any operation during recovery fails due to a bad block, E_RECOVER
|
||||
* is returned again, and recovery restarts. Do not add new data to the
|
||||
* journal (rewrites of recovered data are fine) until recovery is
|
||||
* complete.
|
||||
*/
|
||||
static inline int dhara_journal_in_recovery(const struct dhara_journal *j)
|
||||
{
|
||||
return j->flags & DHARA_JOURNAL_F_RECOVERY;
|
||||
}
|
||||
|
||||
dhara_page_t dhara_journal_next_recoverable(struct dhara_journal *j);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user