1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "local.h"
4 #include "fcall.h"
5
6 static char *
copypages(LogfsServer * server,long newb,long oldb,Pageset copymask,LogfsLowLevelReadResult * llrrp,int * markedbadp)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 *
logfsservercopyactivedata(LogfsServer * server,long newb,long oldblockindex,int forcepage0,LogfsLowLevelReadResult * llrrp,int * markedbadp)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 *
logfsserverreplacedatablock(LogfsServer * server,long index)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 *
logfsserverreplacelogblock(LogfsServer * server,LogSegment * seg,long index)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 *
logfsserverreplaceblock(LogfsServer * server,LogSegment * seg,long index)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