xref: /inferno-os/liblogfs/log.c (revision 48f27553574bf59de5f101ae072f82f5f1993d6f)
1  #include "logfsos.h"
2  #include "logfs.h"
3  #include "local.h"
4  #include "fcall.h"
5  
6  void
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
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
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 *
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
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 *
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 *
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
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 *
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 *
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
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 *
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