1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 
5 int			bootstrap = 0;
6 int			syncwrites = 0;
7 int			queuewrites = 0;
8 int			writestodevnull = 0;
9 int			verifywrites = 0;
10 
11 static Packet		*readilump(Lump *u, IAddr *ia, u8int *score);
12 
13 /*
14  * Some of this logic is duplicated in hdisk.c
15  */
16 Packet*
readlump(u8int * score,int type,u32int size,int * cached)17 readlump(u8int *score, int type, u32int size, int *cached)
18 {
19 	Lump *u;
20 	Packet *p;
21 	IAddr ia;
22 	u32int n;
23 
24 	trace(TraceLump, "readlump enter");
25 /*
26 	qlock(&stats.lock);
27 	stats.lumpreads++;
28 	qunlock(&stats.lock);
29 */
30 	if(scorecmp(score, zeroscore) == 0)
31 		return packetalloc();
32 	u = lookuplump(score, type);
33 	if(u->data != nil){
34 		trace(TraceLump, "readlump lookuplump hit");
35 		if(cached)
36 			*cached = 1;
37 		n = packetsize(u->data);
38 		if(n > size){
39 			seterr(EOk, "read too small: asked for %d need at least %d", size, n);
40 			putlump(u);
41 
42 			return nil;
43 		}
44 		p = packetdup(u->data, 0, n);
45 		putlump(u);
46 		return p;
47 	}
48 
49 	if(cached)
50 		*cached = 0;
51 
52 	if(lookupscore(score, type, &ia) < 0){
53 		/* ZZZ place to check for someone trying to guess scores */
54 		seterr(EOk, "no block with score %V/%d exists", score, type);
55 
56 		putlump(u);
57 		return nil;
58 	}
59 	if(ia.size > size){
60 		seterr(EOk, "read too small 1: asked for %d need at least %d", size, ia.size);
61 
62 		putlump(u);
63 		return nil;
64 	}
65 
66 	trace(TraceLump, "readlump readilump");
67 	p = readilump(u, &ia, score);
68 	putlump(u);
69 
70 	trace(TraceLump, "readlump exit");
71 	return p;
72 }
73 
74 /*
75  * save away a lump, and return it's score.
76  * doesn't store duplicates, but checks that the data is really the same.
77  */
78 int
writelump(Packet * p,u8int * score,int type,u32int creator,uint ms)79 writelump(Packet *p, u8int *score, int type, u32int creator, uint ms)
80 {
81 	Lump *u;
82 	int ok;
83 
84 /*
85 	qlock(&stats.lock);
86 	stats.lumpwrites++;
87 	qunlock(&stats.lock);
88 */
89 
90 	packetsha1(p, score);
91 	if(packetsize(p) == 0 || writestodevnull==1){
92 		packetfree(p);
93 		return 0;
94 	}
95 
96 	u = lookuplump(score, type);
97 	if(u->data != nil){
98 		ok = 0;
99 		if(packetcmp(p, u->data) != 0){
100 			uchar nscore[VtScoreSize];
101 
102 			packetsha1(u->data, nscore);
103 			if(scorecmp(u->score, score) != 0)
104 				seterr(EStrange, "lookuplump returned bad score %V not %V", u->score, score);
105 			else if(scorecmp(u->score, nscore) != 0)
106 				seterr(EStrange, "lookuplump returned bad data %V not %V", nscore, u->score);
107 			else
108 				seterr(EStrange, "score collision %V", score);
109 			ok = -1;
110 		}
111 		packetfree(p);
112 		putlump(u);
113 		return ok;
114 	}
115 
116 	if(writestodevnull==2){
117 		packetfree(p);
118 		return 0;
119 	}
120 
121 	if(queuewrites)
122 		return queuewrite(u, p, creator, ms);
123 
124 	ok = writeqlump(u, p, creator, ms);
125 
126 	putlump(u);
127 	return ok;
128 }
129 
130 int
writeqlump(Lump * u,Packet * p,int creator,uint ms)131 writeqlump(Lump *u, Packet *p, int creator, uint ms)
132 {
133 	ZBlock *flat;
134 	Packet *old;
135 	IAddr ia;
136 	int ok;
137 
138 	if(lookupscore(u->score, u->type, &ia) == 0){
139 		if(verifywrites == 0){
140 			/* assume the data is here! */
141 			packetfree(p);
142 			ms = msec() - ms;
143 			addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
144 			return 0;
145 		}
146 
147 		/*
148 		 * if the read fails,
149 		 * assume it was corrupted data and store the block again
150 		 */
151 		old = readilump(u, &ia, u->score);
152 		if(old != nil){
153 			ok = 0;
154 			if(packetcmp(p, old) != 0){
155 				uchar nscore[VtScoreSize];
156 
157 				packetsha1(old, nscore);
158 				if(scorecmp(u->score, nscore) != 0)
159 					seterr(EStrange, "readilump returned bad data %V not %V", nscore, u->score);
160 				else
161 					seterr(EStrange, "score collision %V", u->score);
162 				ok = -1;
163 			}
164 			packetfree(p);
165 			packetfree(old);
166 
167 			ms = msec() - ms;
168 			addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
169 			return ok;
170 		}
171 		logerr(EAdmin, "writelump: read %V failed, rewriting: %r\n", u->score);
172 	}
173 
174 	flat = packet2zblock(p, packetsize(p));
175 	ok = storeclump(mainindex, flat, u->score, u->type, creator, &ia);
176 	freezblock(flat);
177 	if(ok == 0)
178 		insertlump(u, p);
179 	else
180 		packetfree(p);
181 
182 	if(syncwrites){
183 		flushdcache();
184 		flushicache();
185 		flushdcache();
186 	}
187 
188 	ms = msec() - ms;
189 	addstat2(StatRpcWriteNew, 1, StatRpcWriteNewTime, ms);
190 	return ok;
191 }
192 
193 static Packet*
readilump(Lump * u,IAddr * ia,u8int * score)194 readilump(Lump *u, IAddr *ia, u8int *score)
195 {
196 	Arena *arena;
197 	ZBlock *zb;
198 	Packet *p, *pp;
199 	Clump cl;
200 	u64int aa;
201 	u8int sc[VtScoreSize];
202 
203 	trace(TraceLump, "readilump enter");
204 	arena = amapitoa(mainindex, ia->addr, &aa);
205 	if(arena == nil){
206 		trace(TraceLump, "readilump amapitoa failed");
207 		return nil;
208 	}
209 
210 	trace(TraceLump, "readilump loadclump");
211 	zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid);
212 	if(zb == nil){
213 		trace(TraceLump, "readilump loadclump failed");
214 		return nil;
215 	}
216 
217 	if(ia->size != cl.info.uncsize){
218 		seterr(EInconsist, "index and clump size mismatch");
219 		freezblock(zb);
220 		return nil;
221 	}
222 	if(ia->type != cl.info.type){
223 		seterr(EInconsist, "index and clump type mismatch");
224 		freezblock(zb);
225 		return nil;
226 	}
227 	if(scorecmp(score, sc) != 0){
228 		seterr(ECrash, "score mismatch");
229 		freezblock(zb);
230 		return nil;
231 	}
232 
233 	trace(TraceLump, "readilump success");
234 	p = zblock2packet(zb, cl.info.uncsize);
235 	freezblock(zb);
236 	pp = packetdup(p, 0, packetsize(p));
237 	trace(TraceLump, "readilump insertlump");
238 	insertlump(u, pp);
239 	trace(TraceLump, "readilump exit");
240 	return p;
241 }
242