1 #include <u.h> 2 #include <libc.h> 3 #include "iotrack.h" 4 #include "dat.h" 5 #include "fns.h" 6 7 #define HIOB 31 /* a prime */ 8 #define NIOBUF 80 9 10 static Iotrack hiob[HIOB+1]; /* hash buckets + lru list */ 11 static Iotrack iobuf[NIOBUF]; /* the real ones */ 12 13 #define UNLINK(p, nx, pr) ((p)->pr->nx = (p)->nx, (p)->nx->pr = (p)->pr) 14 15 #define LINK(h, p, nx, pr) ((p)->nx = (h)->nx, (p)->pr = (h), \ 16 (h)->nx->pr = (p), (h)->nx = (p)) 17 18 #define HTOFRONT(h, p) ((h)->hnext != (p) ? (UNLINK(p,hnext,hprev), LINK(h,p,hnext,hprev)) : 0) 19 20 #define TOFRONT(h, p) ((h)->next != (p) ? (UNLINK(p, next, prev), LINK(h,p, next, prev)) : 0) 21 22 Iosect * 23 getsect(Xfs *xf, long addr) 24 { 25 return getiosect(xf, addr, 1); 26 } 27 28 Iosect * 29 getosect(Xfs *xf, long addr) 30 { 31 return getiosect(xf, addr, 0); 32 } 33 34 Iosect * 35 getiosect(Xfs *xf, long addr, int rflag) 36 { 37 Iotrack *t; 38 long taddr; 39 int toff; 40 Iosect *p; 41 42 toff = addr % Sect2trk; 43 taddr = addr - toff; 44 t = getiotrack(xf, taddr); 45 if(rflag && (t->flags&BSTALE)){ 46 if(tread(t) < 0){ 47 unlock(&t->lock); 48 return 0; 49 } 50 t->flags &= ~BSTALE; 51 } 52 t->ref++; 53 p = t->tp->p[toff]; 54 if(p == 0){ 55 p = newsect(); 56 t->tp->p[toff] = p; 57 p->flags = t->flags&BSTALE; 58 p->lock.key = 0; 59 p->t = t; 60 p->iobuf = t->tp->buf[toff]; 61 } 62 unlock(&t->lock); 63 lock(&p->lock); 64 return p; 65 } 66 67 void 68 putsect(Iosect *p) 69 { 70 Iotrack *t; 71 72 if(canlock(&p->lock)) 73 panic("putsect"); 74 t = p->t; 75 lock(&t->lock); 76 t->flags |= p->flags; 77 p->flags = 0; 78 t->ref--; 79 if(t->flags & BIMM){ 80 if(t->flags & BMOD) 81 twrite(t); 82 t->flags &= ~(BMOD|BIMM); 83 } 84 unlock(&t->lock); 85 unlock(&p->lock); 86 } 87 88 Iotrack * 89 getiotrack(Xfs *xf, long addr) 90 { 91 Iotrack *hp, *p; 92 Iotrack *mp = &hiob[HIOB]; 93 long h; 94 /* 95 * chat("iotrack %d,%d...", dev, addr); 96 */ 97 h = (xf->dev<<24) ^ addr; 98 if(h < 0) 99 h = ~h; 100 h %= HIOB; 101 hp = &hiob[h]; 102 103 loop: 104 105 /* 106 * look for it in the active list 107 */ 108 lock(&hp->lock); 109 for(p=hp->hnext; p != hp; p=p->hnext){ 110 if(p->addr != addr || p->xf != xf) 111 continue; 112 unlock(&hp->lock); 113 lock(&p->lock); 114 if(p->addr == addr && p->xf == xf) 115 goto out; 116 unlock(&p->lock); 117 goto loop; 118 } 119 unlock(&hp->lock); 120 /* 121 * not found 122 * take oldest unref'd entry 123 */ 124 lock(&mp->lock); 125 for(p=mp->prev; p != mp; p=p->prev) 126 if(p->ref == 0 && canlock(&p->lock)){ 127 if(p->ref == 0) 128 break; 129 unlock(&p->lock); 130 } 131 unlock(&mp->lock); 132 if(p == mp){ 133 print("iotrack all ref'd\n"); 134 goto loop; 135 } 136 if(p->flags & BMOD){ 137 twrite(p); 138 p->flags &= ~(BMOD|BIMM); 139 unlock(&p->lock); 140 goto loop; 141 } 142 purgetrack(p); 143 p->addr = addr; 144 p->xf = xf; 145 p->flags = BSTALE; 146 out: 147 lock(&hp->lock); HTOFRONT(hp, p); unlock(&hp->lock); 148 lock(&mp->lock); TOFRONT(mp, p); unlock(&mp->lock); 149 return p; 150 } 151 152 void 153 purgetrack(Iotrack *t) 154 { 155 int i, ref = Sect2trk; 156 Iosect *p; 157 158 for(i=0; i<Sect2trk; i++){ 159 p = t->tp->p[i]; 160 if(p == 0){ 161 --ref; 162 continue; 163 } 164 if(canlock(&p->lock)){ 165 freesect(p); 166 --ref; 167 t->tp->p[i] = 0; 168 } 169 } 170 if(t->ref != ref) 171 panic("purgetrack"); 172 } 173 174 int 175 twrite(Iotrack *t) 176 { 177 int i, ref; 178 179 chat("[twrite %d...", t->addr); 180 if(t->flags & BSTALE){ 181 for(ref=0,i=0; i<Sect2trk; i++) 182 if(t->tp->p[i]) 183 ++ref; 184 if(ref < Sect2trk){ 185 if(tread(t) < 0){ 186 chat("error]"); 187 return -1; 188 } 189 }else 190 t->flags &= ~BSTALE; 191 } 192 if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){ 193 chat("error]"); 194 return -1; 195 } 196 chat(" done]"); 197 return 0; 198 } 199 200 int 201 tread(Iotrack *t) 202 { 203 int i, ref = 0; 204 uchar buf[Sect2trk][Sectorsize]; 205 206 for(i=0; i<Sect2trk; i++) 207 if(t->tp->p[i]) 208 ++ref; 209 chat("[tread %d...", t->addr); 210 if(ref == 0){ 211 if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){ 212 chat("error]"); 213 return -1; 214 } 215 chat("done]"); 216 t->flags &= ~BSTALE; 217 return 0; 218 } 219 if(devread(t->xf, t->addr, buf, Trksize) < 0){ 220 chat("error]"); 221 return -1; 222 } 223 for(i=0; i<Sect2trk; i++) 224 if(t->tp->p[i] == 0){ 225 memmove(t->tp->buf[i], buf[i], Sectorsize); 226 chat("%d ", i); 227 } 228 chat("done]"); 229 t->flags &= ~BSTALE; 230 return 0; 231 } 232 233 void 234 purgebuf(Xfs *xf) 235 { 236 Iotrack *p; 237 238 for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){ 239 if(p->xf != xf) 240 continue; 241 lock(&p->lock); 242 if(p->xf == xf){ 243 if(p->flags & BMOD) 244 twrite(p); 245 p->flags = BSTALE; 246 purgetrack(p); 247 } 248 unlock(&p->lock); 249 } 250 } 251 252 void 253 sync(void) 254 { 255 Iotrack *p; 256 257 for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){ 258 if(!(p->flags & BMOD)) 259 continue; 260 lock(&p->lock); 261 if(p->flags & BMOD){ 262 twrite(p); 263 p->flags &= ~(BMOD|BIMM); 264 } 265 unlock(&p->lock); 266 } 267 } 268 269 void 270 iotrack_init(void) 271 { 272 Iotrack *mp, *p; 273 274 for (mp=&hiob[0]; mp<&hiob[HIOB]; mp++) 275 mp->hprev = mp->hnext = mp; 276 mp->prev = mp->next = mp; 277 278 for (p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) { 279 p->hprev = p->hnext = p; 280 p->prev = p->next = p; 281 TOFRONT(mp, p); 282 p->tp = sbrk(sizeof(Track)); 283 memset(p->tp->p, 0, sizeof p->tp->p); 284 } 285 } 286 287 static Lock freelock; 288 static Iosect * freelist; 289 290 Iosect * 291 newsect(void) 292 { 293 Iosect *p; 294 295 lock(&freelock); 296 if(p = freelist) /* assign = */ 297 freelist = p->next; 298 else 299 p = malloc(sizeof(Iosect)); 300 unlock(&freelock); 301 p->next = 0; 302 return p; 303 } 304 305 void 306 freesect(Iosect *p) 307 { 308 lock(&freelock); 309 p->next = freelist; 310 freelist = p; 311 unlock(&freelock); 312 } 313