1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "local.h"
4 #include "fcall.h"
5
6 void
logfsflashaddr2spo(LogfsServer * server,u32int flashaddr,long * seq,int * page,int * offset)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
logfsspo2flashaddr(LogfsServer * server,long seq,int page,int offset)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
logfsflashaddr2o(LogfsServer * server,u32int flashaddr,int * offset)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 *
logfslogsegmentnew(LogfsServer * server,int gen,LogSegment ** segp)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
logfslogsegmentfree(LogSegment ** segp)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 *
logfslogsegmentflush(LogfsServer * server,int active)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 *
logspace(LogfsServer * server,int active,int takearisk,int nbytes,uchar ** where,u32int * flashaddr)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
logdirty(LogfsServer * server,int active)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 *
logfslogbytes(LogfsServer * server,int active,uchar * msg,uint size)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 memmove(p, msg, size);
177 logdirty(server, active);
178 return nil;
179 }
180
181 char *
logfslog(LogfsServer * server,int active,LogMessage * s)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
lognicesizeforwrite(LogfsServer * server,int active,u32int count,int muidlen)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 *
logfslogwrite(LogfsServer * server,int active,u32int path,u32int offset,int count,u32int mtime,u32int cvers,char * muid,uchar * data,u32int * flashaddr)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