1*3e12c5d1SDavid du Colombier #include <u.h> 2*3e12c5d1SDavid du Colombier #include <libc.h> 3*3e12c5d1SDavid du Colombier #include "cformat.h" 4*3e12c5d1SDavid du Colombier #include "lru.h" 5*3e12c5d1SDavid du Colombier #include "bcache.h" 6*3e12c5d1SDavid du Colombier #include "disk.h" 7*3e12c5d1SDavid du Colombier #include "inode.h" 8*3e12c5d1SDavid du Colombier #include "file.h" 9*3e12c5d1SDavid du Colombier 10*3e12c5d1SDavid du Colombier /* 11*3e12c5d1SDavid du Colombier * merge data with that which already exists in a block 12*3e12c5d1SDavid du Colombier * 13*3e12c5d1SDavid du Colombier * we allow only one range per block, always use the new 14*3e12c5d1SDavid du Colombier * data if the ranges don't overlap. 15*3e12c5d1SDavid du Colombier */ 16*3e12c5d1SDavid du Colombier void 17*3e12c5d1SDavid du Colombier fmerge(Dptr *p, char *to, char *from, int start, int len) 18*3e12c5d1SDavid du Colombier { 19*3e12c5d1SDavid du Colombier int end; 20*3e12c5d1SDavid du Colombier 21*3e12c5d1SDavid du Colombier end = start + len; 22*3e12c5d1SDavid du Colombier memmove(to+start, from, end-start); 23*3e12c5d1SDavid du Colombier 24*3e12c5d1SDavid du Colombier /* 25*3e12c5d1SDavid du Colombier * if ranges do not overlap... 26*3e12c5d1SDavid du Colombier */ 27*3e12c5d1SDavid du Colombier if(start>p->end || p->start>end){ 28*3e12c5d1SDavid du Colombier /* 29*3e12c5d1SDavid du Colombier * just use the new data 30*3e12c5d1SDavid du Colombier */ 31*3e12c5d1SDavid du Colombier p->start = start; 32*3e12c5d1SDavid du Colombier p->end = end; 33*3e12c5d1SDavid du Colombier } else { 34*3e12c5d1SDavid du Colombier /* 35*3e12c5d1SDavid du Colombier * merge ranges 36*3e12c5d1SDavid du Colombier */ 37*3e12c5d1SDavid du Colombier if(start < p->start) 38*3e12c5d1SDavid du Colombier p->start = start; 39*3e12c5d1SDavid du Colombier if(end > p->end) 40*3e12c5d1SDavid du Colombier p->end = end; 41*3e12c5d1SDavid du Colombier } 42*3e12c5d1SDavid du Colombier 43*3e12c5d1SDavid du Colombier } 44*3e12c5d1SDavid du Colombier 45*3e12c5d1SDavid du Colombier /* 46*3e12c5d1SDavid du Colombier * write a block (or less) of data onto a disk, follow it with any necessary 47*3e12c5d1SDavid du Colombier * pointer writes. 48*3e12c5d1SDavid du Colombier * 49*3e12c5d1SDavid du Colombier * N.B. ordering is everything 50*3e12c5d1SDavid du Colombier */ 51*3e12c5d1SDavid du Colombier int 52*3e12c5d1SDavid du Colombier fbwrite(Icache *ic, Ibuf *b, char *a, ulong off, int len) 53*3e12c5d1SDavid du Colombier { 54*3e12c5d1SDavid du Colombier Bbuf *dbb; /* data block */ 55*3e12c5d1SDavid du Colombier Bbuf *ibb; /* indirect block */ 56*3e12c5d1SDavid du Colombier Dptr *p; 57*3e12c5d1SDavid du Colombier Dptr t; 58*3e12c5d1SDavid du Colombier ulong fbno; 59*3e12c5d1SDavid du Colombier int wrinode; 60*3e12c5d1SDavid du Colombier 61*3e12c5d1SDavid du Colombier fbno = off / ic->bsize; 62*3e12c5d1SDavid du Colombier p = &b->inode.ptr; 63*3e12c5d1SDavid du Colombier ibb = 0; 64*3e12c5d1SDavid du Colombier wrinode = 0; 65*3e12c5d1SDavid du Colombier 66*3e12c5d1SDavid du Colombier /* 67*3e12c5d1SDavid du Colombier * are there any pages for this inode? 68*3e12c5d1SDavid du Colombier */ 69*3e12c5d1SDavid du Colombier if(p->bno == Notabno){ 70*3e12c5d1SDavid du Colombier wrinode = 1; 71*3e12c5d1SDavid du Colombier goto dowrite; 72*3e12c5d1SDavid du Colombier } 73*3e12c5d1SDavid du Colombier 74*3e12c5d1SDavid du Colombier /* 75*3e12c5d1SDavid du Colombier * is it an indirect block? 76*3e12c5d1SDavid du Colombier */ 77*3e12c5d1SDavid du Colombier if(p->bno & Indbno){ 78*3e12c5d1SDavid du Colombier ibb = bcread(ic, p->bno); 79*3e12c5d1SDavid du Colombier if(ibb == 0) 80*3e12c5d1SDavid du Colombier return -1; 81*3e12c5d1SDavid du Colombier p = (Dptr*)ibb->data; 82*3e12c5d1SDavid du Colombier p += fbno % ic->p2b; 83*3e12c5d1SDavid du Colombier goto dowrite; 84*3e12c5d1SDavid du Colombier } 85*3e12c5d1SDavid du Colombier 86*3e12c5d1SDavid du Colombier /* 87*3e12c5d1SDavid du Colombier * is it the wrong direct block? 88*3e12c5d1SDavid du Colombier */ 89*3e12c5d1SDavid du Colombier if((p->fbno%ic->p2b) != (fbno%ic->p2b)){ 90*3e12c5d1SDavid du Colombier /* 91*3e12c5d1SDavid du Colombier * yes, make an indirect block 92*3e12c5d1SDavid du Colombier */ 93*3e12c5d1SDavid du Colombier t = *p; 94*3e12c5d1SDavid du Colombier dpalloc(ic, p); 95*3e12c5d1SDavid du Colombier if(p->bno == Notabno){ 96*3e12c5d1SDavid du Colombier *p = t; 97*3e12c5d1SDavid du Colombier return -1; 98*3e12c5d1SDavid du Colombier } 99*3e12c5d1SDavid du Colombier ibb = bcalloc(ic, p->bno); 100*3e12c5d1SDavid du Colombier if(ibb == 0){ 101*3e12c5d1SDavid du Colombier *p = t; 102*3e12c5d1SDavid du Colombier return -1; 103*3e12c5d1SDavid du Colombier } 104*3e12c5d1SDavid du Colombier p = (Dptr*)ibb->data; 105*3e12c5d1SDavid du Colombier p += t.fbno % ic->p2b; 106*3e12c5d1SDavid du Colombier *p = t; 107*3e12c5d1SDavid du Colombier p = (Dptr*)ibb->data; 108*3e12c5d1SDavid du Colombier p += fbno % ic->p2b; 109*3e12c5d1SDavid du Colombier } 110*3e12c5d1SDavid du Colombier wrinode = 1; 111*3e12c5d1SDavid du Colombier 112*3e12c5d1SDavid du Colombier dowrite: 113*3e12c5d1SDavid du Colombier /* 114*3e12c5d1SDavid du Colombier * get the data block into the block cache 115*3e12c5d1SDavid du Colombier */ 116*3e12c5d1SDavid du Colombier if(p->bno == Notabno){ 117*3e12c5d1SDavid du Colombier /* 118*3e12c5d1SDavid du Colombier * create a new block 119*3e12c5d1SDavid du Colombier */ 120*3e12c5d1SDavid du Colombier dalloc(ic, p); 121*3e12c5d1SDavid du Colombier if(p->bno == Notabno) 122*3e12c5d1SDavid du Colombier return -1; /* no blocks left (maybe) */ 123*3e12c5d1SDavid du Colombier dbb = bcalloc(ic, p->bno); 124*3e12c5d1SDavid du Colombier } else { 125*3e12c5d1SDavid du Colombier /* 126*3e12c5d1SDavid du Colombier * use what's there 127*3e12c5d1SDavid du Colombier */ 128*3e12c5d1SDavid du Colombier dbb = bcread(ic, p->bno); 129*3e12c5d1SDavid du Colombier } 130*3e12c5d1SDavid du Colombier if(dbb == 0) 131*3e12c5d1SDavid du Colombier return -1; 132*3e12c5d1SDavid du Colombier 133*3e12c5d1SDavid du Colombier /* 134*3e12c5d1SDavid du Colombier * merge in the new data 135*3e12c5d1SDavid du Colombier */ 136*3e12c5d1SDavid du Colombier if(p->fbno != fbno){ 137*3e12c5d1SDavid du Colombier p->start = p->end = 0; 138*3e12c5d1SDavid du Colombier p->fbno = fbno; 139*3e12c5d1SDavid du Colombier } 140*3e12c5d1SDavid du Colombier fmerge(p, dbb->data, a, off % ic->bsize, len); 141*3e12c5d1SDavid du Colombier 142*3e12c5d1SDavid du Colombier /* 143*3e12c5d1SDavid du Colombier * write changed blocks back in the 144*3e12c5d1SDavid du Colombier * correct order 145*3e12c5d1SDavid du Colombier */ 146*3e12c5d1SDavid du Colombier bcmark(ic, dbb); 147*3e12c5d1SDavid du Colombier if(ibb){ 148*3e12c5d1SDavid du Colombier bcmark(ic, ibb); 149*3e12c5d1SDavid du Colombier } 150*3e12c5d1SDavid du Colombier if(wrinode){ 151*3e12c5d1SDavid du Colombier if(iwrite(ic, b) < 0) 152*3e12c5d1SDavid du Colombier return -1; 153*3e12c5d1SDavid du Colombier } 154*3e12c5d1SDavid du Colombier return len; 155*3e12c5d1SDavid du Colombier } 156*3e12c5d1SDavid du Colombier 157*3e12c5d1SDavid du Colombier /* 158*3e12c5d1SDavid du Colombier * write `n' bytes to the cache 159*3e12c5d1SDavid du Colombier * 160*3e12c5d1SDavid du Colombier * return number of bytes written 161*3e12c5d1SDavid du Colombier */ 162*3e12c5d1SDavid du Colombier long 163*3e12c5d1SDavid du Colombier fwrite(Icache *ic, Ibuf *b, char *a, ulong off, long n) 164*3e12c5d1SDavid du Colombier { 165*3e12c5d1SDavid du Colombier int len; 166*3e12c5d1SDavid du Colombier long sofar; 167*3e12c5d1SDavid du Colombier 168*3e12c5d1SDavid du Colombier for(sofar = 0; sofar < n; sofar += len){ 169*3e12c5d1SDavid du Colombier len = ic->bsize - ((off+sofar)%ic->bsize); 170*3e12c5d1SDavid du Colombier if(len > n - sofar) 171*3e12c5d1SDavid du Colombier len = n - sofar; 172*3e12c5d1SDavid du Colombier if(fbwrite(ic, b, a+sofar, off+sofar, len) < 0) 173*3e12c5d1SDavid du Colombier return sofar; 174*3e12c5d1SDavid du Colombier } 175*3e12c5d1SDavid du Colombier return sofar; 176*3e12c5d1SDavid du Colombier } 177*3e12c5d1SDavid du Colombier 178*3e12c5d1SDavid du Colombier /* 179*3e12c5d1SDavid du Colombier * get a pointer to the next valid data at or after `off' 180*3e12c5d1SDavid du Colombier */ 181*3e12c5d1SDavid du Colombier Dptr * 182*3e12c5d1SDavid du Colombier fpget(Icache *ic, Ibuf *b, ulong off) 183*3e12c5d1SDavid du Colombier { 184*3e12c5d1SDavid du Colombier Bbuf *ibb; /* indirect block */ 185*3e12c5d1SDavid du Colombier ulong fbno; 186*3e12c5d1SDavid du Colombier long doff; 187*3e12c5d1SDavid du Colombier Dptr *p; 188*3e12c5d1SDavid du Colombier Dptr *p0; 189*3e12c5d1SDavid du Colombier Dptr *pf; 190*3e12c5d1SDavid du Colombier 191*3e12c5d1SDavid du Colombier fbno = off / ic->bsize; 192*3e12c5d1SDavid du Colombier p = &b->inode.ptr; 193*3e12c5d1SDavid du Colombier 194*3e12c5d1SDavid du Colombier /* 195*3e12c5d1SDavid du Colombier * are there any pages for this inode? 196*3e12c5d1SDavid du Colombier */ 197*3e12c5d1SDavid du Colombier if(p->bno == Notabno) 198*3e12c5d1SDavid du Colombier return 0; 199*3e12c5d1SDavid du Colombier 200*3e12c5d1SDavid du Colombier /* 201*3e12c5d1SDavid du Colombier * if it's a direct block, life is easy? 202*3e12c5d1SDavid du Colombier */ 203*3e12c5d1SDavid du Colombier if(!(p->bno & Indbno)){ 204*3e12c5d1SDavid du Colombier /* 205*3e12c5d1SDavid du Colombier * a direct block, return p if it's at least past what we want 206*3e12c5d1SDavid du Colombier */ 207*3e12c5d1SDavid du Colombier if(p->fbno > fbno) 208*3e12c5d1SDavid du Colombier return p; 209*3e12c5d1SDavid du Colombier if(p->fbno < fbno) 210*3e12c5d1SDavid du Colombier return 0; 211*3e12c5d1SDavid du Colombier doff = off % ic->bsize; 212*3e12c5d1SDavid du Colombier if(doff>=p->start && doff<p->end) 213*3e12c5d1SDavid du Colombier return p; 214*3e12c5d1SDavid du Colombier else 215*3e12c5d1SDavid du Colombier return 0; 216*3e12c5d1SDavid du Colombier } 217*3e12c5d1SDavid du Colombier 218*3e12c5d1SDavid du Colombier /* 219*3e12c5d1SDavid du Colombier * read the indirect block 220*3e12c5d1SDavid du Colombier */ 221*3e12c5d1SDavid du Colombier ibb = bcread(ic, p->bno); 222*3e12c5d1SDavid du Colombier if(ibb == 0) 223*3e12c5d1SDavid du Colombier return 0; 224*3e12c5d1SDavid du Colombier 225*3e12c5d1SDavid du Colombier /* 226*3e12c5d1SDavid du Colombier * find the next valid pointer 227*3e12c5d1SDavid du Colombier */ 228*3e12c5d1SDavid du Colombier p0 = (Dptr*)ibb->data; 229*3e12c5d1SDavid du Colombier pf = p0 + (fbno % ic->p2b); 230*3e12c5d1SDavid du Colombier if(pf->bno!=Notabno && pf->fbno==fbno){ 231*3e12c5d1SDavid du Colombier doff = off % ic->bsize; 232*3e12c5d1SDavid du Colombier if(doff<pf->end) 233*3e12c5d1SDavid du Colombier return pf; 234*3e12c5d1SDavid du Colombier } 235*3e12c5d1SDavid du Colombier for(p = pf+1 ;p < p0 + ic->p2b; p++){ 236*3e12c5d1SDavid du Colombier fbno++; 237*3e12c5d1SDavid du Colombier if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end) 238*3e12c5d1SDavid du Colombier return p; 239*3e12c5d1SDavid du Colombier } 240*3e12c5d1SDavid du Colombier for(p = p0 ;p < pf; p++){ 241*3e12c5d1SDavid du Colombier fbno++; 242*3e12c5d1SDavid du Colombier if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end) 243*3e12c5d1SDavid du Colombier return p; 244*3e12c5d1SDavid du Colombier } 245*3e12c5d1SDavid du Colombier return 0; 246*3e12c5d1SDavid du Colombier } 247*3e12c5d1SDavid du Colombier 248*3e12c5d1SDavid du Colombier /* 249*3e12c5d1SDavid du Colombier * read `n' bytes from the cache. 250*3e12c5d1SDavid du Colombier * 251*3e12c5d1SDavid du Colombier * if we hit a gap and we've read something, 252*3e12c5d1SDavid du Colombier * return number of bytes read so far. 253*3e12c5d1SDavid du Colombier * 254*3e12c5d1SDavid du Colombier * if we start with a gap, return minus the number of bytes 255*3e12c5d1SDavid du Colombier * to the next data. 256*3e12c5d1SDavid du Colombier * 257*3e12c5d1SDavid du Colombier * if there are no bytes cached, return 0. 258*3e12c5d1SDavid du Colombier */ 259*3e12c5d1SDavid du Colombier long 260*3e12c5d1SDavid du Colombier fread(Icache *ic, Ibuf *b, char *a, ulong off, long n) 261*3e12c5d1SDavid du Colombier { 262*3e12c5d1SDavid du Colombier int len; 263*3e12c5d1SDavid du Colombier Dptr *p; 264*3e12c5d1SDavid du Colombier Bbuf *bb; 265*3e12c5d1SDavid du Colombier long sofar; 266*3e12c5d1SDavid du Colombier long gap; 267*3e12c5d1SDavid du Colombier int start; 268*3e12c5d1SDavid du Colombier 269*3e12c5d1SDavid du Colombier for(sofar = 0; sofar < n; sofar += len, off += len){ 270*3e12c5d1SDavid du Colombier /* 271*3e12c5d1SDavid du Colombier * get pointer to next data 272*3e12c5d1SDavid du Colombier */ 273*3e12c5d1SDavid du Colombier len = n - sofar; 274*3e12c5d1SDavid du Colombier p = fpget(ic, b, off); 275*3e12c5d1SDavid du Colombier 276*3e12c5d1SDavid du Colombier /* 277*3e12c5d1SDavid du Colombier * if no more data, return what we have so far 278*3e12c5d1SDavid du Colombier */ 279*3e12c5d1SDavid du Colombier if(p == 0) 280*3e12c5d1SDavid du Colombier return sofar; 281*3e12c5d1SDavid du Colombier 282*3e12c5d1SDavid du Colombier /* 283*3e12c5d1SDavid du Colombier * if there's a gap, return the size of the gap 284*3e12c5d1SDavid du Colombier */ 285*3e12c5d1SDavid du Colombier gap = (ic->bsize*p->fbno + p->start) - off; 286*3e12c5d1SDavid du Colombier if(gap>0){ 287*3e12c5d1SDavid du Colombier if(sofar == 0) 288*3e12c5d1SDavid du Colombier return -gap; 289*3e12c5d1SDavid du Colombier else 290*3e12c5d1SDavid du Colombier return sofar; 291*3e12c5d1SDavid du Colombier } 292*3e12c5d1SDavid du Colombier 293*3e12c5d1SDavid du Colombier /* 294*3e12c5d1SDavid du Colombier * return what we have 295*3e12c5d1SDavid du Colombier */ 296*3e12c5d1SDavid du Colombier bb = bcread(ic, p->bno); 297*3e12c5d1SDavid du Colombier if(bb == 0) 298*3e12c5d1SDavid du Colombier return sofar; 299*3e12c5d1SDavid du Colombier start = p->start - gap; 300*3e12c5d1SDavid du Colombier if(p->end - start < len) 301*3e12c5d1SDavid du Colombier len = p->end - start; 302*3e12c5d1SDavid du Colombier memmove(a + sofar, bb->data + start, len); 303*3e12c5d1SDavid du Colombier } 304*3e12c5d1SDavid du Colombier return sofar; 305*3e12c5d1SDavid du Colombier } 306