xref: /inferno-os/liblogfs/read.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 struct DirReadState {
737da2899SCharles.Forsyth 	u32int offset;
837da2899SCharles.Forsyth 	u32int lastoffset;
937da2899SCharles.Forsyth 	u32int limit;
1037da2899SCharles.Forsyth 	uchar *data;
1137da2899SCharles.Forsyth };
1237da2899SCharles.Forsyth 
1337da2899SCharles.Forsyth typedef struct ReaderState {
1437da2899SCharles.Forsyth 	uchar *buf;
1537da2899SCharles.Forsyth 	u32int maxoffset;
1637da2899SCharles.Forsyth 	LogfsServer *server;
1737da2899SCharles.Forsyth 	char *errmsg;
1837da2899SCharles.Forsyth } ReaderState;
1937da2899SCharles.Forsyth 
2037da2899SCharles.Forsyth static DirReadState *
drsinit(LogfsIdentityStore * is,Entry * list,uchar * buf,u32int buflen,u32int * rcount)2137da2899SCharles.Forsyth drsinit(LogfsIdentityStore *is, Entry *list, uchar *buf, u32int buflen, u32int *rcount)
2237da2899SCharles.Forsyth {
2337da2899SCharles.Forsyth 	Entry *p, *q;
2437da2899SCharles.Forsyth 	DirReadState *drs;
2537da2899SCharles.Forsyth 	u32int k;
2637da2899SCharles.Forsyth 	/*
2737da2899SCharles.Forsyth 	 * stash as many entries as will fit in the read buffer
2837da2899SCharles.Forsyth 	 */
2937da2899SCharles.Forsyth 	*rcount = 0;
3037da2899SCharles.Forsyth 	for(p = list; p; p = p->next) {
3137da2899SCharles.Forsyth 		uint len = logfsflattenentry(is, buf, buflen, p);
3237da2899SCharles.Forsyth 		if(len == 0)
3337da2899SCharles.Forsyth 			break;
3437da2899SCharles.Forsyth 		*rcount += len;
3537da2899SCharles.Forsyth 		buf += len;
3637da2899SCharles.Forsyth 		buflen -= len;
3737da2899SCharles.Forsyth 	}
3837da2899SCharles.Forsyth 	drs = logfsrealloc(nil, sizeof(*drs));
3937da2899SCharles.Forsyth 	if(drs == nil)
4037da2899SCharles.Forsyth 		return nil;
4137da2899SCharles.Forsyth 	drs->offset = *rcount;
4237da2899SCharles.Forsyth 	drs->lastoffset = drs->offset;
4337da2899SCharles.Forsyth 	k = 0;
4437da2899SCharles.Forsyth 	for(q = p; q; q = q->next)
4537da2899SCharles.Forsyth 		k += logfsflattenentry(is, nil, 0, q);
4637da2899SCharles.Forsyth 	if(k) {
4737da2899SCharles.Forsyth 		u32int k2;
4837da2899SCharles.Forsyth //		print("drsinit: %ud bytes extra\n", k);
4937da2899SCharles.Forsyth 		drs->data = logfsrealloc(nil, k);
5037da2899SCharles.Forsyth 		if(drs->data == nil) {
5137da2899SCharles.Forsyth 			logfsfreemem(drs);
5237da2899SCharles.Forsyth 			return nil;
5337da2899SCharles.Forsyth 		}
5437da2899SCharles.Forsyth 		k2 = 0;
5537da2899SCharles.Forsyth 		for(q = p; q; q = q->next)
5637da2899SCharles.Forsyth 			k2 += logfsflattenentry(is, drs->data + k2, k - k2, q);
5737da2899SCharles.Forsyth 		drs->limit = drs->offset + k;
5837da2899SCharles.Forsyth 	}
5937da2899SCharles.Forsyth //	print("drsinit: rcount %ud\n", *rcount);
6037da2899SCharles.Forsyth 	return drs;
6137da2899SCharles.Forsyth }
6237da2899SCharles.Forsyth 
6337da2899SCharles.Forsyth static void
drsread(DirReadState * drs,uchar * buf,u32int buflen,u32int * rcount)6437da2899SCharles.Forsyth drsread(DirReadState *drs, uchar *buf, u32int buflen, u32int *rcount)
6537da2899SCharles.Forsyth {
6637da2899SCharles.Forsyth 	uchar *p;
6737da2899SCharles.Forsyth 	*rcount = 0;
6837da2899SCharles.Forsyth 	p = drs->data + drs->lastoffset - drs->offset;
6937da2899SCharles.Forsyth 	while(drs->lastoffset < drs->limit) {
7037da2899SCharles.Forsyth 		/*
7137da2899SCharles.Forsyth 		 * copy an entry, if it fits
7237da2899SCharles.Forsyth 		 */
7337da2899SCharles.Forsyth 		uint len = GBIT16(p) + BIT16SZ;
7437da2899SCharles.Forsyth 		if(len > buflen)
7537da2899SCharles.Forsyth 			break;
76*28942eadSforsyth 		memmove(buf, p, len);
7737da2899SCharles.Forsyth 		drs->lastoffset += len;
7837da2899SCharles.Forsyth 		*rcount += len;
7937da2899SCharles.Forsyth 		buf += len;
8037da2899SCharles.Forsyth 		buflen -= len;
8137da2899SCharles.Forsyth 		p += len;
8237da2899SCharles.Forsyth 	}
8337da2899SCharles.Forsyth 	if(drs->lastoffset >= drs->limit) {
8437da2899SCharles.Forsyth 		logfsfreemem(drs->data);
8537da2899SCharles.Forsyth 		drs->data = nil;
8637da2899SCharles.Forsyth 	}
8737da2899SCharles.Forsyth }
8837da2899SCharles.Forsyth 
8937da2899SCharles.Forsyth void
logfsdrsfree(DirReadState ** drsp)9037da2899SCharles.Forsyth logfsdrsfree(DirReadState **drsp)
9137da2899SCharles.Forsyth {
9237da2899SCharles.Forsyth 	DirReadState *drs = *drsp;
9337da2899SCharles.Forsyth 	if(drs) {
9437da2899SCharles.Forsyth 		logfsfreemem(drs->data);
9537da2899SCharles.Forsyth 		logfsfreemem(drs);
9637da2899SCharles.Forsyth 		*drsp = nil;
9737da2899SCharles.Forsyth 	}
9837da2899SCharles.Forsyth }
9937da2899SCharles.Forsyth 
10037da2899SCharles.Forsyth static int
reader(void * magic,u32int baseoffset,u32int limitoffset,Extent * e,u32int extentoffset)10137da2899SCharles.Forsyth reader(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
10237da2899SCharles.Forsyth {
10337da2899SCharles.Forsyth 	ReaderState *s = magic;
10437da2899SCharles.Forsyth 	LogfsServer *server;
10537da2899SCharles.Forsyth 	LogfsLowLevel *ll;
10637da2899SCharles.Forsyth 	LogfsLowLevelReadResult llrr;
10737da2899SCharles.Forsyth 	long seq;
10837da2899SCharles.Forsyth 	int page;
10937da2899SCharles.Forsyth 	int offset;
11037da2899SCharles.Forsyth 	long block;
11137da2899SCharles.Forsyth 	int pagesize;
11237da2899SCharles.Forsyth 	LogSegment *seg;
11337da2899SCharles.Forsyth 	int replace;
11437da2899SCharles.Forsyth 
11537da2899SCharles.Forsyth 	if(e == nil) {
11637da2899SCharles.Forsyth //print("fill(%d, %d)\n", baseoffset, limitoffset);
11737da2899SCharles.Forsyth 		memset(s->buf + baseoffset, 0, limitoffset - baseoffset);
11837da2899SCharles.Forsyth 		if(limitoffset > s->maxoffset)
11937da2899SCharles.Forsyth 			s->maxoffset = limitoffset;
12037da2899SCharles.Forsyth 		return 1;
12137da2899SCharles.Forsyth 	}
12237da2899SCharles.Forsyth 	server = s->server;
12337da2899SCharles.Forsyth 	ll = server->ll;
12437da2899SCharles.Forsyth 	/*
12537da2899SCharles.Forsyth 	 * extentoffset is how much to trim off the front of the extent
12637da2899SCharles.Forsyth 	 */
12737da2899SCharles.Forsyth 	logfsflashaddr2spo(server, e->flashaddr + extentoffset, &seq, &page, &offset);
12837da2899SCharles.Forsyth 	/*
12937da2899SCharles.Forsyth 	 * offset is the offset within the page to where e->min is stored
13037da2899SCharles.Forsyth 	 */
13137da2899SCharles.Forsyth //print("read(%d, %d, %c%ld/%ud/%ud)\n",
13237da2899SCharles.Forsyth //	baseoffset, limitoffset, (e->flashaddr & LogAddr) ? 'L' :  'D', seq, page, offset);
13337da2899SCharles.Forsyth 	if(e->flashaddr & LogAddr) {
13437da2899SCharles.Forsyth 		if(seq >= server->activelog->unsweptblockindex && seq <= server->activelog->curblockindex)
13537da2899SCharles.Forsyth 			seg = server->activelog;
13637da2899SCharles.Forsyth 		else if(server->sweptlog && seq <= server->sweptlog->curblockindex)
13737da2899SCharles.Forsyth 			seg = server->sweptlog;
13837da2899SCharles.Forsyth 		else {
13937da2899SCharles.Forsyth 			print("logfsserverread: illegal log sequence number %ld (active=[%ld, %ld], swept=[%ld, %ld])\n",
14037da2899SCharles.Forsyth 				seq, server->activelog->unsweptblockindex, server->activelog->curblockindex,
14137da2899SCharles.Forsyth 				server->sweptlog ? 0L : -1L, server->sweptlog ? server->sweptlog->curblockindex : -1L);
14237da2899SCharles.Forsyth 			s->errmsg = logfseinternal;
14337da2899SCharles.Forsyth 			return -1;
14437da2899SCharles.Forsyth 		}
14537da2899SCharles.Forsyth 		if(seg->curpage == page && seg->curblockindex == seq) {
14637da2899SCharles.Forsyth 			/*
14737da2899SCharles.Forsyth 			 * it hasn't made it to disk yet
14837da2899SCharles.Forsyth 			 */
149*28942eadSforsyth 			memmove(s->buf + baseoffset, seg->pagebuf + offset, limitoffset - baseoffset);
15037da2899SCharles.Forsyth 			goto done;
15137da2899SCharles.Forsyth 		}
15237da2899SCharles.Forsyth 		if(seq < seg->unsweptblockindex) {
15337da2899SCharles.Forsyth 			/* data already swept */
15437da2899SCharles.Forsyth 			print("logfsserverread: log address has been swept\n");
15537da2899SCharles.Forsyth 			s->errmsg = logfseinternal;
15637da2899SCharles.Forsyth 			return -1;
15737da2899SCharles.Forsyth 		}
15837da2899SCharles.Forsyth 		block = seg->blockmap[seq];
15937da2899SCharles.Forsyth 	}
16037da2899SCharles.Forsyth 	else {
16137da2899SCharles.Forsyth 		seg = nil;
16237da2899SCharles.Forsyth 		if(seq >= server->ndatablocks)
16337da2899SCharles.Forsyth 			block = -1;
16437da2899SCharles.Forsyth 		else
16537da2899SCharles.Forsyth 			block = server->datablock[seq].block;
16637da2899SCharles.Forsyth 		if(block < 0) {
16737da2899SCharles.Forsyth 			print("logfsserveread: data address does not exist\n");
16837da2899SCharles.Forsyth 			s->errmsg = logfseinternal;
16937da2899SCharles.Forsyth 			return -1;
17037da2899SCharles.Forsyth 		}
17137da2899SCharles.Forsyth 	}
17237da2899SCharles.Forsyth 	/*
17337da2899SCharles.Forsyth 	 * read as many pages as necessary to get to the limitoffset
17437da2899SCharles.Forsyth 	 */
17537da2899SCharles.Forsyth 	pagesize = 1 << ll->l2pagesize;
17637da2899SCharles.Forsyth 	replace = 0;
17737da2899SCharles.Forsyth 	while(baseoffset < limitoffset) {
17837da2899SCharles.Forsyth 		u32int thistime;
17937da2899SCharles.Forsyth 		thistime = pagesize - offset;
18037da2899SCharles.Forsyth 		if(thistime > (limitoffset - baseoffset))
18137da2899SCharles.Forsyth 			thistime = limitoffset - baseoffset;
18237da2899SCharles.Forsyth 		s->errmsg = (*ll->readpagerange)(ll, s->buf + baseoffset, block, page,
18337da2899SCharles.Forsyth 			offset, thistime, &llrr);
18437da2899SCharles.Forsyth 		if(s->errmsg)
18537da2899SCharles.Forsyth 			return -1;
18637da2899SCharles.Forsyth 		if(llrr != LogfsLowLevelReadResultOk) {
18737da2899SCharles.Forsyth 			replace = 1;
18837da2899SCharles.Forsyth 		}
18937da2899SCharles.Forsyth 		baseoffset += thistime;
19037da2899SCharles.Forsyth 		page++;
19137da2899SCharles.Forsyth 		offset = 0;
19237da2899SCharles.Forsyth 	}
19337da2899SCharles.Forsyth 	if(replace) {
19437da2899SCharles.Forsyth 		s->errmsg = logfsserverreplaceblock(server, seg, seq);
19537da2899SCharles.Forsyth 		if(s->errmsg)
19637da2899SCharles.Forsyth 			return -1;
19737da2899SCharles.Forsyth 	}
19837da2899SCharles.Forsyth done:
19937da2899SCharles.Forsyth 	if(limitoffset > s->maxoffset)
20037da2899SCharles.Forsyth 		s->maxoffset = limitoffset;
20137da2899SCharles.Forsyth 	return 1;
20237da2899SCharles.Forsyth }
20337da2899SCharles.Forsyth 
20437da2899SCharles.Forsyth char *
logfsserverread(LogfsServer * server,u32int fid,u32int offset,u32int count,uchar * buf,u32int buflen,u32int * rcount)20537da2899SCharles.Forsyth logfsserverread(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int buflen, u32int *rcount)
20637da2899SCharles.Forsyth {
20737da2899SCharles.Forsyth 	Fid *f;
20837da2899SCharles.Forsyth 	Entry *e;
20937da2899SCharles.Forsyth 	ReaderState s;
21037da2899SCharles.Forsyth 	int rv;
21137da2899SCharles.Forsyth 
21237da2899SCharles.Forsyth 	if(server->trace > 1)
21337da2899SCharles.Forsyth 		print("logfsserverread(%ud, %ud, %ud)\n", fid, offset, count);
21437da2899SCharles.Forsyth 	f = logfsfidmapfindentry(server->fidmap, fid);
21537da2899SCharles.Forsyth 	if(f == nil)
21637da2899SCharles.Forsyth 		return logfsebadfid;
21737da2899SCharles.Forsyth 	if(f->openmode < 0)
21837da2899SCharles.Forsyth 		return logfsefidnotopen;
21937da2899SCharles.Forsyth 	if((f->openmode & 3) == OWRITE)
22037da2899SCharles.Forsyth 		return logfseaccess;
22137da2899SCharles.Forsyth 	if(count > buflen)
22237da2899SCharles.Forsyth 		return Etoobig;
22337da2899SCharles.Forsyth 	e = f->entry;
22437da2899SCharles.Forsyth 	if(e->deadandgone)
22537da2899SCharles.Forsyth 		return Eio;
22637da2899SCharles.Forsyth 	if(e->qid.type & QTDIR) {
22737da2899SCharles.Forsyth 		if(offset != 0) {
22837da2899SCharles.Forsyth 			if(f->drs == nil || f->drs->lastoffset != offset)
22937da2899SCharles.Forsyth 				return Eio;
23037da2899SCharles.Forsyth 			drsread(f->drs, buf, count, rcount);
23137da2899SCharles.Forsyth 		}
23237da2899SCharles.Forsyth 		else {
23337da2899SCharles.Forsyth 			logfsdrsfree(&f->drs);
23437da2899SCharles.Forsyth 			f->drs = drsinit(server->is, e->u.dir.list, buf, count, rcount);
23537da2899SCharles.Forsyth 			if(f->drs == nil)
23637da2899SCharles.Forsyth 				return Enomem;
23737da2899SCharles.Forsyth 		}
23837da2899SCharles.Forsyth 		return nil;
23937da2899SCharles.Forsyth 	}
24037da2899SCharles.Forsyth 	if(offset >= e->u.file.length) {
24137da2899SCharles.Forsyth 		*rcount = 0;
24237da2899SCharles.Forsyth 		return nil;
24337da2899SCharles.Forsyth 	}
24437da2899SCharles.Forsyth 	s.buf = buf;
24537da2899SCharles.Forsyth 	s.server = server;
24637da2899SCharles.Forsyth 	s.maxoffset = 0;
24737da2899SCharles.Forsyth 	rv = logfsextentlistwalkrange(e->u.file.extent, reader, &s, offset, offset + count);
24837da2899SCharles.Forsyth 	if(rv < 0)
24937da2899SCharles.Forsyth 		return s.errmsg;
25037da2899SCharles.Forsyth 	*rcount = s.maxoffset;
25137da2899SCharles.Forsyth 	return nil;
25237da2899SCharles.Forsyth }
25337da2899SCharles.Forsyth 
254