1 #include "lib9.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, ulong 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 ulong 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 70 ob = server->datablock + oldblockindex; 71 if(forcepage0) { 72 u32int mask; 73 mask = logfsdatapagemask(1, 0); 74 if(ob->free & mask) { 75 ob->dirty |= mask; 76 ob->free |= mask; 77 } 78 } 79 if(server->trace > 1) 80 print("copyactivedata %ld: (%ld -> %ld)\n", oldblockindex, ob->block, newb); 81 newpath = mkdatapath(dataseqof(ob->path), copygensucc(copygenof(ob->path))); 82 (*ll->setblocktag)(ll, newb, LogfsTdata); 83 (*ll->setblockpath)(ll, newb, newpath); 84 errmsg = copypages(server, newb, ob->block, ~ob->free, llrrp, markedbadp); 85 if(errmsg) 86 return errmsg; 87 /* 88 * anything dirty and free is now not dirty and free 89 */ 90 ob->dirty &= ~(ob->dirty & ob->free); 91 ob->block = newb; 92 ob->path = newpath; 93 return nil; 94 } 95 96 /* 97 * unconditionally replace a datablock, and mark the old one bad 98 * NB: if page 0 is apparently unused, force it to be copied, and mark 99 * it free and dirty afterwards 100 */ 101 char * 102 logfsserverreplacedatablock(LogfsServer *server, long index) 103 { 104 long newb; 105 LogfsLowLevel *ll = server->ll; 106 107 newb = logfsfindfreeblock(ll, AllocReasonReplace); 108 /* TODO - recover space by scavenging other blocks, or recycling the log */ 109 while(newb >= 0) { 110 char *errmsg; 111 LogfsLowLevelReadResult llrr; 112 long oldblock; 113 int markedbad; 114 DataBlock *db; 115 116 db = server->datablock + index; 117 oldblock = db->block; 118 errmsg = logfsservercopyactivedata(server, newb, index, 1, &llrr, &markedbad); 119 if(errmsg) { 120 if(!markedbad) 121 return errmsg; 122 newb = logfsfindfreeblock(ll, AllocReasonReplace); 123 continue; 124 } 125 (*ll->markblockbad)(ll, oldblock); 126 return nil; 127 } 128 return logfsefullreplacing; 129 } 130 131 char * 132 logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index) 133 { 134 ulong opath; 135 LogfsLowLevel *ll = server->ll; 136 long oldb = seg->blockmap[index]; 137 138 opath = (*ll->getblockpath)(ll, oldb); 139 140 for(;;) { 141 long newb; 142 int pages; 143 char *errmsg; 144 LogfsLowLevelReadResult llrr; 145 int markedbad; 146 147 newb = logfsfindfreeblock(ll, AllocReasonReplace); 148 if(newb < 0) 149 return "full replacing log block"; 150 /* TODO - scavenge data space for a spare block */ 151 (*ll->setblocktag)(ll, newb, LogfsTlog); 152 (*ll->setblockpath)(ll, newb, mklogpath(seg->gen, index, copygensucc(copygenof(opath)))); 153 if(index == seg->curblockindex) 154 pages = seg->curpage; 155 else 156 pages = 1 << server->ll->l2pagesperblock; 157 errmsg = copypages(server, newb, oldb, logfsdatapagemask(pages, 0), &llrr, &markedbad); 158 if(errmsg == nil) { 159 (*ll->markblockbad)(ll, seg->blockmap[index]); 160 seg->blockmap[index] = newb; 161 return nil; 162 } 163 if(!markedbad) 164 return errmsg; 165 } 166 } 167 168 char * 169 logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long index) 170 { 171 if(seg) 172 return logfsserverreplacelogblock(server, seg, index); 173 else 174 return logfsserverreplacedatablock(server, index); 175 } 176