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* 137dd7cddfSDavid du Colombier bopen(long (*fn)(Buf*, void*, long, long), 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; 277dd7cddfSDavid du Colombier b->fn = fn; 287dd7cddfSDavid du Colombier 297dd7cddfSDavid du Colombier return b; 307dd7cddfSDavid du Colombier } 317dd7cddfSDavid du Colombier 327dd7cddfSDavid du Colombier long 337dd7cddfSDavid du Colombier bread(Buf *b, void *v, long n, long off) 347dd7cddfSDavid du Colombier { 357dd7cddfSDavid du Colombier long m, noff; 367dd7cddfSDavid du Colombier 377dd7cddfSDavid du Colombier assert(b->omode == OREAD); 387dd7cddfSDavid du Colombier 397dd7cddfSDavid du Colombier /* Refill buffer */ 407dd7cddfSDavid du Colombier if(b->off > off || off >= b->off+b->ndata) { 417dd7cddfSDavid du Colombier noff = off - off % b->bs; 427dd7cddfSDavid du Colombier if(vflag) 437dd7cddfSDavid du Colombier fprint(2, "try refill at %ld\n", noff); 447dd7cddfSDavid du Colombier if((m = b->fn(b, b->data, Nblock, noff/b->bs)) <= 0) 457dd7cddfSDavid du Colombier return -1; 467dd7cddfSDavid du Colombier b->ndata = b->bs * m; 477dd7cddfSDavid du Colombier b->off = noff; 487dd7cddfSDavid du Colombier if(vflag) 497dd7cddfSDavid du Colombier fprint(2, "refill %ld at %ld\n", b->ndata, b->off); 507dd7cddfSDavid du Colombier } 517dd7cddfSDavid du Colombier 52*14414594SDavid du Colombier // fprint(2, "read %ld at %ld\n", n, off); 537dd7cddfSDavid du Colombier /* Satisfy request from buffer */ 547dd7cddfSDavid du Colombier off -= b->off; 557dd7cddfSDavid du Colombier if(n > b->ndata - off) 567dd7cddfSDavid du Colombier n = b->ndata - off; 577dd7cddfSDavid du Colombier memmove(v, b->data+off, n); 587dd7cddfSDavid du Colombier return n; 597dd7cddfSDavid du Colombier } 607dd7cddfSDavid du Colombier 617dd7cddfSDavid du Colombier long 627dd7cddfSDavid du Colombier bwrite(Buf *b, void *v, long n) 637dd7cddfSDavid du Colombier { 647dd7cddfSDavid du Colombier long on, m, mdata; 657dd7cddfSDavid du Colombier uchar *p; 667dd7cddfSDavid du Colombier 677dd7cddfSDavid du Colombier p = v; 687dd7cddfSDavid du Colombier on = n; 697dd7cddfSDavid du Colombier 707dd7cddfSDavid du Colombier /* Fill buffer */ 717dd7cddfSDavid du Colombier mdata = b->bs*b->nblock; 727dd7cddfSDavid du Colombier m = mdata - b->ndata; 737dd7cddfSDavid du Colombier if(m > n) 747dd7cddfSDavid du Colombier m = n; 757dd7cddfSDavid du Colombier memmove(b->data+b->ndata, p, m); 767dd7cddfSDavid du Colombier p += m; 777dd7cddfSDavid du Colombier n -= m; 787dd7cddfSDavid du Colombier b->ndata += m; 797dd7cddfSDavid du Colombier 807dd7cddfSDavid du Colombier /* Flush buffer */ 817dd7cddfSDavid du Colombier if(b->ndata == mdata) { 827dd7cddfSDavid du Colombier if(b->fn(b, b->data, b->nblock, 0) < 0) { 837dd7cddfSDavid du Colombier if(vflag) 847dd7cddfSDavid du Colombier fprint(2, "write fails: %r\n"); 857dd7cddfSDavid du Colombier return -1; 867dd7cddfSDavid du Colombier } 877dd7cddfSDavid du Colombier b->ndata = 0; 887dd7cddfSDavid du Colombier } 897dd7cddfSDavid du Colombier 907dd7cddfSDavid du Colombier /* For now, don't worry about big writes; 9P only does 8k */ 917dd7cddfSDavid du Colombier assert(n < mdata); 927dd7cddfSDavid du Colombier 937dd7cddfSDavid du Colombier /* Add remainder to buffer */ 947dd7cddfSDavid du Colombier if(n) { 957dd7cddfSDavid du Colombier memmove(b->data, p, n); 967dd7cddfSDavid du Colombier b->ndata = n; 977dd7cddfSDavid du Colombier } 987dd7cddfSDavid du Colombier 997dd7cddfSDavid du Colombier return on; 1007dd7cddfSDavid du Colombier } 1017dd7cddfSDavid du Colombier 1027dd7cddfSDavid du Colombier void 1037dd7cddfSDavid du Colombier bterm(Buf *b) 1047dd7cddfSDavid du Colombier { 1057dd7cddfSDavid du Colombier if(b->omode == OWRITE && b->ndata) 1067dd7cddfSDavid du Colombier b->fn(b, b->data, (b->ndata+b->bs-1)/b->bs, b->off); 1077dd7cddfSDavid du Colombier 1087dd7cddfSDavid du Colombier free(b->data); 1097dd7cddfSDavid du Colombier free(b); 1107dd7cddfSDavid du Colombier } 111