xref: /plan9-contrib/sys/src/cmd/cdfs/buf.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
1 /*
2  * Buffered I/O on block devices.
3  * Write buffering ignores offset.
4  */
5 
6 #include <u.h>
7 #include <libc.h>
8 #include <disk.h>
9 #include "dat.h"
10 #include "fns.h"
11 
12 Buf*
13 bopen(long (*fn)(Buf*, void*, long, long), int omode, int bs, int nblock)
14 {
15 	Buf *b;
16 
17 	assert(omode == OREAD || OWRITE);
18 	assert(bs > 0 && nblock > 0);
19 	assert(fn != nil);
20 
21 	b = emalloc(sizeof(*b));
22 	b->data = emalloc(bs*nblock);
23 	b->ndata = 0;
24 	b->nblock = nblock;
25 	b->bs = bs;
26 	b->omode = omode;
27 	b->fn = fn;
28 
29 	return b;
30 }
31 
32 long
33 bread(Buf *b, void *v, long n, long off)
34 {
35 	long m, noff;
36 
37 	assert(b->omode == OREAD);
38 
39 	/* Refill buffer */
40 	if(b->off > off || off >= b->off+b->ndata) {
41 		noff = off - off % b->bs;
42 		if(vflag)
43 			fprint(2, "try refill at %ld\n", noff);
44 		if((m = b->fn(b, b->data, Nblock, noff/b->bs)) <= 0)
45 			return m;
46 		b->ndata = b->bs * m;
47 		b->off = noff;
48 		if(vflag)
49 			fprint(2, "refill %ld at %ld\n", b->ndata, b->off);
50 	}
51 
52 //	fprint(2, "read %ld at %ld\n", n, off);
53 	/* Satisfy request from buffer */
54 	off -= b->off;
55 	if(n > b->ndata - off)
56 		n = b->ndata - off;
57 	memmove(v, b->data+off, n);
58 	return n;
59 }
60 
61 long
62 bwrite(Buf *b, void *v, long n)
63 {
64 	long on, m, mdata;
65 	uchar *p;
66 
67 	p = v;
68 	on = n;
69 
70 	/* Fill buffer */
71 	mdata = b->bs*b->nblock;
72 	m = mdata - b->ndata;
73 	if(m > n)
74 		m = n;
75 	memmove(b->data+b->ndata, p, m);
76 	p += m;
77 	n -= m;
78 	b->ndata += m;
79 
80 	/* Flush buffer */
81 	if(b->ndata == mdata) {
82 		if(b->fn(b, b->data, b->nblock, 0) < 0) {
83 			if(vflag)
84 				fprint(2, "write fails: %r\n");
85 			return -1;
86 		}
87 		b->ndata = 0;
88 	}
89 
90 	/* For now, don't worry about big writes; 9P only does 8k */
91 	assert(n < mdata);
92 
93 	/* Add remainder to buffer */
94 	if(n) {
95 		memmove(b->data, p, n);
96 		b->ndata = n;
97 	}
98 
99 	return on;
100 }
101 
102 void
103 bterm(Buf *b)
104 {
105 	if(b->omode == OWRITE && b->ndata)
106 		b->fn(b, b->data, (b->ndata+b->bs-1)/b->bs, b->off);
107 
108 	free(b->data);
109 	free(b);
110 }
111