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