1 #include "lib9.h" 2 #include "logfs.h" 3 #include "local.h" 4 #include "fcall.h" 5 6 void 7 logfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset) 8 { 9 LogfsLowLevel *ll = server->ll; 10 flashaddr &= ~LogAddr; 11 *offset = flashaddr & ((1 << ll->l2pagesize) - 1); 12 flashaddr >>= ll->l2pagesize; 13 *page = flashaddr & ((1 << ll->l2pagesperblock) - 1); 14 flashaddr >>= ll->l2pagesperblock; 15 *seq = flashaddr; 16 } 17 18 u32int 19 logfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset) 20 { 21 //print("logfsspo2flashaddr(%ld, %d, %d)\n", seq, page, offset); 22 return (((seq << server->ll->l2pagesperblock) + page) << server->ll->l2pagesize) + offset; 23 } 24 25 void 26 logfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset) 27 { 28 LogfsLowLevel *ll = server->ll; 29 flashaddr &= ~LogAddr; 30 *offset = flashaddr & ((1 << ll->l2pagesize) - 1); 31 } 32 33 char * 34 logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp) 35 { 36 LogSegment *seg; 37 seg = logfsrealloc(nil, sizeof(LogSegment) + (server->ll->blocks - 1) * sizeof(long)); 38 if(seg == nil) 39 return Enomem; 40 seg->pagebuf = logfsrealloc(nil, 1 << server->ll->l2pagesize); 41 if(seg->pagebuf == nil) { 42 logfsfreemem(seg); 43 return Enomem; 44 } 45 seg->curpage = -1; 46 seg->curblockindex = -1; 47 seg->gen = gen; 48 *segp = seg; 49 return nil; 50 } 51 52 void 53 logfslogsegmentfree(LogSegment **segp) 54 { 55 LogSegment *seg = *segp; 56 if(seg) { 57 logfsfreemem(seg->pagebuf); 58 logfsfreemem(seg); 59 *segp = nil; 60 } 61 } 62 63 char * 64 logfslogsegmentflush(LogfsServer *server, int active) 65 { 66 LogSegment *seg; 67 seg = active ? server->activelog : server->sweptlog; 68 if(seg == nil) 69 return nil; 70 if(seg->curpage >= 0 && seg->nbytes) { 71 char *errmsg; 72 LogfsLowLevel *ll = server->ll; 73 int pagesize = 1 << ll->l2pagesize; 74 //print("curblockindex %ld curpage %d nbytes %d\n", seg->curblockindex, seg->curpage, seg->nbytes); 75 if(seg->nbytes < pagesize) 76 seg->pagebuf[seg->nbytes++] = LogfsLogTend; 77 memset(seg->pagebuf + seg->nbytes, 0xff, pagesize - seg->nbytes); 78 for(;;) { 79 errmsg = (*ll->writepage)(ll, seg->pagebuf, 80 seg->blockmap[seg->curblockindex], seg->curpage); 81 if(errmsg == nil) 82 break; 83 if(strcmp(errmsg, Eio) != 0) 84 return errmsg; 85 errmsg = logfsserverreplacelogblock(server, seg, seg->curblockindex); 86 if(errmsg) 87 return errmsg; 88 } 89 seg->curpage++; 90 if(seg->curpage == (1 << ll->l2pagesperblock)) 91 seg->curpage = -1; 92 seg->nbytes = 0; 93 } 94 return nil; 95 } 96 97 static char * 98 logspace(LogfsServer *server, int active, int takearisk, int nbytes, uchar **where, u32int *flashaddr) 99 { 100 char *errmsg; 101 LogfsLowLevel *ll = server->ll; 102 int pagesize = 1 << ll->l2pagesize; 103 LogSegment *seg; 104 105 if(nbytes > pagesize) 106 return logfselogmsgtoobig; 107 retry: 108 seg = active ? server->activelog : server->sweptlog; 109 for(;;) { 110 //print("curpage %d nbytes %d\n", seg->curpage, seg->nbytes); 111 if(seg->curpage >= 0) { 112 if(seg->nbytes + nbytes < pagesize) 113 break; 114 errmsg = logfslogsegmentflush(server, active); 115 if(errmsg) 116 return errmsg; 117 } 118 if(seg->curpage < 0) { 119 long block; 120 long path; 121 block = logfsfindfreeblock(ll, 122 active ? (takearisk ? AllocReasonLogExtend : AllocReasonDataExtend) : AllocReasonTransfer); 123 if(block < 0) { 124 if(active) { 125 int didsomething; 126 errmsg = logfsserverlogsweep(server, 0, &didsomething); 127 if(errmsg) 128 return errmsg; 129 if(didsomething) 130 goto retry; 131 } 132 return logfselogfull; 133 } 134 seg->blockmap[++seg->curblockindex] = block; 135 path = mklogpath(seg->curblockindex, seg->gen, 0); 136 (*ll->setblocktag)(ll, block, LogfsTlog); 137 (*ll->setblockpath)(ll, block, path); 138 seg->curpage = 0; 139 #ifdef FUTURE 140 /* TODO - do we need one of these if the underlying system supports erase counting? */ 141 seg->pagebuf[0] = LogfsLogTstart; 142 PBIT16(seg->pagebuf + 1, 8); 143 PBIT32(seg->pagebuf + 3, path); /* TODO duplicate information */ 144 PBIT32(seg->pagebuf + 7, 0); /* TODO don't have this - discuss with forsyth */ 145 seg->nbytes = 11; 146 #else 147 seg->nbytes = 0; 148 #endif 149 } 150 } 151 *where = seg->pagebuf + seg->nbytes; 152 if(flashaddr) 153 *flashaddr = logfsspo2flashaddr(server, seg->curblockindex, seg->curpage, seg->nbytes); 154 seg->nbytes += nbytes; 155 return nil; 156 } 157 158 static void 159 logdirty(LogfsServer *server, int active) 160 { 161 if(active) 162 server->activelog->dirty = 1; 163 else 164 server->sweptlog->dirty = 1; 165 } 166 167 char * 168 logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size) 169 { 170 char *errmsg; 171 uchar *p; 172 173 errmsg = logspace(server, active, 0, size, &p, nil); 174 if(errmsg) 175 return errmsg; 176 memcpy(p, msg, size); 177 logdirty(server, active); 178 return nil; 179 } 180 181 char * 182 logfslog(LogfsServer *server, int active, LogMessage *s) 183 { 184 uint size = logfssizeS2M(s); 185 char *errmsg; 186 uchar *p; 187 int takearisk; 188 189 if(server->trace > 1) { 190 print("%c<< ", active ? 'A' : 'S'); 191 logfsdumpS(s); 192 print("\n"); 193 } 194 if(active) { 195 switch(s->type) { 196 case LogfsLogTremove: 197 case LogfsLogTtrunc: 198 takearisk = 1; 199 break; 200 default: 201 takearisk = 0; 202 } 203 } 204 else 205 takearisk = 0; 206 errmsg = logspace(server, active, takearisk, size, &p, nil); 207 if(errmsg) 208 return errmsg; 209 if(logfsconvS2M(s, p, size) != size) 210 return "bad conversion"; 211 logdirty(server, active); 212 return nil; 213 } 214 215 int 216 lognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen) 217 { 218 int rawspace; 219 LogSegment *seg; 220 if(count > LogDataLimit) 221 return 0; 222 seg = active ? server->activelog : server->sweptlog; 223 if(seg->curpage < 0) 224 return LogDataLimit; 225 rawspace = (1 << server->ll->l2pagesize) - seg->nbytes; 226 if(rawspace < 5 * 4 + 2 + muidlen + 1) 227 return LogDataLimit; 228 return 5 * 4 + 2 + muidlen - rawspace; 229 } 230 231 char * 232 logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime, u32int cvers, 233 char *muid, uchar *data, u32int *flashaddr) 234 { 235 /* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */ 236 LogMessage s; 237 uint size; 238 char *errmsg; 239 uchar *p; 240 u32int faddr; 241 uint asize; 242 243 s.type = LogfsLogTwrite; 244 s.path = path; 245 s.u.write.offset = offset; 246 s.u.write.count = count; 247 s.u.write.mtime = mtime; 248 s.u.write.cvers = cvers; 249 s.u.write.muid = muid; 250 s.u.write.data = data; 251 size = logfssizeS2M(&s); 252 errmsg = logspace(server, active, 0, size, &p, &faddr); 253 if(errmsg) 254 return errmsg; 255 if(data) 256 *flashaddr = (faddr + size - count) | LogAddr; 257 s.u.write.flashaddr = *flashaddr; 258 if(server->trace > 1) { 259 print("%c<< ", active ? 'A' : 'S'); 260 logfsdumpS(&s); 261 print("\n"); 262 } 263 if((asize = logfsconvS2M(&s, p, size)) != size) { 264 print("expected %d actual %d\n", size, asize); 265 return "bad conversion"; 266 } 267 logdirty(server, active); 268 return nil; 269 } 270 271