1 #include "logfsos.h" 2 #include "logfs.h" 3 #include "local.h" 4 #include "fcall.h" 5 6 static char * 7 copypages(LogfsServer *server, long newb, long oldb, Pageset copymask, LogfsLowLevelReadResult *llrrp, int *markedbadp) 8 { 9 char *errmsg; 10 int page; 11 LogfsLowLevel *ll; 12 int ppb; 13 int pagesize; 14 uchar *buf; 15 16 if(copymask == 0) 17 return nil; 18 19 ll = server->ll; 20 ppb = 1 << ll->l2pagesperblock; 21 pagesize = 1 << ll->l2pagesize; 22 *markedbadp = 0; 23 *llrrp = LogfsLowLevelReadResultOk; 24 errmsg = nil; 25 26 buf = logfsrealloc(nil, 1 << ll->l2pagesize); 27 if(buf == nil) 28 return Enomem; 29 30 for(page = ppb - 1; page >= 0; page--) { 31 Pageset m; 32 33 m = logfsdatapagemask(1, page); 34 35 if(copymask & m) { 36 LogfsLowLevelReadResult llrr; 37 if(server->trace > 1) 38 print("copypages read page %d\n", page); 39 errmsg = (*ll->readpagerange)(ll, buf, oldb, page, 0, pagesize, &llrr); 40 if(errmsg != nil) 41 break; 42 if(llrr > *llrrp) 43 *llrrp = llrr; 44 if(server->trace > 1) 45 print("copypages write page %d\n", page); 46 errmsg = (*ll->writepage)(ll, buf, newb, page); 47 if(errmsg) { 48 if(strcmp(errmsg, Eio) == 0) { 49 (*ll->markblockbad)(ll, newb); 50 *markedbadp = 1; 51 } 52 break; 53 } 54 if(server->trace > 1) 55 print("copypages end page %d\n", page); 56 } 57 } 58 logfsfreemem(buf); 59 return errmsg; 60 } 61 62 char * 63 logfsservercopyactivedata(LogfsServer *server, long newb, long oldblockindex, int forcepage0, LogfsLowLevelReadResult *llrrp, int *markedbadp) 64 { 65 LogfsLowLevel *ll = server->ll; 66 ulong newpath; 67 DataBlock *ob; 68 char *errmsg; 69 Pageset copymask; 70 71 ob = server->datablock + oldblockindex; 72 copymask = ~ob->free; 73 if(forcepage0) 74 copymask |= logfsdatapagemask(1, 0); 75 if(server->trace > 1) 76 print("copyactivedata %ld: (%ld -> %ld)\n", oldblockindex, ob->block, newb); 77 newpath = mkdatapath(dataseqof(ob->path), copygensucc(copygenof(ob->path))); 78 (*ll->setblocktag)(ll, newb, LogfsTdata); 79 (*ll->setblockpath)(ll, newb, newpath); 80 errmsg = copypages(server, newb, ob->block, copymask, llrrp, markedbadp); 81 if(errmsg) 82 return errmsg; 83 /* 84 * anything not copied is now not dirty 85 */ 86 ob->dirty &= copymask; 87 ob->block = newb; 88 ob->path = newpath; 89 return nil; 90 } 91 92 /* 93 * unconditionally replace a datablock, and mark the old one bad 94 * NB: if page 0 is apparently unused, force it to be copied, and mark 95 * it free and dirty afterwards 96 */ 97 char * 98 logfsserverreplacedatablock(LogfsServer *server, long index) 99 { 100 long newb; 101 LogfsLowLevel *ll = server->ll; 102 103 newb = logfsfindfreeblock(ll, AllocReasonReplace); 104 /* TODO - recover space by scavenging other blocks, or recycling the log */ 105 while(newb >= 0) { 106 char *errmsg; 107 LogfsLowLevelReadResult llrr; 108 long oldblock; 109 int markedbad; 110 DataBlock *db; 111 112 db = server->datablock + index; 113 oldblock = db->block; 114 errmsg = logfsservercopyactivedata(server, newb, index, 1, &llrr, &markedbad); 115 if(errmsg) { 116 if(!markedbad) 117 return errmsg; 118 newb = logfsfindfreeblock(ll, AllocReasonReplace); 119 continue; 120 } 121 (*ll->markblockbad)(ll, oldblock); 122 return nil; 123 } 124 return logfsefullreplacing; 125 } 126 127 char * 128 logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index) 129 { 130 ulong opath; 131 LogfsLowLevel *ll = server->ll; 132 long oldb = seg->blockmap[index]; 133 134 opath = (*ll->getblockpath)(ll, oldb); 135 136 for(;;) { 137 long newb; 138 int pages; 139 char *errmsg; 140 LogfsLowLevelReadResult llrr; 141 int markedbad; 142 143 newb = logfsfindfreeblock(ll, AllocReasonReplace); 144 if(newb < 0) 145 return "full replacing log block"; 146 /* TODO - scavenge data space for a spare block */ 147 (*ll->setblocktag)(ll, newb, LogfsTlog); 148 (*ll->setblockpath)(ll, newb, mklogpath(seg->gen, index, copygensucc(copygenof(opath)))); 149 if(index == seg->curblockindex) 150 pages = seg->curpage; 151 else 152 pages = 1 << server->ll->l2pagesperblock; 153 errmsg = copypages(server, newb, oldb, logfsdatapagemask(pages, 0), &llrr, &markedbad); 154 if(errmsg == nil) { 155 (*ll->markblockbad)(ll, seg->blockmap[index]); 156 seg->blockmap[index] = newb; 157 return nil; 158 } 159 if(!markedbad) 160 return errmsg; 161 } 162 } 163 164 char * 165 logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long index) 166 { 167 if(seg) 168 return logfsserverreplacelogblock(server, seg, index); 169 else 170 return logfsserverreplacedatablock(server, index); 171 } 172