xref: /plan9/sys/src/cmd/ext2srv/iobuf.c (revision ec46fab06dcae3e636b775c4eaa679036316e1d8)
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include "dat.h"
7 #include "fns.h"
8 
9 #define	NIOBUF		100
10 #define	HIOB		(NIOBUF/3)
11 
12 static Iobuf*	hiob[HIOB];		/* hash buckets */
13 static Iobuf	iobuf[NIOBUF];		/* buffer headers */
14 static Iobuf*	iohead;
15 static Iobuf*	iotail;
16 
17 Iobuf*
getbuf(Xfs * dev,long addr)18 getbuf(Xfs *dev, long addr)
19 {
20 	Iobuf *p, *h, **l, **f;
21 
22 	l = &hiob[addr%HIOB];
23 	for(p = *l; p; p = p->hash) {
24 		if(p->addr == addr && p->dev == dev) {
25 			p->busy++;
26 			return p;
27 		}
28 	}
29 	/* Find a non-busy buffer from the tail */
30 	for(p = iotail; p && (p->busy > 0); p = p->prev)
31 		;
32 	if(!p)
33 		panic("all buffers busy");
34 	if(p->dirty){
35 		xwrite(p);
36 		p->dirty = 0;
37 	}
38 
39 	if( xread(dev, p, addr) < 0)
40 		return 0;
41 	/* Delete from hash chain */
42 	f = &hiob[p->addr%HIOB];
43 	if( *f == p )
44 		*f = p->hash;
45 	else {
46 		for(h = *f; h ; h = h->hash)
47 			if( h->hash == p ){
48 				h->hash = p->hash;
49 				break;
50 			}
51 	}
52 	/* Fill and hash */
53 	p->hash = *l;
54 	*l = p;
55 	p->addr = addr;
56 	p->dev = dev;
57 	p->busy=1;
58 
59 	return p;
60 }
61 void
putbuf(Iobuf * p)62 putbuf(Iobuf *p)
63 {
64 	if(p->busy <= 0)
65 		panic("putbuf");
66 	p->busy--;
67 
68 	/* Link onto head for lru */
69 	if(p == iohead)
70 		return;
71 	if( p == iotail ){
72 		p->prev->next = 0;
73 		iotail = p->prev;
74 	}else{
75 		p->prev->next = p->next;
76 		p->next->prev = p->prev;
77 	}
78 
79 	p->prev = 0;
80 	p->next = iohead;
81 	iohead->prev = p;
82 	iohead = p;
83 }
84 void
dirtybuf(Iobuf * p)85 dirtybuf(Iobuf *p)
86 {
87 	if(p->busy <=0)
88 		panic("dirtybuf");
89 	p->dirty = 1;
90 }
91 void
syncbuf(void)92 syncbuf(void)
93 {
94 	Iobuf *p;
95 
96 	for(p=&iobuf[0] ; p<&iobuf[NIOBUF]; p++)
97 		if( p->dirty ){
98 			xwrite(p);
99 			p->dirty = 0;
100 		}
101 }
102 void
purgebuf(Xfs * dev)103 purgebuf(Xfs *dev)
104 {
105 	Iobuf *p;
106 
107 	for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++)
108 		if(p->dev == dev)
109 			p->busy = 0;
110 
111 	/* Blow hash chains */
112 	memset(hiob, 0, sizeof(hiob));
113 }
114 void
iobuf_init(void)115 iobuf_init(void)
116 {
117 	Iobuf *p;
118 
119 	iohead = iobuf;
120 	iotail = iobuf+NIOBUF-1;
121 
122 	for(p = iobuf; p <= iotail; p++) {
123 		p->next = p+1;
124 		p->prev = p-1;
125 
126 		p->iobuf = (char *)malloc(EXT2_MAX_BLOCK_SIZE);
127 		if(p->iobuf == 0)
128 			panic("iobuf_init");
129 	}
130 
131 	iohead->prev = 0;
132 	iotail->next = 0;
133 }
134 int
xread(Xfs * dev,Iobuf * p,long addr)135 xread(Xfs *dev, Iobuf *p, long addr)
136 {
137 	/*chat("xread %d,%d...", dev->dev, addr);*/
138 
139 	seek(dev->dev, (vlong)addr*dev->block_size, 0);
140 	if(read(dev->dev, p->iobuf, dev->block_size) != dev->block_size){
141 		chat("xread %d, block=%d failed ...", dev->dev, addr);
142 		errno = Eio;
143 		return -1;
144 	}
145 	/*chat("xread ok...");*/
146 	return 0;
147 }
148 void
xwrite(Iobuf * p)149 xwrite(Iobuf *p)
150 {
151 	Xfs *dev;
152 	long addr;
153 
154 	dev = p->dev;
155 	addr = p->addr;
156 	/*chat("xwrite %d,%d...", dev->dev, addr);*/
157 
158 	seek(dev->dev, (vlong)addr*dev->block_size, 0);
159 	if(write(dev->dev, p->iobuf, dev->block_size) != dev->block_size){
160 		chat("xwrite %d, block=%d failed ...", dev->dev, addr);
161 		errno = Eio;
162 		return;
163 	}
164 	/*chat("xwrite ok...");*/
165 }
166 void
dumpbuf(void)167 dumpbuf(void)
168 {
169 	Iobuf *p;
170 
171 	for(p = iotail; p ; p = p->prev)
172 		if( p->busy )
173 			mchat("\nHi ERROR buf(%x, %d, %d)\n", p, p->addr, p->busy);
174 }
175