xref: /inferno-os/liblogfs/log.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
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