aboutsummaryrefslogtreecommitdiffstats
path: root/cache.c
blob: bf3dc899a9a2185f78d565534f754a859ee7d82f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "cache.h"
#include "disklab.h"

#include <stdio.h>
#include <fcntl.h>




/*
 * Each CachePtr contains:
 * - Block pointer
 * - LRU previous pointer
 * - LRU next pointer
 * - Block data buffer address
 * The first entry is the head node of the list
 */


static struct cache_struct cache_head, cache[MAX_CACHE_ENTRIES];
static __u8 cache_data[65536];
static int cache_block_size;
static int cache_entries;

/**
 * cache_init:
 *
 * Initialize the cache data structres.
 *
 */
void cache_init(int block_size)
{
        struct cache_struct *prev, *cur;
        __u8 *data = cache_data;
        int i;

        cache_block_size = block_size;
        cache_entries = sizeof cache_data / block_size;
        if (cache_entries > MAX_CACHE_ENTRIES)
                cache_entries = MAX_CACHE_ENTRIES;
        
        cache_head.prev = &cache[cache_entries-1];
        cache_head.prev->next = &cache_head;
        prev = &cache_head;
        
        for (i = 0; i < cache_entries; i++) {
                cur = &cache[i];
                cur->block = 0;
                cur->prev  = prev;
                prev->next = cur;
                cur->data  = data;
                data += block_size;
                prev = cur++;
        }
}




/**
 * get_cache_block:
 *
 * Check for a particular BLOCK in the block cache, 
 * and if it is already there, just do nothing and return;
 * otherwise load it and updata the relative cache
 * structre with data pointer.
 *
 * @param: block, the block number we want check.
 * @retrun: return the most recent cache structure pointer
 *
 */
struct cache_struct * get_cache_block(__u32 block)
{
        /* let's find it from the end, 'cause the endest is the freshest */
        struct cache_struct *cs = cache_head.prev;
        struct cache_struct *head,  *last;
        int i;

        if ( !block ) {
                printf("ERROR: we got a ZERO block number that's not we want!\n");
                return NULL;
        }

        /* it's aleardy the freshest, so nothing we need do , just return it */
        if ( cs->block == block ) 
                return cs;

        for ( i = 0; i < cache_entries; i ++ ) {
                if ( cs->block == block )
                        break;
                else
                        cs = cs->prev;
        }

        if ( i == cache_entries ) {
                /* missed, so we need to load it */

                /* store it at the head of real cache */
                cs = cache_head.next;
                
                cs->block = block;
                getoneblk(cs->data, block, cache_block_size);
        }
 
        /* remove cs from current position in list */
        cs->prev->next = cs->next;
        cs->next->prev = cs->prev;
        
        
        /* add to just before head node */
        last = cache_head.prev;
        head = &cache_head;

        last->next = cs;
        cs->prev = last;
        head->prev = cs;
        cs->next = head;

        return cs;
}




/**
 * Just print the sector, and according the LRU algorithm, 
 * Left most value is the most least secotr, and Right most 
 * value is the most Recent sector. I see it's a Left Right Used
 * (LRU) algorithm; Just kidding:)
 */
void print_cache(void)
{
        int i = 0;
        struct cache_struct *cs = &cache_head;
        for (; i < cache_entries; i++) {
                cs = cs->next;
                printf("%d ", cs->block);
        }

        printf("\n");
}