xref: /inferno-os/liblogfs/log.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "local.h"
437da2899SCharles.Forsyth #include "fcall.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth void
logfsflashaddr2spo(LogfsServer * server,u32int flashaddr,long * seq,int * page,int * offset)737da2899SCharles.Forsyth logfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset)
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth 	LogfsLowLevel *ll = server->ll;
1037da2899SCharles.Forsyth 	flashaddr &= ~LogAddr;
1137da2899SCharles.Forsyth 	*offset = flashaddr & ((1 << ll->l2pagesize) - 1);
1237da2899SCharles.Forsyth 	flashaddr >>= ll->l2pagesize;
1337da2899SCharles.Forsyth 	*page = flashaddr & ((1 << ll->l2pagesperblock) - 1);
1437da2899SCharles.Forsyth 	flashaddr >>= ll->l2pagesperblock;
1537da2899SCharles.Forsyth 	*seq = flashaddr;
1637da2899SCharles.Forsyth }
1737da2899SCharles.Forsyth 
1837da2899SCharles.Forsyth u32int
logfsspo2flashaddr(LogfsServer * server,long seq,int page,int offset)1937da2899SCharles.Forsyth logfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset)
2037da2899SCharles.Forsyth {
2137da2899SCharles.Forsyth //print("logfsspo2flashaddr(%ld, %d, %d)\n", seq, page, offset);
2237da2899SCharles.Forsyth 	return (((seq << server->ll->l2pagesperblock) + page) << server->ll->l2pagesize) + offset;
2337da2899SCharles.Forsyth }
2437da2899SCharles.Forsyth 
2537da2899SCharles.Forsyth void
logfsflashaddr2o(LogfsServer * server,u32int flashaddr,int * offset)2637da2899SCharles.Forsyth logfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset)
2737da2899SCharles.Forsyth {
2837da2899SCharles.Forsyth 	LogfsLowLevel *ll = server->ll;
2937da2899SCharles.Forsyth 	flashaddr &= ~LogAddr;
3037da2899SCharles.Forsyth 	*offset = flashaddr & ((1 << ll->l2pagesize) - 1);
3137da2899SCharles.Forsyth }
3237da2899SCharles.Forsyth 
3337da2899SCharles.Forsyth char *
logfslogsegmentnew(LogfsServer * server,int gen,LogSegment ** segp)3437da2899SCharles.Forsyth logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp)
3537da2899SCharles.Forsyth {
3637da2899SCharles.Forsyth 	LogSegment *seg;
3737da2899SCharles.Forsyth 	seg = logfsrealloc(nil, sizeof(LogSegment) + (server->ll->blocks - 1) * sizeof(long));
3837da2899SCharles.Forsyth 	if(seg == nil)
3937da2899SCharles.Forsyth 		return Enomem;
4037da2899SCharles.Forsyth 	seg->pagebuf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
4137da2899SCharles.Forsyth 	if(seg->pagebuf == nil) {
4237da2899SCharles.Forsyth 		logfsfreemem(seg);
4337da2899SCharles.Forsyth 		return Enomem;
4437da2899SCharles.Forsyth 	}
4537da2899SCharles.Forsyth 	seg->curpage = -1;
4637da2899SCharles.Forsyth 	seg->curblockindex = -1;
4737da2899SCharles.Forsyth 	seg->gen = gen;
4837da2899SCharles.Forsyth 	*segp = seg;
4937da2899SCharles.Forsyth 	return nil;
5037da2899SCharles.Forsyth }
5137da2899SCharles.Forsyth 
5237da2899SCharles.Forsyth void
logfslogsegmentfree(LogSegment ** segp)5337da2899SCharles.Forsyth logfslogsegmentfree(LogSegment **segp)
5437da2899SCharles.Forsyth {
5537da2899SCharles.Forsyth 	LogSegment *seg = *segp;
5637da2899SCharles.Forsyth 	if(seg) {
5737da2899SCharles.Forsyth 		logfsfreemem(seg->pagebuf);
5837da2899SCharles.Forsyth 		logfsfreemem(seg);
5937da2899SCharles.Forsyth 		*segp = nil;
6037da2899SCharles.Forsyth 	}
6137da2899SCharles.Forsyth }
6237da2899SCharles.Forsyth 
6337da2899SCharles.Forsyth char *
logfslogsegmentflush(LogfsServer * server,int active)6437da2899SCharles.Forsyth logfslogsegmentflush(LogfsServer *server, int active)
6537da2899SCharles.Forsyth {
6637da2899SCharles.Forsyth 	LogSegment *seg;
6737da2899SCharles.Forsyth 	seg = active ? server->activelog : server->sweptlog;
6837da2899SCharles.Forsyth 	if(seg == nil)
6937da2899SCharles.Forsyth 		return nil;
7037da2899SCharles.Forsyth 	if(seg->curpage >= 0 && seg->nbytes) {
7137da2899SCharles.Forsyth 		char *errmsg;
7237da2899SCharles.Forsyth 		LogfsLowLevel *ll = server->ll;
7337da2899SCharles.Forsyth 		int pagesize = 1 << ll->l2pagesize;
7437da2899SCharles.Forsyth //print("curblockindex %ld curpage %d nbytes %d\n", seg->curblockindex, seg->curpage, seg->nbytes);
7537da2899SCharles.Forsyth 		if(seg->nbytes < pagesize)
7637da2899SCharles.Forsyth 			seg->pagebuf[seg->nbytes++] = LogfsLogTend;
7737da2899SCharles.Forsyth 		memset(seg->pagebuf + seg->nbytes, 0xff, pagesize - seg->nbytes);
7837da2899SCharles.Forsyth 		for(;;) {
7937da2899SCharles.Forsyth 			errmsg = (*ll->writepage)(ll, seg->pagebuf,
8037da2899SCharles.Forsyth 				seg->blockmap[seg->curblockindex], seg->curpage);
8137da2899SCharles.Forsyth 			if(errmsg == nil)
8237da2899SCharles.Forsyth 				break;
8337da2899SCharles.Forsyth 			if(strcmp(errmsg, Eio) != 0)
8437da2899SCharles.Forsyth 				return errmsg;
8537da2899SCharles.Forsyth 			errmsg = logfsserverreplacelogblock(server, seg, seg->curblockindex);
8637da2899SCharles.Forsyth 			if(errmsg)
8737da2899SCharles.Forsyth 				return errmsg;
8837da2899SCharles.Forsyth 		}
8937da2899SCharles.Forsyth 		seg->curpage++;
9037da2899SCharles.Forsyth 		if(seg->curpage == (1 << ll->l2pagesperblock))
9137da2899SCharles.Forsyth 			seg->curpage = -1;
9237da2899SCharles.Forsyth 		seg->nbytes = 0;
9337da2899SCharles.Forsyth 	}
9437da2899SCharles.Forsyth 	return nil;
9537da2899SCharles.Forsyth }
9637da2899SCharles.Forsyth 
9737da2899SCharles.Forsyth static char *
logspace(LogfsServer * server,int active,int takearisk,int nbytes,uchar ** where,u32int * flashaddr)9837da2899SCharles.Forsyth logspace(LogfsServer *server, int active, int takearisk, int nbytes, uchar **where, u32int *flashaddr)
9937da2899SCharles.Forsyth {
10037da2899SCharles.Forsyth 	char *errmsg;
10137da2899SCharles.Forsyth 	LogfsLowLevel *ll = server->ll;
10237da2899SCharles.Forsyth 	int pagesize = 1 << ll->l2pagesize;
10337da2899SCharles.Forsyth 	LogSegment *seg;
10437da2899SCharles.Forsyth 
10537da2899SCharles.Forsyth 	if(nbytes > pagesize)
10637da2899SCharles.Forsyth 		return logfselogmsgtoobig;
10737da2899SCharles.Forsyth retry:
10837da2899SCharles.Forsyth 	seg = active ? server->activelog : server->sweptlog;
10937da2899SCharles.Forsyth 	for(;;) {
11037da2899SCharles.Forsyth //print("curpage %d nbytes %d\n", seg->curpage, seg->nbytes);
11137da2899SCharles.Forsyth 		if(seg->curpage >= 0) {
11237da2899SCharles.Forsyth 			if(seg->nbytes + nbytes < pagesize)
11337da2899SCharles.Forsyth 				break;
11437da2899SCharles.Forsyth 			errmsg = logfslogsegmentflush(server, active);
11537da2899SCharles.Forsyth 			if(errmsg)
11637da2899SCharles.Forsyth 				return errmsg;
11737da2899SCharles.Forsyth 		}
11837da2899SCharles.Forsyth 		if(seg->curpage < 0) {
11937da2899SCharles.Forsyth 			long block;
12037da2899SCharles.Forsyth 			long path;
12137da2899SCharles.Forsyth 			block = logfsfindfreeblock(ll,
12237da2899SCharles.Forsyth 				active ? (takearisk ? AllocReasonLogExtend : AllocReasonDataExtend) : AllocReasonTransfer);
12337da2899SCharles.Forsyth 			if(block < 0) {
12437da2899SCharles.Forsyth 				if(active) {
12537da2899SCharles.Forsyth 					int didsomething;
12637da2899SCharles.Forsyth 					errmsg = logfsserverlogsweep(server, 0, &didsomething);
12737da2899SCharles.Forsyth 					if(errmsg)
12837da2899SCharles.Forsyth 						return errmsg;
12937da2899SCharles.Forsyth 					if(didsomething)
13037da2899SCharles.Forsyth 						goto retry;
13137da2899SCharles.Forsyth 				}
13237da2899SCharles.Forsyth 				return logfselogfull;
13337da2899SCharles.Forsyth 			}
13437da2899SCharles.Forsyth 			seg->blockmap[++seg->curblockindex] = block;
13537da2899SCharles.Forsyth 			path = mklogpath(seg->curblockindex, seg->gen, 0);
13637da2899SCharles.Forsyth 			(*ll->setblocktag)(ll, block, LogfsTlog);
13737da2899SCharles.Forsyth 			(*ll->setblockpath)(ll, block, path);
13837da2899SCharles.Forsyth 			seg->curpage = 0;
13937da2899SCharles.Forsyth #ifdef FUTURE
14037da2899SCharles.Forsyth 			/* TODO - do we need one of these if the underlying system supports erase counting? */
14137da2899SCharles.Forsyth 			seg->pagebuf[0] = LogfsLogTstart;
14237da2899SCharles.Forsyth 			PBIT16(seg->pagebuf + 1, 8);
14337da2899SCharles.Forsyth 			PBIT32(seg->pagebuf + 3, path);	/* TODO duplicate information */
14437da2899SCharles.Forsyth 			PBIT32(seg->pagebuf + 7, 0);		/* TODO don't have this - discuss with forsyth */
14537da2899SCharles.Forsyth 			seg->nbytes = 11;
14637da2899SCharles.Forsyth #else
14737da2899SCharles.Forsyth 			seg->nbytes = 0;
14837da2899SCharles.Forsyth #endif
14937da2899SCharles.Forsyth 		}
15037da2899SCharles.Forsyth 	}
15137da2899SCharles.Forsyth 	*where = seg->pagebuf + seg->nbytes;
15237da2899SCharles.Forsyth 	if(flashaddr)
15337da2899SCharles.Forsyth 		*flashaddr = logfsspo2flashaddr(server, seg->curblockindex, seg->curpage, seg->nbytes);
15437da2899SCharles.Forsyth 	seg->nbytes += nbytes;
15537da2899SCharles.Forsyth 	return nil;
15637da2899SCharles.Forsyth }
15737da2899SCharles.Forsyth 
15837da2899SCharles.Forsyth static void
logdirty(LogfsServer * server,int active)15937da2899SCharles.Forsyth logdirty(LogfsServer *server, int active)
16037da2899SCharles.Forsyth {
16137da2899SCharles.Forsyth 	if(active)
16237da2899SCharles.Forsyth 		server->activelog->dirty = 1;
16337da2899SCharles.Forsyth 	else
16437da2899SCharles.Forsyth 		server->sweptlog->dirty = 1;
16537da2899SCharles.Forsyth }
16637da2899SCharles.Forsyth 
16737da2899SCharles.Forsyth char *
logfslogbytes(LogfsServer * server,int active,uchar * msg,uint size)16837da2899SCharles.Forsyth logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size)
16937da2899SCharles.Forsyth {
17037da2899SCharles.Forsyth 	char *errmsg;
17137da2899SCharles.Forsyth 	uchar *p;
17237da2899SCharles.Forsyth 
17337da2899SCharles.Forsyth 	errmsg = logspace(server, active, 0, size, &p, nil);
17437da2899SCharles.Forsyth 	if(errmsg)
17537da2899SCharles.Forsyth 		return errmsg;
176*28942eadSforsyth 	memmove(p, msg, size);
17737da2899SCharles.Forsyth 	logdirty(server, active);
17837da2899SCharles.Forsyth 	return nil;
17937da2899SCharles.Forsyth }
18037da2899SCharles.Forsyth 
18137da2899SCharles.Forsyth char *
logfslog(LogfsServer * server,int active,LogMessage * s)18237da2899SCharles.Forsyth logfslog(LogfsServer *server, int active, LogMessage *s)
18337da2899SCharles.Forsyth {
18437da2899SCharles.Forsyth 	uint size = logfssizeS2M(s);
18537da2899SCharles.Forsyth 	char *errmsg;
18637da2899SCharles.Forsyth 	uchar *p;
18737da2899SCharles.Forsyth 	int takearisk;
18837da2899SCharles.Forsyth 
18937da2899SCharles.Forsyth 	if(server->trace > 1) {
19037da2899SCharles.Forsyth 		print("%c<< ", active ? 'A' : 'S');
19137da2899SCharles.Forsyth 		logfsdumpS(s);
19237da2899SCharles.Forsyth 		print("\n");
19337da2899SCharles.Forsyth 	}
19437da2899SCharles.Forsyth 	if(active) {
19537da2899SCharles.Forsyth 		switch(s->type) {
19637da2899SCharles.Forsyth 		case LogfsLogTremove:
19737da2899SCharles.Forsyth 		case LogfsLogTtrunc:
19837da2899SCharles.Forsyth 			takearisk = 1;
19937da2899SCharles.Forsyth 			break;
20037da2899SCharles.Forsyth 		default:
20137da2899SCharles.Forsyth 			takearisk = 0;
20237da2899SCharles.Forsyth 		}
20337da2899SCharles.Forsyth 	}
20437da2899SCharles.Forsyth 	else
20537da2899SCharles.Forsyth 		takearisk = 0;
20637da2899SCharles.Forsyth 	errmsg = logspace(server, active, takearisk, size, &p, nil);
20737da2899SCharles.Forsyth 	if(errmsg)
20837da2899SCharles.Forsyth 		return errmsg;
20937da2899SCharles.Forsyth 	if(logfsconvS2M(s, p, size) != size)
21037da2899SCharles.Forsyth 		return "bad conversion";
21137da2899SCharles.Forsyth 	logdirty(server, active);
21237da2899SCharles.Forsyth 	return nil;
21337da2899SCharles.Forsyth }
21437da2899SCharles.Forsyth 
21537da2899SCharles.Forsyth int
lognicesizeforwrite(LogfsServer * server,int active,u32int count,int muidlen)21637da2899SCharles.Forsyth lognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen)
21737da2899SCharles.Forsyth {
21837da2899SCharles.Forsyth 	int rawspace;
21937da2899SCharles.Forsyth 	LogSegment *seg;
22037da2899SCharles.Forsyth 	if(count > LogDataLimit)
22137da2899SCharles.Forsyth 		return 0;
22237da2899SCharles.Forsyth 	seg = active ? server->activelog : server->sweptlog;
22337da2899SCharles.Forsyth 	if(seg->curpage < 0)
22437da2899SCharles.Forsyth 		return LogDataLimit;
22537da2899SCharles.Forsyth 	rawspace = (1 << server->ll->l2pagesize) - seg->nbytes;
22637da2899SCharles.Forsyth 	if(rawspace < 5 * 4 + 2 + muidlen + 1)
22737da2899SCharles.Forsyth 		return LogDataLimit;
22837da2899SCharles.Forsyth 	return 5 * 4 + 2 + muidlen - rawspace;
22937da2899SCharles.Forsyth }
23037da2899SCharles.Forsyth 
23137da2899SCharles.Forsyth char *
logfslogwrite(LogfsServer * server,int active,u32int path,u32int offset,int count,u32int mtime,u32int cvers,char * muid,uchar * data,u32int * flashaddr)23237da2899SCharles.Forsyth logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime, u32int cvers,
23337da2899SCharles.Forsyth 	char *muid, uchar *data, u32int *flashaddr)
23437da2899SCharles.Forsyth {
23537da2899SCharles.Forsyth 	/* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
23637da2899SCharles.Forsyth 	LogMessage s;
23737da2899SCharles.Forsyth 	uint size;
23837da2899SCharles.Forsyth 	char *errmsg;
23937da2899SCharles.Forsyth 	uchar *p;
24037da2899SCharles.Forsyth 	u32int faddr;
24137da2899SCharles.Forsyth 	uint asize;
24237da2899SCharles.Forsyth 
24337da2899SCharles.Forsyth 	s.type = LogfsLogTwrite;
24437da2899SCharles.Forsyth 	s.path = path;
24537da2899SCharles.Forsyth 	s.u.write.offset = offset;
24637da2899SCharles.Forsyth 	s.u.write.count = count;
24737da2899SCharles.Forsyth 	s.u.write.mtime = mtime;
24837da2899SCharles.Forsyth 	s.u.write.cvers = cvers;
24937da2899SCharles.Forsyth 	s.u.write.muid = muid;
25037da2899SCharles.Forsyth 	s.u.write.data = data;
25137da2899SCharles.Forsyth 	size = logfssizeS2M(&s);
25237da2899SCharles.Forsyth 	errmsg = logspace(server, active, 0, size, &p, &faddr);
25337da2899SCharles.Forsyth 	if(errmsg)
25437da2899SCharles.Forsyth 		return errmsg;
25537da2899SCharles.Forsyth 	if(data)
25637da2899SCharles.Forsyth 		*flashaddr = (faddr + size - count) | LogAddr;
25737da2899SCharles.Forsyth 	s.u.write.flashaddr = *flashaddr;
25837da2899SCharles.Forsyth 	if(server->trace > 1) {
25937da2899SCharles.Forsyth 		print("%c<< ", active ? 'A' : 'S');
26037da2899SCharles.Forsyth 		logfsdumpS(&s);
26137da2899SCharles.Forsyth 		print("\n");
26237da2899SCharles.Forsyth 	}
26337da2899SCharles.Forsyth 	if((asize = logfsconvS2M(&s, p, size)) != size) {
26437da2899SCharles.Forsyth 		print("expected %d actual %d\n", size, asize);
26537da2899SCharles.Forsyth 		return "bad conversion";
26637da2899SCharles.Forsyth 	}
26737da2899SCharles.Forsyth 	logdirty(server, active);
26837da2899SCharles.Forsyth 	return nil;
26937da2899SCharles.Forsyth }
27037da2899SCharles.Forsyth 
271