17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * Buffered I/O on block devices.
37dd7cddfSDavid du Colombier * Write buffering ignores offset.
47dd7cddfSDavid du Colombier */
57dd7cddfSDavid du Colombier
67dd7cddfSDavid du Colombier #include <u.h>
77dd7cddfSDavid du Colombier #include <libc.h>
87dd7cddfSDavid du Colombier #include <disk.h>
97dd7cddfSDavid du Colombier #include "dat.h"
107dd7cddfSDavid du Colombier #include "fns.h"
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier Buf*
bopen(long (* fn)(Buf *,void *,long,ulong),int omode,int bs,int nblock)13dd12a5c6SDavid du Colombier bopen(long (*fn)(Buf*, void*, long, ulong), int omode, int bs, int nblock)
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier Buf *b;
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier assert(omode == OREAD || OWRITE);
187dd7cddfSDavid du Colombier assert(bs > 0 && nblock > 0);
197dd7cddfSDavid du Colombier assert(fn != nil);
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier b = emalloc(sizeof(*b));
227dd7cddfSDavid du Colombier b->data = emalloc(bs*nblock);
237dd7cddfSDavid du Colombier b->ndata = 0;
247dd7cddfSDavid du Colombier b->nblock = nblock;
257dd7cddfSDavid du Colombier b->bs = bs;
267dd7cddfSDavid du Colombier b->omode = omode;
27dd12a5c6SDavid du Colombier b->fn = fn; /* function to read or write bs-byte blocks */
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier return b;
307dd7cddfSDavid du Colombier }
317dd7cddfSDavid du Colombier
327dd7cddfSDavid du Colombier long
bread(Buf * b,void * v,long n,vlong off)33dd12a5c6SDavid du Colombier bread(Buf *b, void *v, long n, vlong off)
347dd7cddfSDavid du Colombier {
35dd12a5c6SDavid du Colombier long m;
36dd12a5c6SDavid du Colombier vlong noff;
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier assert(b->omode == OREAD);
397dd7cddfSDavid du Colombier
407dd7cddfSDavid du Colombier /* Refill buffer */
417dd7cddfSDavid du Colombier if(b->off > off || off >= b->off+b->ndata) {
427dd7cddfSDavid du Colombier noff = off - off % b->bs;
43*f80c7c99SDavid du Colombier if(vflag > 1)
44dd12a5c6SDavid du Colombier fprint(2, "try refill at %lld...", noff);
45dd12a5c6SDavid du Colombier if((m = b->fn(b, b->data, b->nblock, noff/b->bs)) <= 0) {
46dd12a5c6SDavid du Colombier if (vflag)
47*f80c7c99SDavid du Colombier fprint(2, "read failed: %r\n");
4859cc4ca5SDavid du Colombier return m;
49dd12a5c6SDavid du Colombier }
507dd7cddfSDavid du Colombier b->ndata = b->bs * m;
517dd7cddfSDavid du Colombier b->off = noff;
52*f80c7c99SDavid du Colombier if(vflag > 1)
53dd12a5c6SDavid du Colombier fprint(2, "got %ld\n", b->ndata);
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier
5614414594SDavid du Colombier // fprint(2, "read %ld at %ld\n", n, off);
577dd7cddfSDavid du Colombier /* Satisfy request from buffer */
587dd7cddfSDavid du Colombier off -= b->off;
597dd7cddfSDavid du Colombier if(n > b->ndata - off)
607dd7cddfSDavid du Colombier n = b->ndata - off;
617dd7cddfSDavid du Colombier memmove(v, b->data+off, n);
627dd7cddfSDavid du Colombier return n;
637dd7cddfSDavid du Colombier }
647dd7cddfSDavid du Colombier
657dd7cddfSDavid du Colombier long
bwrite(Buf * b,void * v,long n)667dd7cddfSDavid du Colombier bwrite(Buf *b, void *v, long n)
677dd7cddfSDavid du Colombier {
687dd7cddfSDavid du Colombier long on, m, mdata;
697dd7cddfSDavid du Colombier uchar *p;
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier p = v;
727dd7cddfSDavid du Colombier on = n;
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier /* Fill buffer */
757dd7cddfSDavid du Colombier mdata = b->bs*b->nblock;
767dd7cddfSDavid du Colombier m = mdata - b->ndata;
777dd7cddfSDavid du Colombier if(m > n)
787dd7cddfSDavid du Colombier m = n;
797dd7cddfSDavid du Colombier memmove(b->data+b->ndata, p, m);
807dd7cddfSDavid du Colombier p += m;
817dd7cddfSDavid du Colombier n -= m;
827dd7cddfSDavid du Colombier b->ndata += m;
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier /* Flush buffer */
857dd7cddfSDavid du Colombier if(b->ndata == mdata) {
867dd7cddfSDavid du Colombier if(b->fn(b, b->data, b->nblock, 0) < 0) {
877dd7cddfSDavid du Colombier if(vflag)
887dd7cddfSDavid du Colombier fprint(2, "write fails: %r\n");
897dd7cddfSDavid du Colombier return -1;
907dd7cddfSDavid du Colombier }
917dd7cddfSDavid du Colombier b->ndata = 0;
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier /* For now, don't worry about big writes; 9P only does 8k */
957dd7cddfSDavid du Colombier assert(n < mdata);
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier /* Add remainder to buffer */
987dd7cddfSDavid du Colombier if(n) {
997dd7cddfSDavid du Colombier memmove(b->data, p, n);
1007dd7cddfSDavid du Colombier b->ndata = n;
1017dd7cddfSDavid du Colombier }
1027dd7cddfSDavid du Colombier
1037dd7cddfSDavid du Colombier return on;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier void
bterm(Buf * b)1077dd7cddfSDavid du Colombier bterm(Buf *b)
1087dd7cddfSDavid du Colombier {
109436f307dSDavid du Colombier /* DVD & BD prefer full ecc blocks (tracks), but can cope with less */
1107dd7cddfSDavid du Colombier if(b->omode == OWRITE && b->ndata)
111dd12a5c6SDavid du Colombier b->fn(b, b->data, (b->ndata + b->bs - 1)/b->bs, 0);
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier free(b->data);
1147dd7cddfSDavid du Colombier free(b);
1157dd7cddfSDavid du Colombier }
116