123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /*
- * Buffered I/O on block devices.
- * Write buffering ignores offset.
- */
- #include <u.h>
- #include <libc.h>
- #include <disk.h>
- #include "dat.h"
- #include "fns.h"
- Buf*
- bopen(long (*fn)(Buf*, void*, long, ulong), int omode, int bs, int nblock)
- {
- Buf *b;
- assert(omode == OREAD || OWRITE);
- assert(bs > 0 && nblock > 0);
- assert(fn != nil);
- b = emalloc(sizeof(*b));
- b->data = emalloc(bs*nblock);
- b->ndata = 0;
- b->nblock = nblock;
- b->bs = bs;
- b->omode = omode;
- b->fn = fn; /* function to read or write bs-byte blocks */
- return b;
- }
- long
- bread(Buf *b, void *v, long n, vlong off)
- {
- long m;
- vlong noff;
- assert(b->omode == OREAD);
- /* Refill buffer */
- if(b->off > off || off >= b->off+b->ndata) {
- noff = off - off % b->bs;
- if(vflag > 1)
- fprint(2, "try refill at %lld...", noff);
- if((m = b->fn(b, b->data, b->nblock, noff/b->bs)) <= 0) {
- if (vflag)
- fprint(2, "read failed: %r\n");
- return m;
- }
- b->ndata = b->bs * m;
- b->off = noff;
- if(vflag > 1)
- fprint(2, "got %ld\n", b->ndata);
- }
- // fprint(2, "read %ld at %ld\n", n, off);
- /* Satisfy request from buffer */
- off -= b->off;
- if(n > b->ndata - off)
- n = b->ndata - off;
- memmove(v, b->data+off, n);
- return n;
- }
- long
- bwrite(Buf *b, void *v, long n)
- {
- long on, m, mdata;
- uchar *p;
- p = v;
- on = n;
- /* Fill buffer */
- mdata = b->bs*b->nblock;
- m = mdata - b->ndata;
- if(m > n)
- m = n;
- memmove(b->data+b->ndata, p, m);
- p += m;
- n -= m;
- b->ndata += m;
- /* Flush buffer */
- if(b->ndata == mdata) {
- if(b->fn(b, b->data, b->nblock, 0) < 0) {
- if(vflag)
- fprint(2, "write fails: %r\n");
- return -1;
- }
- b->ndata = 0;
- }
- /* For now, don't worry about big writes; 9P only does 8k */
- assert(n < mdata);
- /* Add remainder to buffer */
- if(n) {
- memmove(b->data, p, n);
- b->ndata = n;
- }
- return on;
- }
- void
- bterm(Buf *b)
- {
- /* DVD & BD prefer full ecc blocks (tracks), but can cope with less */
- if(b->omode == OWRITE && b->ndata)
- b->fn(b, b->data, (b->ndata + b->bs - 1)/b->bs, 0);
- free(b->data);
- free(b);
- }
|