1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "local.h"
4 #include "fcall.h"
5
6 struct DirReadState {
7 u32int offset;
8 u32int lastoffset;
9 u32int limit;
10 uchar *data;
11 };
12
13 typedef struct ReaderState {
14 uchar *buf;
15 u32int maxoffset;
16 LogfsServer *server;
17 char *errmsg;
18 } ReaderState;
19
20 static DirReadState *
drsinit(LogfsIdentityStore * is,Entry * list,uchar * buf,u32int buflen,u32int * rcount)21 drsinit(LogfsIdentityStore *is, Entry *list, uchar *buf, u32int buflen, u32int *rcount)
22 {
23 Entry *p, *q;
24 DirReadState *drs;
25 u32int k;
26 /*
27 * stash as many entries as will fit in the read buffer
28 */
29 *rcount = 0;
30 for(p = list; p; p = p->next) {
31 uint len = logfsflattenentry(is, buf, buflen, p);
32 if(len == 0)
33 break;
34 *rcount += len;
35 buf += len;
36 buflen -= len;
37 }
38 drs = logfsrealloc(nil, sizeof(*drs));
39 if(drs == nil)
40 return nil;
41 drs->offset = *rcount;
42 drs->lastoffset = drs->offset;
43 k = 0;
44 for(q = p; q; q = q->next)
45 k += logfsflattenentry(is, nil, 0, q);
46 if(k) {
47 u32int k2;
48 // print("drsinit: %ud bytes extra\n", k);
49 drs->data = logfsrealloc(nil, k);
50 if(drs->data == nil) {
51 logfsfreemem(drs);
52 return nil;
53 }
54 k2 = 0;
55 for(q = p; q; q = q->next)
56 k2 += logfsflattenentry(is, drs->data + k2, k - k2, q);
57 drs->limit = drs->offset + k;
58 }
59 // print("drsinit: rcount %ud\n", *rcount);
60 return drs;
61 }
62
63 static void
drsread(DirReadState * drs,uchar * buf,u32int buflen,u32int * rcount)64 drsread(DirReadState *drs, uchar *buf, u32int buflen, u32int *rcount)
65 {
66 uchar *p;
67 *rcount = 0;
68 p = drs->data + drs->lastoffset - drs->offset;
69 while(drs->lastoffset < drs->limit) {
70 /*
71 * copy an entry, if it fits
72 */
73 uint len = GBIT16(p) + BIT16SZ;
74 if(len > buflen)
75 break;
76 memmove(buf, p, len);
77 drs->lastoffset += len;
78 *rcount += len;
79 buf += len;
80 buflen -= len;
81 p += len;
82 }
83 if(drs->lastoffset >= drs->limit) {
84 logfsfreemem(drs->data);
85 drs->data = nil;
86 }
87 }
88
89 void
logfsdrsfree(DirReadState ** drsp)90 logfsdrsfree(DirReadState **drsp)
91 {
92 DirReadState *drs = *drsp;
93 if(drs) {
94 logfsfreemem(drs->data);
95 logfsfreemem(drs);
96 *drsp = nil;
97 }
98 }
99
100 static int
reader(void * magic,u32int baseoffset,u32int limitoffset,Extent * e,u32int extentoffset)101 reader(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
102 {
103 ReaderState *s = magic;
104 LogfsServer *server;
105 LogfsLowLevel *ll;
106 LogfsLowLevelReadResult llrr;
107 long seq;
108 int page;
109 int offset;
110 long block;
111 int pagesize;
112 LogSegment *seg;
113 int replace;
114
115 if(e == nil) {
116 //print("fill(%d, %d)\n", baseoffset, limitoffset);
117 memset(s->buf + baseoffset, 0, limitoffset - baseoffset);
118 if(limitoffset > s->maxoffset)
119 s->maxoffset = limitoffset;
120 return 1;
121 }
122 server = s->server;
123 ll = server->ll;
124 /*
125 * extentoffset is how much to trim off the front of the extent
126 */
127 logfsflashaddr2spo(server, e->flashaddr + extentoffset, &seq, &page, &offset);
128 /*
129 * offset is the offset within the page to where e->min is stored
130 */
131 //print("read(%d, %d, %c%ld/%ud/%ud)\n",
132 // baseoffset, limitoffset, (e->flashaddr & LogAddr) ? 'L' : 'D', seq, page, offset);
133 if(e->flashaddr & LogAddr) {
134 if(seq >= server->activelog->unsweptblockindex && seq <= server->activelog->curblockindex)
135 seg = server->activelog;
136 else if(server->sweptlog && seq <= server->sweptlog->curblockindex)
137 seg = server->sweptlog;
138 else {
139 print("logfsserverread: illegal log sequence number %ld (active=[%ld, %ld], swept=[%ld, %ld])\n",
140 seq, server->activelog->unsweptblockindex, server->activelog->curblockindex,
141 server->sweptlog ? 0L : -1L, server->sweptlog ? server->sweptlog->curblockindex : -1L);
142 s->errmsg = logfseinternal;
143 return -1;
144 }
145 if(seg->curpage == page && seg->curblockindex == seq) {
146 /*
147 * it hasn't made it to disk yet
148 */
149 memmove(s->buf + baseoffset, seg->pagebuf + offset, limitoffset - baseoffset);
150 goto done;
151 }
152 if(seq < seg->unsweptblockindex) {
153 /* data already swept */
154 print("logfsserverread: log address has been swept\n");
155 s->errmsg = logfseinternal;
156 return -1;
157 }
158 block = seg->blockmap[seq];
159 }
160 else {
161 seg = nil;
162 if(seq >= server->ndatablocks)
163 block = -1;
164 else
165 block = server->datablock[seq].block;
166 if(block < 0) {
167 print("logfsserveread: data address does not exist\n");
168 s->errmsg = logfseinternal;
169 return -1;
170 }
171 }
172 /*
173 * read as many pages as necessary to get to the limitoffset
174 */
175 pagesize = 1 << ll->l2pagesize;
176 replace = 0;
177 while(baseoffset < limitoffset) {
178 u32int thistime;
179 thistime = pagesize - offset;
180 if(thistime > (limitoffset - baseoffset))
181 thistime = limitoffset - baseoffset;
182 s->errmsg = (*ll->readpagerange)(ll, s->buf + baseoffset, block, page,
183 offset, thistime, &llrr);
184 if(s->errmsg)
185 return -1;
186 if(llrr != LogfsLowLevelReadResultOk) {
187 replace = 1;
188 }
189 baseoffset += thistime;
190 page++;
191 offset = 0;
192 }
193 if(replace) {
194 s->errmsg = logfsserverreplaceblock(server, seg, seq);
195 if(s->errmsg)
196 return -1;
197 }
198 done:
199 if(limitoffset > s->maxoffset)
200 s->maxoffset = limitoffset;
201 return 1;
202 }
203
204 char *
logfsserverread(LogfsServer * server,u32int fid,u32int offset,u32int count,uchar * buf,u32int buflen,u32int * rcount)205 logfsserverread(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int buflen, u32int *rcount)
206 {
207 Fid *f;
208 Entry *e;
209 ReaderState s;
210 int rv;
211
212 if(server->trace > 1)
213 print("logfsserverread(%ud, %ud, %ud)\n", fid, offset, count);
214 f = logfsfidmapfindentry(server->fidmap, fid);
215 if(f == nil)
216 return logfsebadfid;
217 if(f->openmode < 0)
218 return logfsefidnotopen;
219 if((f->openmode & 3) == OWRITE)
220 return logfseaccess;
221 if(count > buflen)
222 return Etoobig;
223 e = f->entry;
224 if(e->deadandgone)
225 return Eio;
226 if(e->qid.type & QTDIR) {
227 if(offset != 0) {
228 if(f->drs == nil || f->drs->lastoffset != offset)
229 return Eio;
230 drsread(f->drs, buf, count, rcount);
231 }
232 else {
233 logfsdrsfree(&f->drs);
234 f->drs = drsinit(server->is, e->u.dir.list, buf, count, rcount);
235 if(f->drs == nil)
236 return Enomem;
237 }
238 return nil;
239 }
240 if(offset >= e->u.file.length) {
241 *rcount = 0;
242 return nil;
243 }
244 s.buf = buf;
245 s.server = server;
246 s.maxoffset = 0;
247 rv = logfsextentlistwalkrange(e->u.file.extent, reader, &s, offset, offset + count);
248 if(rv < 0)
249 return s.errmsg;
250 *rcount = s.maxoffset;
251 return nil;
252 }
253
254