1 #include "logfsos.h" 2 #include "logfs.h" 3 #include "local.h" 4 #include "fcall.h" 5 6 static void 7 maxpath(LogfsServer *server, ulong p) 8 { 9 if(p > server->path) 10 server->path = p; 11 } 12 13 static char * 14 recreate(LogfsServer *server, LogMessage *s, int *ok) 15 { 16 Entry *parent; 17 char *errmsg; 18 Entry *e; 19 Path *p; 20 21 parent = logfspathmapfinde(server->pathmap, s->path); 22 if(parent == nil) 23 return "can't find parent"; 24 if(logfspathmapfindentry(server->pathmap, s->u.create.newpath) != nil){ 25 Entry *d = logfspathmapfinde(server->pathmap, s->u.create.newpath); 26 if(d == nil) 27 print("existing was nil\n"); 28 else{ 29 print("existing: name=%q d=%d path=%8.8llux uid=%q gid=%q perm=%#uo\n", 30 d->name, d->deadandgone, d->qid.path, d->uid, d->gid, d->perm); 31 } 32 return "duplicate path"; 33 } 34 if((parent->qid.type & QTDIR) == 0) 35 return Enotdir; 36 errmsg = logfsentrynew(server, 1, s->u.create.newpath, parent, 37 s->u.create.name, s->u.create.uid, s->u.create.gid, s->u.create.mtime, s->u.create.uid, 38 s->u.create.perm, s->u.create.cvers, 0, &e); 39 if(errmsg) { 40 *ok = 0; 41 return errmsg; 42 } 43 /* p guaranteed to be non null */ 44 errmsg = logfspathmapnewentry(server->pathmap, s->u.create.newpath, e, &p); 45 if(errmsg) { 46 logfsfreemem(e); 47 *ok = 0; 48 return errmsg; 49 } 50 e->next = parent->u.dir.list; 51 parent->u.dir.list = e; 52 return nil; 53 } 54 55 static char * 56 reremove(LogfsServer *server, LogMessage *s, int *ok) 57 { 58 Entry *oe; 59 Entry *parent; 60 Entry **ep; 61 Entry *e; 62 char *ustmuid; 63 64 USED(ok); 65 oe = logfspathmapfinde(server->pathmap, s->path); 66 if(oe == nil) 67 return logfseunknownpath; 68 parent = oe->parent; 69 if(parent == oe) 70 return "tried to remove root"; 71 if((parent->qid.type & QTDIR) == 0) 72 return Enotdir; 73 if((oe->qid.type & QTDIR) != 0 && oe->u.dir.list) 74 return logfsenotempty; 75 for(ep = &parent->u.dir.list; e = *ep; ep = &e->next) 76 if(e == oe) 77 break; 78 if(e == nil) 79 return logfseinternal; 80 ustmuid = logfsisustadd(server->is, s->u.remove.muid); 81 if(ustmuid == nil) 82 return Enomem; 83 parent->mtime = s->u.remove.mtime; 84 parent->muid = ustmuid; 85 logfspathmapdeleteentry(server->pathmap, s->path); 86 *ep = e->next; 87 if(e->inuse > 1) { 88 print("replay: entry inuse > 1\n"); 89 e->inuse = 1; 90 } 91 logfsentryclunk(e); 92 return nil; 93 } 94 95 static char * 96 retrunc(LogfsServer *server, LogMessage *s, int *ok) 97 { 98 Entry *e; 99 char *ustmuid; 100 101 USED(ok); 102 e = logfspathmapfinde(server->pathmap, s->path); 103 if(e == nil) 104 return logfseunknownpath; 105 if((e->qid.type & QTDIR) != 0) 106 return Eperm; 107 if(e->u.file.cvers >= s->u.trunc.cvers) 108 return "old news"; 109 ustmuid = logfsisustadd(server->is, s->u.trunc.muid); 110 if(ustmuid == nil) 111 return Enomem; 112 e->muid = ustmuid; 113 e->mtime = s->u.trunc.mtime; 114 e->qid.vers++; 115 e->u.file.cvers = s->u.trunc.cvers; 116 /* 117 * zap all extents 118 */ 119 logfsextentlistreset(e->u.file.extent); 120 e->u.file.length = 0; 121 return nil; 122 } 123 124 static char * 125 rewrite(LogfsServer *server, LogMessage *s, int *ok) 126 { 127 Entry *e; 128 char *ustmuid; 129 Extent extent; 130 char *errmsg; 131 132 USED(ok); 133 e = logfspathmapfinde(server->pathmap, s->path); 134 if(e == nil) 135 return logfseunknownpath; 136 if((e->qid.type & QTDIR) != 0) 137 return Eperm; 138 if(e->u.file.cvers != s->u.write.cvers) 139 return nil; 140 ustmuid = logfsisustadd(server->is, s->u.write.muid); 141 if(ustmuid == nil) 142 return Enomem; 143 extent.min = s->u.write.offset; 144 extent.max = s->u.write.offset + s->u.write.count; 145 extent.flashaddr = s->u.write.flashaddr; 146 errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil); 147 if(errmsg) 148 return errmsg; 149 e->mtime = s->u.write.mtime; 150 e->muid = ustmuid; 151 if(extent.max > e->u.file.length) 152 e->u.file.length = extent.max; 153 /* TODO forsyth increments vers here; not sure whether necessary */ 154 return nil; 155 } 156 157 static char * 158 rewstat(LogfsServer *server, LogMessage *s, int *ok) 159 { 160 Entry *e; 161 char *errmsg; 162 char *cname, *ustgid, *ustmuid; 163 char *ustuid; 164 165 USED(ok); 166 e = logfspathmapfinde(server->pathmap, s->path); 167 if(e == nil) 168 return logfseunknownpath; 169 cname = nil; 170 ustuid = nil; 171 ustgid = nil; 172 ustmuid = nil; 173 if(s->u.wstat.name) { 174 cname = logfsstrdup(s->u.wstat.name); 175 if(cname == nil) { 176 memerror: 177 errmsg = Enomem; 178 goto fail; 179 } 180 } 181 if(s->u.wstat.uid) { 182 ustuid = logfsisustadd(server->is, s->u.wstat.uid); 183 if(ustuid == nil) 184 goto memerror; 185 } 186 if(s->u.wstat.gid) { 187 ustgid = logfsisustadd(server->is, s->u.wstat.gid); 188 if(ustgid == nil) 189 goto memerror; 190 } 191 if(s->u.wstat.muid) { 192 ustmuid = logfsisustadd(server->is, s->u.wstat.muid); 193 if(ustmuid == nil) 194 goto memerror; 195 } 196 if(cname) { 197 logfsfreemem(e->name); 198 e->name = cname; 199 cname = nil; 200 } 201 if(ustuid) 202 e->uid = ustuid; 203 if(ustgid) 204 e->gid = ustgid; 205 if(ustmuid) 206 e->muid = ustmuid; 207 if(s->u.wstat.perm != ~0) 208 e->perm = (e->perm & DMDIR) | (s->u.wstat.perm & ~DMDIR); 209 if(s->u.wstat.mtime != ~0) 210 e->mtime = s->u.wstat.mtime; 211 errmsg = nil; 212 fail: 213 logfsfreemem(cname); 214 return errmsg; 215 } 216 217 static char * 218 replayblock(LogfsServer *server, LogSegment *seg, uchar *buf, long i, int *pagep, int disableerrors) 219 { 220 int page; 221 LogfsLowLevel *ll = server->ll; 222 LogfsLowLevelReadResult llrr; 223 ushort size; 224 LogMessage s; 225 int ppb = 1 << ll->l2pagesperblock; 226 int pagesize = 1 << ll->l2pagesize; 227 228 for(page = 0; page < ppb; page++) { 229 uchar *p, *bufend; 230 char *errmsg = (*ll->readpagerange)(ll, buf, seg->blockmap[i], page, 0, pagesize, &llrr); 231 if(errmsg) 232 return errmsg; 233 if(llrr != LogfsLowLevelReadResultOk) 234 logfsserverreplacelogblock(server, seg, i); 235 /* ignore failure to replace block */ 236 if(server->trace > 1) 237 print("replaying seq %ld block %ld page %d\n", i, seg->blockmap[i], page); 238 p = buf; 239 if(*p == 0xff) 240 break; 241 bufend = p + pagesize; 242 while(p < bufend) { 243 int ok = 1; 244 size = logfsconvM2S(p, bufend - p, &s); 245 if(size == 0) 246 return "parse failure"; 247 if(server->trace > 1) { 248 print(">> "); 249 logfsdumpS(&s); 250 print("\n"); 251 } 252 if(s.type == LogfsLogTend) 253 break; 254 switch(s.type) { 255 case LogfsLogTstart: 256 break; 257 case LogfsLogTcreate: 258 maxpath(server, s.path); 259 maxpath(server, s.u.create.newpath); 260 errmsg = recreate(server, &s, &ok); 261 break; 262 case LogfsLogTtrunc: 263 maxpath(server, s.path); 264 errmsg = retrunc(server, &s, &ok); 265 break; 266 case LogfsLogTremove: 267 maxpath(server, s.path); 268 errmsg = reremove(server, &s, &ok); 269 break; 270 case LogfsLogTwrite: 271 maxpath(server, s.path); 272 errmsg = rewrite(server, &s, &ok); 273 break; 274 case LogfsLogTwstat: 275 maxpath(server, s.path); 276 errmsg = rewstat(server, &s, &ok); 277 break; 278 default: 279 return "bad tag in log page"; 280 } 281 if(!ok) 282 return errmsg; 283 if(errmsg && !disableerrors){ 284 print("bad replay: %s\n", errmsg); 285 print("on: "); logfsdumpS(&s); print("\n"); 286 } 287 p += size; 288 } 289 } 290 *pagep = page; 291 return nil; 292 } 293 294 static int 295 map(void *magic, Extent *x, int hole) 296 { 297 LogfsServer *server; 298 LogfsLowLevel *ll; 299 long seq; 300 int page; 301 int offset; 302 Pageset mask; 303 DataBlock *db; 304 305 if(hole || (x->flashaddr & LogAddr) != 0) 306 return 1; 307 server = magic; 308 ll = server->ll; 309 logfsflashaddr2spo(server, x->flashaddr, &seq, &page, &offset); 310 if(seq >= server->ndatablocks || (db = server->datablock + seq)->block < 0) { 311 print("huntfordata: seq %ld invalid\n", seq); 312 return 1; 313 } 314 mask = logfsdatapagemask((x->max - x->min + offset + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize, page); 315 //print("mask 0x%.8ux free 0x%.8ux dirty 0x%.8ux\n", mask, db->free, db->dirty); 316 if((db->free & mask) != mask) 317 print("huntfordata: data referenced more than once: block %ld(%ld) free 0x%.8llux mask 0x%.8llux\n", 318 seq, db->block, (u64int)db->free, (u64int)mask); 319 db->free &= ~mask; 320 db->dirty |= mask; 321 return 1; 322 } 323 324 static void 325 huntfordatainfile(LogfsServer *server, Entry *e) 326 { 327 logfsextentlistwalk(e->u.file.extent, map, server); 328 } 329 330 static void 331 huntfordataindir(LogfsServer *server, Entry *pe) 332 { 333 Entry *e; 334 for(e = pe->u.dir.list; e; e = e->next) 335 if(e->qid.type & QTDIR) 336 huntfordataindir(server, e); 337 else 338 huntfordatainfile(server, e); 339 } 340 341 char * 342 logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock) 343 { 344 uchar *buf; 345 long i; 346 int page; 347 char *errmsg; 348 349 if(seg == nil || seg->curblockindex < 0) 350 return nil; 351 buf = logfsrealloc(nil, 1 << server->ll->l2pagesize); 352 if(buf == nil) 353 return Enomem; 354 for(i = 0; i <= seg->curblockindex; i++) { 355 errmsg = replayblock(server, seg, buf, i, &page, disableerrorsforfirstblock); 356 disableerrorsforfirstblock = 0; 357 if(errmsg) { 358 print("logfsreplay: error: %s\n", errmsg); 359 goto fail; 360 } 361 } 362 /* 363 * if the last block ended early, restart at the first free page 364 */ 365 if(page < (1 << server->ll->l2pagesperblock)) 366 seg->curpage = page; 367 errmsg = nil; 368 fail: 369 logfsfreemem(buf); 370 return errmsg; 371 } 372 373 void 374 logfsreplayfinddata(LogfsServer *server) 375 { 376 huntfordataindir(server, &server->root); 377 if(server->trace > 0) { 378 long i; 379 DataBlock *db; 380 for(i = 0, db = server->datablock; i < server->ndatablocks; i++, db++) { 381 logfsfreeanddirtydatablockcheck(server, i); 382 if(db->block >= 0) 383 print("%4ld: free 0x%.8llux dirty 0x%.8llux\n", i, (u64int)server->datablock[i].free, (u64int)server->datablock[i].dirty); 384 } 385 } 386 } 387