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))) 19 20 #define TOFRONT(h, p) ((h)->next != (p) && (UNLINK(p, next, prev), LINK(h,p, next, prev))) 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 unmlock(&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 unmlock(&t->lock); 63 mlock(&p->lock); 64 return p; 65 } 66 67 void 68 putsect(Iosect *p) 69 { 70 Iotrack *t; 71 72 if(canmlock(&p->lock)) 73 panic("putsect"); 74 t = p->t; 75 mlock(&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 unmlock(&t->lock); 85 unmlock(&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 mlock(&hp->lock); 109 for(p=hp->hnext; p != hp; p=p->hnext){ 110 if(p->addr != addr || p->xf != xf) 111 continue; 112 unmlock(&hp->lock); 113 mlock(&p->lock); 114 if(p->addr == addr && p->xf == xf) 115 goto out; 116 unmlock(&p->lock); 117 goto loop; 118 } 119 unmlock(&hp->lock); 120 /* 121 * not found 122 * take oldest unref'd entry 123 */ 124 mlock(&mp->lock); 125 for(p=mp->prev; p != mp; p=p->prev) 126 if(p->ref == 0 && canmlock(&p->lock)){ 127 if(p->ref == 0) 128 break; 129 unmlock(&p->lock); 130 } 131 unmlock(&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 unmlock(&p->lock); 140 goto loop; 141 } 142 purgetrack(p); 143 p->addr = addr; 144 p->xf = xf; 145 p->flags = BSTALE; 146 out: 147 mlock(&hp->lock); 148 HTOFRONT(hp, p); 149 unmlock(&hp->lock); 150 mlock(&mp->lock); 151 TOFRONT(mp, p); 152 unmlock(&mp->lock); 153 return p; 154 } 155 156 void 157 purgetrack(Iotrack *t) 158 { 159 int i, ref = Sect2trk; 160 Iosect *p; 161 162 for(i=0; i<Sect2trk; i++){ 163 p = t->tp->p[i]; 164 if(p == 0){ 165 --ref; 166 continue; 167 } 168 if(canmlock(&p->lock)){ 169 freesect(p); 170 --ref; 171 t->tp->p[i] = 0; 172 } 173 } 174 if(t->ref != ref) 175 panic("purgetrack"); 176 } 177 178 int 179 twrite(Iotrack *t) 180 { 181 int i, ref; 182 183 chat("[twrite %ld...", t->addr); 184 if(t->flags & BSTALE){ 185 for(ref=0,i=0; i<Sect2trk; i++) 186 if(t->tp->p[i]) 187 ++ref; 188 if(ref < Sect2trk){ 189 if(tread(t) < 0){ 190 chat("error]"); 191 return -1; 192 } 193 }else 194 t->flags &= ~BSTALE; 195 } 196 if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){ 197 chat("error]"); 198 return -1; 199 } 200 chat(" done]"); 201 return 0; 202 } 203 204 int 205 tread(Iotrack *t) 206 { 207 int i, ref = 0; 208 uchar buf[Sect2trk][Sectorsize]; 209 210 for(i=0; i<Sect2trk; i++) 211 if(t->tp->p[i]) 212 ++ref; 213 chat("[tread %ld+%ld...", t->addr, t->xf->offset); 214 if(ref == 0){ 215 if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){ 216 chat("error]"); 217 return -1; 218 } 219 chat("done]"); 220 t->flags &= ~BSTALE; 221 return 0; 222 } 223 if(devread(t->xf, t->addr, buf, Trksize) < 0){ 224 chat("error]"); 225 return -1; 226 } 227 for(i=0; i<Sect2trk; i++) 228 if(t->tp->p[i] == 0){ 229 memmove(t->tp->buf[i], buf[i], Sectorsize); 230 chat("%d ", i); 231 } 232 chat("done]"); 233 t->flags &= ~BSTALE; 234 return 0; 235 } 236 237 void 238 purgebuf(Xfs *xf) 239 { 240 Iotrack *p; 241 242 for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){ 243 if(p->xf != xf) 244 continue; 245 mlock(&p->lock); 246 if(p->xf == xf){ 247 if(p->flags & BMOD) 248 twrite(p); 249 p->flags = BSTALE; 250 purgetrack(p); 251 } 252 unmlock(&p->lock); 253 } 254 } 255 256 void 257 sync(void) 258 { 259 Iotrack *p; 260 261 for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){ 262 if(!(p->flags & BMOD)) 263 continue; 264 mlock(&p->lock); 265 if(p->flags & BMOD){ 266 twrite(p); 267 p->flags &= ~(BMOD|BIMM); 268 } 269 unmlock(&p->lock); 270 } 271 } 272 273 void 274 iotrack_init(void) 275 { 276 Iotrack *mp, *p; 277 278 for (mp=&hiob[0]; mp<&hiob[HIOB]; mp++) 279 mp->hprev = mp->hnext = mp; 280 mp->prev = mp->next = mp; 281 282 for (p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) { 283 p->hprev = p->hnext = p; 284 p->prev = p->next = p; 285 TOFRONT(mp, p); 286 p->tp = sbrk(sizeof(Track)); 287 memset(p->tp->p, 0, sizeof p->tp->p); 288 } 289 } 290 291 static MLock freelock; 292 static Iosect * freelist; 293 294 Iosect * 295 newsect(void) 296 { 297 Iosect *p; 298 299 mlock(&freelock); 300 if(p = freelist) /* assign = */ 301 freelist = p->next; 302 else 303 p = malloc(sizeof(Iosect)); 304 unmlock(&freelock); 305 p->next = 0; 306 return p; 307 } 308 309 void 310 freesect(Iosect *p) 311 { 312 mlock(&freelock); 313 p->next = freelist; 314 freelist = p; 315 unmlock(&freelock); 316 } 317