Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include "cformat.h"
4
#include "lru.h"
5
#include "bcache.h"
6
 
7
int
8
bcinit(Bcache *bc, int f, int bsize)
9
{
10
	Bbuf *b;
11
 
12
	/*
13
	 *  allocate space for all buffers
14
	 *  point all buffers into outer space
15
	 */
16
	bc->dfirst = 0;
17
	bc->bsize = bsize;
18
	bc->f = f;
19
	lruinit(bc);
20
	for(b = bc->bb; b < &bc->bb[Nbcache]; b++){
21
		b->inuse = 0;
22
		b->next = 0;
23
		b->dirty = 0;
24
		if(b->data == 0)
25
			b->data = (char *)malloc(bc->bsize);
26
		if(b->data == 0)
27
			return -1;
28
		lruadd(bc, b);
29
	}
30
 
31
	return 0;
32
}
33
 
34
/*
35
 *  Find a buffer for block b.  If it's dirty, write it out.
36
 */
37
Bbuf *
38
bcfind(Bcache *bc, ulong bno)
39
{
40
	Bbuf *b;
41
 
42
	if(bno == Notabno)
43
		error("bcfind: Notabno");
44
	bno &= ~Indbno;
45
 
46
	/*
47
	 *  if we already have a buffer for this bno, use it
48
	 */
49
	for(b = bc->bb; b < &bc->bb[Nbcache]; b++)
50
		if(b->inuse && b->bno==bno)
51
			goto out;
52
 
53
	/*
54
	 *  get least recently used block
55
	 */
56
	b = (Bbuf*)bc->lnext;
57
out:
58
	/*
59
	 *  if dirty, write it out
60
	 */
61
	if(b->dirty)
62
		if(bcwrite(bc, b) < 0)
63
			warning("writing dirty page");
64
	lruref(bc, b);
65
	return b;
66
}
67
 
68
/*
69
 *  allocate a buffer block for a block.  it's guaranteed to be there till
70
 *  the next Nbcache bcread's.
71
 */
72
Bbuf *
73
bcalloc(Bcache *bc, ulong bno)
74
{
75
	Bbuf *b;
76
 
77
	b = bcfind(bc, bno);
78
	bno &= ~Indbno;
79
	b->bno = bno;
80
	b->inuse = 1;
81
	return b;
82
}
83
 
84
/*
85
 *  read a block into a buffer cache.  it's guaranteed to be there till
86
 *  the next Nbcache bcread's.
87
 */
88
Bbuf *
89
bcread(Bcache *bc, ulong bno)
90
{
91
	Bbuf *b;
92
 
93
	b = bcfind(bc, bno);
94
	bno &= ~Indbno;
95
	if(b->bno!=bno || !b->inuse)
96
		/*
97
		 *  read in the one we really want
98
		 */
99
		if(bread(bc, bno, b->data) < 0){
100
			b->inuse = 0;
101
			return 0;
102
		}
103
	b->bno = bno;
104
	b->inuse = 1;
105
	return b;
106
}
107
 
108
/*
109
 *  mark a page dirty, if it's already dirty force a write
110
 *
111
 *	N.B: ordering is important.
112
 */
113
void
114
bcmark(Bcache *bc, Bbuf *b)
115
{
116
	lruref(bc, b);
117
 
118
	if(b->dirty){
119
		bcwrite(bc, b);
120
		return;
121
	}
122
 
123
	b->dirty = 1;
124
	if(bc->dfirst)
125
		bc->dlast->next = b;
126
	else
127
		bc->dfirst = b;
128
	bc->dlast = b;
129
}
130
 
131
/*
132
 *  write out a page (and all preceding dirty ones)
133
 */
134
int
135
bcwrite(Bcache *bc, Bbuf *b)
136
{
137
	Bbuf *nb;
138
 
139
	/*
140
	 *  write out all preceding pages
141
	 */
142
	while(nb = bc->dfirst){
143
		if(bwrite(bc, nb->bno, nb->data) < 0)
144
			return -1;
145
		nb->dirty = 0;
146
		bc->dfirst = nb->next;
147
		nb->next = 0;
148
		if(nb == b)
149
			return 0;
150
	}
151
 
152
	/*
153
	 *  write out this page
154
	 */
155
	if(bwrite(bc, b->bno, b->data) < 0)
156
		return -1;
157
	b->dirty = 0;
158
	b->next = 0;
159
	return 0;
160
}
161
 
162
/*
163
 *  write out all dirty pages (in order)
164
 */
165
int
166
bcsync(Bcache *bc)
167
{
168
	if(bc->dfirst)
169
		return bcwrite(bc, bc->dlast);
170
	return 0;
171
}
172
 
173
/*
174
 *  read a block from disk
175
 */
176
int
177
bread(Bcache *bc, ulong bno, void *buf)
178
{
179
	uvlong x = (uvlong)bno * bc->bsize;
180
 
181
	if(pread(bc->f, buf, bc->bsize, x) != bc->bsize)
182
		return -1;
183
	return 0;
184
}
185
 
186
/*
187
 *  write a block to disk
188
 */
189
int
190
bwrite(Bcache *bc, ulong bno, void *buf)
191
{
192
	uvlong x = (uvlong)bno * bc->bsize;
193
 
194
	if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize)
195
		return -1;
196
	return 0;
197
}