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 * 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 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 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 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 * 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