www.pudn.com > efs.rar > fs_journal.c
/**********************************************************************
* fs_journal.c
*
* File system memory journal.
* Copyright (C) 2002, 2003, 2004, 2005, 2006 Qualcomm, Inc.
*/
/*===========================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header: //depot/asic/MSMSHARED/services/efs/MSM_EFS.01.02/fs_journal.c#4 $ $DateTime: 2006/06/29 13:31:48 $ $Author: davidb $
when who what, where, why
-------- --- ------------------------------------------------------
2006-06-26 yg Memory reduction effort
2005-10-30 sh Lint cleanup.
2005-05-26 sd Compilation fixes for L4.
2004-10-15 dlb Update copyright header.
2003-06-17 jkl Clean up code.
2003-03-07 dlb Fixed iterator to not delete modified node.
2002-08-08 drh Created by dlb. Added history header
===========================================================================*/
#define SIMPLE_JOURNAL_DUMP
#include
#ifdef DEBUG_WALK_HISTORY
#error code not present
#endif
#undef LOG_JOURNAL_CHANGES
#ifdef LOG_JOURNAL_CHANGES
#define JOURNAL_LOG_FILENAME "journal.log"
#include
FILE *journal_log_file;
#endif
#include "fs_device.h"
#include "fs_sys_types.h"
#include "fs_err.h"
#include "fs_journal.h"
#ifdef FEATURE_IG_EFS_EXT_SERVER
#include "amssassert.h"
#else
#include "assert.h"
#endif
#ifdef FEATURE_EFS_EFS2_ON_NAND
/* Bit mask accessors for the colors. */
#define IS_RED(jr, index) \
(((jr)->color[(index)>>3] & (1u << ((index) & 7))) != 0)
#define IS_BLACK(jr, index) (!IS_RED (jr, index))
#define SET_RED(jr, index) \
((jr)->color[(index)>>3] |= (1u << ((index) & 7)))
#define SET_BLACK(jr, index) \
((jr)->color[(index)>>3] &= ~(1u << ((index) & 7)))
/* Comparison macros. */
#define J_EQUAL(jr, a, b) \
(((jr)->key[a] == (jr)->key[b]) && \
((jr)->key_type[a] == (jr)->key_type[b]))
#define J_LESS(jr, a, b) \
(((jr)->key_type[a] < (jr)->key_type[b]) || \
( ((jr)->key_type[a] == (jr)->key_type[b]) && \
((jr)->key[a] < (jr)->key[b])))
static unsigned tree_minimum (fs_journal_t jr, unsigned x);
static unsigned tree_successor (fs_journal_t jr, unsigned x);
static void delete_node (fs_journal_t jr, unsigned z);
#ifdef FS_UNIT_TEST
#error code not present
#endif
#ifdef FS_UNIT_TEST
#error code not present
#endif
void
fs_journal_init (fs_journal_t jr)
{
int i;
// printf ("Journal size: %d bytes\n", sizeof (struct fs_journal_data));
jr->used = 0;
jr->nil = 0;
jr->root = 0;
jr->free_list = 0;
SET_BLACK (jr, 0); /*lint !e572*/
/* Create the free list. */
for (i = 1; i < FS_JOURNAL_SIZE; i++) {
jr->left[i] = jr->free_list;
jr->free_list = i;
}
/* Clear the iterators. */
for (i = 0; i < FS_JOURNAL_MAX_ITERATORS; i++) {
jr->iterator_nexts[i] = 0;
jr->iterators[i] = 0;
}
#ifdef LOG_JOURNAL_CHANGES
journal_log_file = fopen (JOURNAL_LOG_FILENAME, "w");
#endif
}
static void fixup_insert (fs_journal_t jr, unsigned int x);
void
fs_journal_add (fs_journal_t jr,
uint32 key,
unsigned key_type,
uint32 value,
unsigned age)
{
int x, y, z;
y = FS_J_NIL;
x = jr->root;
#ifdef JOURNAL_LOG_FILENAME
fprintf (journal_log_file,
" fs_journal_add (jr, 0x%08x, 0x%02x, 0x%08x, 0x%02x);\n",
key, key_type, value, age);
fflush (journal_log_file);
#endif
#ifdef DEBUG_WALK_HISTORY
#error code not present
#endif
/* Make our new node. If we find it, we'll put this back on the free
* list. */
z = jr->free_list;
if (z == FS_J_NIL) {
FS_ERR_FATAL ("Journal full", 0, 0, 0);
}
jr->free_list = jr->left[jr->free_list];
jr->left[z] = FS_J_NIL;
jr->right[z] = FS_J_NIL;
jr->key[z] = key;
jr->key_type[z] = key_type;
jr->value[z] = value;
jr->age[z] = age;
/* Search for the place to put this. */
while (x != FS_J_NIL) {
y = x;
/* Special check if the node is already present. */
if (J_EQUAL (jr, z, x)) {
/* Just copy over the fields, free up the new one, and forget it. */
jr->value[x] = jr->value[z];
jr->age[x] = jr->age[z];
jr->left[z] = jr->free_list;
jr->free_list = z;
return;
}
if (J_LESS (jr, z, x))
x = jr->left[x];
else
x = jr->right[x];
}
jr->parent[z] = y;
if (y == FS_J_NIL) {
jr->root = z;
} else {
if (J_LESS (jr, z, y))
jr->left[y] = z;
else
jr->right[y] = z;
}
/* Basic insert is finished, now clean up the tree as necessary. */
fixup_insert (jr, z);
jr->used++;
#ifdef FS_UNIT_TEST
#error code not present
#endif
}
int
fs_journal_lookup (fs_journal_t jr,
uint32 key,
unsigned key_type,
uint32 *value,
unsigned *age)
{
int x = jr->root;
/* Store the key into the nil node. */
/* XXX: Don't store this, make new comparison macros. */
jr->key[FS_J_NIL] = key;
jr->key_type[FS_J_NIL] = key_type;
while (x != FS_J_NIL) {
if (J_EQUAL (jr, FS_J_NIL, x))
break;
if (J_LESS (jr, FS_J_NIL, x))
x = jr->left[x];
else
x = jr->right[x];
}
if (x == FS_J_NIL) {
return FALSE;
} else {
*value = jr->value[x];
*age = jr->age[x];
return TRUE;
}
}
void fs_journal_setup_age_walk (fs_journal_t jr,
unsigned age)
{
jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE] = tree_minimum (jr, jr->root);
jr->age_walk_age = age;
}
int fs_journal_age_advance (fs_journal_t jr,
int delete_previous)
{
int x;
if (delete_previous && jr->iterators[FS_JOURNAL_ITERATOR_AGE] != FS_J_NIL
&& (jr->age[jr->iterators[FS_JOURNAL_ITERATOR_AGE]])
== jr->age_walk_age)
{
/* If the other iterator will use us as the next node, we need to move
* their iterator on, otherwise their iterator will be pointing to
* gibberish. */
if (jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE] ==
jr->iterators[FS_JOURNAL_ITERATOR_AGE])
{
jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE] =
tree_successor (jr, jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE]);
}
delete_node (jr, jr->iterators[FS_JOURNAL_ITERATOR_AGE]);
jr->iterators[FS_JOURNAL_ITERATOR_AGE] = FS_J_NIL;
}
x = jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE];
while (x != FS_J_NIL) {
if (jr->age[x] == jr->age_walk_age
&& x != jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE])
{
jr->iterators[FS_JOURNAL_ITERATOR_AGE] = x;
jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE] = tree_successor (jr, x);
return 1;
} else {
x = tree_successor (jr, x);
}
}
jr->iterators[FS_JOURNAL_ITERATOR_AGE] = FS_J_NIL;
jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE] = FS_J_NIL;
return 0;
}
void fs_journal_age_info (fs_journal_t jr,
uint32 *key, unsigned *key_type,
uint32 *value, unsigned *age)
{
int x = jr->iterators[FS_JOURNAL_ITERATOR_AGE];
if (x == FS_J_NIL)
FS_ERR_FATAL ("Attempt to get iterator value of nil iterator", 0, 0, 0);
*key = jr->key[x];
*key_type = jr->key_type[x];
*value = jr->value[x];
*age = jr->age[x];
}
void
fs_journal_setup_key_range_walk (fs_journal_t jr,
unsigned key_type,
uint32 key_min, uint32 key_max)
{
int x;
jr->key_range_walk_key_type = key_type;
jr->key_range_walk_key_min = key_min;
jr->key_range_walk_key_max = key_max;
/* Search for the smallest node greater or equal to key_min. */
jr->key[FS_J_NIL] = key_min;
jr->key_type[FS_J_NIL] = key_type;
x = jr->root;
while (x != FS_J_NIL) {
if (J_EQUAL (jr, FS_J_NIL, x))
break;
if (J_LESS (jr, FS_J_NIL, x)) {
if (jr->left[x] == FS_J_NIL) {
break;
}
x = jr->left[x];
} else {
if (jr->right[x] == FS_J_NIL) {
/* This node is actually less than our key_min, so advance the key.
*/
x = tree_successor (jr, x);
break;
}
x = jr->right[x];
}
}
jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE] = x;
}
int
fs_journal_key_range_advance (fs_journal_t jr, int delete_previous)
{
int x;
if (delete_previous
&& jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE] != FS_J_NIL)
{
/* If the other iterator will use us as the next node, we need to move
* their iterator on, otherwise their iterator will be pointing to
* gibberish. */
if (jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE] ==
jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE])
{
jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE] =
tree_successor (jr, jr->iterator_nexts[FS_JOURNAL_ITERATOR_AGE]);
}
delete_node (jr, jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE]);
jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE] = FS_J_NIL;
}
x = jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE];
while (x != FS_J_NIL) {
if (jr->key_type[x] != jr->key_range_walk_key_type
|| jr->key[x] < jr->key_range_walk_key_min
|| jr->key[x] > jr->key_range_walk_key_max)
{
break;
} else {
jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE] = x;
jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE]
= tree_successor (jr, x);
if (x != jr->iterators[FS_JOURNAL_ITERATOR_AGE]) {
return 1;
}
x = jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE];
}
}
jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE] = FS_J_NIL;
jr->iterator_nexts[FS_JOURNAL_ITERATOR_KEY_RANGE] = FS_J_NIL;
return 0;
}
void
fs_journal_key_range_info (fs_journal_t jr,
uint32 *key, unsigned *key_type,
uint32 *value, unsigned *age)
{
int x = jr->iterators[FS_JOURNAL_ITERATOR_KEY_RANGE];
if (x == FS_J_NIL)
FS_ERR_FATAL ("Attempt to get iterator value of nil iterator", 0, 0, 0);
*key = jr->key[x];
*key_type = jr->key_type[x];
*value = jr->value[x];
*age = jr->age[x];
}
int
fs_journal_free_count (fs_journal_t jr)
{
return FS_JOURNAL_SIZE - jr->used - 1;
}
static void
left_rotate (fs_journal_t jr, int x)
{
int y;
y = jr->right[x];
jr->right[x] = jr->left[y];
if (jr->left[y] != FS_J_NIL)
jr->parent[jr->left[y]] = x;
jr->parent[y] = jr->parent[x];
if (jr->parent[x] == FS_J_NIL) {
jr->root = y;
} else {
if (x == jr->left[jr->parent[x]])
jr->left[jr->parent[x]] = y;
else
jr->right[jr->parent[x]] = y;
}
jr->left[y] = x;
jr->parent[x] = y;
}
static void
right_rotate (fs_journal_t jr, int x)
{
int y;
y = jr->left[x];
jr->left[x] = jr->right[y];
if (jr->right[y] != FS_J_NIL)
jr->parent[jr->right[y]] = x;
jr->parent[y] = jr->parent[x];
if (jr->parent[x] == FS_J_NIL) {
jr->root = y;
} else {
if (x == jr->right[jr->parent[x]])
jr->right[jr->parent[x]] = y;
else
jr->left[jr->parent[x]] = y;
}
jr->right[y] = x;
jr->parent[x] = y;
}
/* Re-balance the tree after inserting node x. */
static void
fixup_insert (fs_journal_t jr, unsigned x)
{
unsigned int y;
SET_RED (jr, x);
while (x != jr->root && IS_RED (jr, jr->parent[x])) {
if (jr->parent[x] == jr->left[jr->parent[jr->parent[x]]]) {
y = jr->right[jr->parent[jr->parent[x]]];
if (IS_RED (jr, y)) {
SET_BLACK (jr, jr->parent[x]);
SET_BLACK (jr, y);
SET_RED (jr, jr->parent[jr->parent[x]]);
x = jr->parent[jr->parent[x]];
} else {
if (x == jr->right[jr->parent[x]]) {
x = jr->parent[x];
left_rotate (jr, x);
}
SET_BLACK (jr, jr->parent[x]);
SET_RED (jr, jr->parent[jr->parent[x]]);
right_rotate (jr, jr->parent[jr->parent[x]]);
}
} else {
y = jr->left[jr->parent[jr->parent[x]]];
if (IS_RED (jr, y)) {
SET_BLACK (jr, jr->parent[x]);
SET_BLACK (jr, y);
SET_RED (jr, jr->parent[jr->parent[x]]);
x = jr->parent[jr->parent[x]];
} else {
if (x == jr->left[jr->parent[x]]) {
x = jr->parent[x];
right_rotate (jr, x);
}
SET_BLACK (jr, jr->parent[x]);
SET_RED (jr, jr->parent[jr->parent[x]]);
left_rotate (jr, jr->parent[jr->parent[x]]);
}
}
}
SET_BLACK (jr, jr->root);
}
static unsigned
tree_minimum (fs_journal_t jr, unsigned x)
{
while (jr->left[x] != FS_J_NIL)
x = jr->left[x];
return x;
}
static unsigned
tree_successor (fs_journal_t jr, unsigned x)
{
unsigned int y;
if (jr->right[x] != FS_J_NIL)
return tree_minimum (jr, jr->right[x]);
y = jr->parent[x];
while (y != FS_J_NIL && x == jr->right[y]) {
x = y;
y = jr->parent[y];
}
return y;
}
static void
delete_fixup (fs_journal_t jr, unsigned int x)
{
unsigned int w;
while (x != jr->root && IS_BLACK (jr, x)) {
if (x == jr->left[jr->parent[x]]) {
w = jr->right[jr->parent[x]];
if (IS_RED (jr, w)) {
SET_BLACK (jr, w);
SET_RED (jr, jr->parent[x]);
left_rotate (jr, jr->parent[x]);
w = jr->right[jr->parent[x]];
}
if (IS_BLACK (jr, jr->left[w]) && IS_BLACK (jr, jr->right[w])) {
SET_RED (jr, w);
x = jr->parent[x];
} else {
if (IS_BLACK (jr, jr->right[w])) {
SET_BLACK (jr, jr->left[w]);
SET_RED (jr, w);
right_rotate (jr, w);
w = jr->right[jr->parent[x]];
}
if (IS_RED (jr, jr->parent[x]))
SET_RED (jr, w);
else
SET_BLACK (jr, w);
SET_BLACK (jr, jr->parent[x]);
SET_BLACK (jr, jr->right[w]);
left_rotate (jr, jr->parent[x]);
x = jr->root;
}
} else {
w = jr->left[jr->parent[x]];
if (IS_RED (jr, w)) {
SET_BLACK (jr, w);
SET_RED (jr, jr->parent[x]);
right_rotate (jr, jr->parent[x]);
w = jr->left[jr->parent[x]];
}
if (IS_BLACK (jr, jr->left[w]) && IS_BLACK (jr, jr->right[w])) {
SET_RED (jr, w);
x = jr->parent[x];
} else {
if (IS_BLACK (jr, jr->left[w])) {
SET_BLACK (jr, jr->right[w]);
SET_RED (jr, w);
left_rotate (jr, w);
w = jr->left[jr->parent[x]];
}
if (IS_RED (jr, jr->parent[x]))
SET_RED (jr, w);
else
SET_BLACK (jr, w);
SET_BLACK (jr, jr->parent[x]);
SET_BLACK (jr, jr->left[w]);
right_rotate (jr, jr->parent[x]);
x = jr->root;
}
}
}
SET_BLACK (jr, x);
}
/* XXX, figure out which node is actually freed, and add it back to free
* list. */
static void
delete_node (fs_journal_t jr, unsigned z)
{
unsigned int y;
unsigned int x;
unsigned int i;
#ifdef JOURNAL_LOG_FILENAME
fprintf (journal_log_file,
" fs_journal_delete (jr, 0x%08x, 0x%02x);\n",
jr->key[z], jr->key_type[z]);
fflush (journal_log_file);
#endif
if (jr->left[z] == FS_J_NIL || jr->right[z] == FS_J_NIL)
y = z;
else
y = tree_successor (jr, z);
if (jr->left[y] != FS_J_NIL)
x = jr->left[y];
else
x = jr->right[y];
jr->parent[x] = jr->parent[y];
if (jr->parent[y] == FS_J_NIL) {
jr->root = x;
} else {
if (y == jr->left[jr->parent[y]])
jr->left[jr->parent[y]] = x;
else
jr->right[jr->parent[y]] = x;
}
if (y != z) {
/* Copy over any used fields. */
jr->key[z] = jr->key[y];
jr->key_type[z] = jr->key_type[y];
jr->value[z] = jr->value[y];
jr->age[z] = jr->age[y];
/* If any of the iterators were pointing to the node we moved, adjust
* them to point to the original node, since that is now the same node.
* At this point, y will never be NIL, so we don't have to special
* check for the iterator not being used. */
ASSERT (y != FS_J_NIL);
/* Disable! to be sure we can reproduce the bug. */
for (i = 0; i < FS_JOURNAL_MAX_ITERATORS; i++) {
if (jr->iterator_nexts[i] == y)
jr->iterator_nexts[i] = z;
if (jr->iterators[i] == y)
jr->iterators[i] = z;
}
}
if (IS_BLACK (jr, y)) {
delete_fixup (jr, x);
}
jr->parent[y] = FS_J_NIL;
jr->left[y] = FS_J_NIL;
jr->right[y] = FS_J_NIL;
/* Add the node back to the free list. */
jr->left[y] = jr->free_list;
jr->free_list = y;
jr->used--;
}
#ifdef FS_UNIT_TEST
#error code not present
#endif /* FS_UNIT_TEST */
#endif /* FEATURE_EFS_EFS2_ON_NAND */