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