devblk.c (4797B)
1 #include <errno.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include <os9/os9.h> 6 7 #include "dev.h" 8 #include "blk.h" 9 10 #define NR_BLOCKS 1 11 #define NR_BLKS 2 12 13 typedef struct buffer Buffer; 14 15 enum Odevqid { 16 Qblockfs, 17 Qraw, 18 Qctl, 19 }; 20 21 enum bstatus { 22 BBUSY = 1 << 0, 23 BDIRTY = 1 << 1, 24 BVALID = 1 << 2, 25 BERROR = 1 << 3, 26 }; 27 28 struct buffer { 29 int devno; 30 long block; 31 int flags; 32 void *ptr; 33 mutex_t mutex; 34 }; 35 36 static char buffers[NR_BLOCKS][BLKSIZ]; 37 static Buffer bcache[NR_BLOCKS]; 38 39 static Dirtab dirtab[] = { 40 {"raw", QID(CHFILE, 0, Qraw), 0, O_READ | O_WRITE}, 41 {"ctl", QID(CHFILE, 0, Qctl), 0, O_READ | O_WRITE} 42 }; 43 44 static Blk *blks[NR_BLKS]; 45 static int nblks; 46 47 static int 48 blkwalk(Chan *c, char *name) 49 { 50 return devwalk(c, name, dirtab, NELEM(dirtab), devgen); 51 } 52 53 static int 54 blkstat(Chan *c, char *file, unsigned char *buf, int n) 55 { 56 return devstat(c, file, buf, n, dirtab, NELEM(dirtab), devgen); 57 } 58 59 static Buffer * 60 getblk(int devno, long blkno) 61 { 62 Buffer *bp = &bcache[blkno % NR_BLOCKS]; 63 Blk *dev; 64 65 repeat: 66 lock(&bp->mutex); 67 if (bp->flags & BBUSY) { 68 unlock(&bp->mutex); 69 /* TODO: sleep(); */ 70 goto repeat; 71 } 72 73 if ((bp->flags & BVALID) == 0 || 74 bp->devno != devno || bp->block != blkno) { 75 if (bp->flags & BDIRTY) { 76 dev = blks[bp->devno]; 77 if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) { 78 seterror(EIO); 79 bp->flags |= BERROR; 80 goto return_buffer; 81 } 82 } 83 84 bp->devno = devno; 85 bp->block = blkno; 86 bp->flags = 0; 87 dev = blks[devno]; 88 89 switch (dev->phy->bread(dev, blkno, bp->ptr)) { 90 case -1: 91 bp->flags |= BERROR; 92 break; 93 case 0: 94 // EOF: no flag set 95 break; 96 default: 97 bp->flags |= BVALID; 98 break; 99 } 100 } 101 102 return_buffer: 103 bp->flags |= BBUSY; 104 unlock(&bp->mutex); 105 return bp; 106 } 107 108 static int 109 brelse(Buffer *bp) 110 { 111 int r = 0; 112 Blk *dev; 113 114 if ((bp->flags & BBUSY) == 0) 115 panic("brelse"); 116 117 lock(&bp->mutex); 118 if ((bp->flags & BDIRTY) != 0) { 119 dev = blks[bp->devno]; 120 if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) { 121 seterror(EIO); 122 bp->flags |= BERROR; 123 r = -1; 124 } 125 } 126 bp->flags &= ~(BBUSY|BDIRTY); 127 unlock(&bp->mutex); 128 129 return r; 130 } 131 132 static int 133 rawread(Chan *c, void *buf, int nbytes) 134 { 135 int n, cnt; 136 Buffer *bp; 137 long off, blk; 138 char *ptr = buf; 139 140 for (cnt = 0; cnt < nbytes; cnt += n) { 141 blk = c->offset / BLKSIZ; 142 off = c->offset % BLKSIZ; 143 144 bp = getblk(c->dev, blk); 145 switch (bp->flags & (BVALID | BERROR)) { 146 case BVALID|BERROR: 147 case BERROR: 148 cnt = -1; 149 case 0: 150 brelse(bp); 151 return cnt; 152 case BVALID: 153 n = BLKSIZ - off; 154 if (n > nbytes) 155 n = nbytes; 156 memcpy(ptr, bp->ptr + off, n); 157 ptr += n; 158 c->offset += n; 159 brelse(bp); 160 break; 161 } 162 } 163 164 return cnt; 165 } 166 167 static int 168 blkread(Chan *c, void *buf, int n) 169 { 170 switch (c->qid.path) { 171 case Qblockfs: 172 return dirread(c, buf, n, dirtab, NELEM(dirtab), devgen); 173 case Qraw: 174 return rawread(c, buf, n); 175 case Qctl: 176 /* TODO */ 177 default: 178 panic("blkread"); 179 } 180 } 181 182 static int 183 rawwrite(Chan *c, void *buf, int nbytes) 184 { 185 int n, cnt; 186 Buffer *bp; 187 long off, blk; 188 char *ptr = buf; 189 190 for (cnt = 0; cnt < nbytes; cnt += n) { 191 blk = c->offset / BLKSIZ; 192 off = c->offset % BLKSIZ; 193 194 bp = getblk(c->dev, blk); 195 switch (bp->flags & (BVALID | BERROR)) { 196 case 0: 197 seterror(EFBIG); 198 case BVALID|BERROR: 199 case BERROR: 200 brelse(bp); 201 return -1; 202 case BVALID: 203 n = BLKSIZ - off; 204 if (n > nbytes - cnt) 205 n = nbytes - cnt; 206 memcpy(bp->ptr + off, ptr, n); 207 ptr += n; 208 c->offset += n; 209 bp->flags |= BDIRTY; 210 brelse(bp); 211 break; 212 } 213 } 214 return cnt; 215 } 216 217 static int 218 blkwrite(Chan *c, void *buf, int n) 219 { 220 switch (c->qid.path) { 221 case Qraw: 222 return rawwrite(c, buf, n); 223 case Qctl: 224 /* TODO */ 225 default: 226 panic("blkwrite"); 227 } 228 } 229 230 static int 231 blksync(Chan *c, int what) 232 { 233 Blk *dev; 234 Buffer *bp; 235 int r = 0; 236 237 for (bp = bcache; bp < &bcache[NR_BLOCKS]; ++bp) { 238 lock(&bp->mutex); 239 240 if ((bp->flags & BDIRTY) != 0 && 241 (what == SYNCALL || bp->devno == c->dev)) { 242 dev = blks[bp->devno]; 243 if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) { 244 r = -1; 245 seterror(EIO); 246 bp->flags |= BERROR; 247 } else { 248 bp->flags &= BDIRTY; 249 } 250 } 251 252 unlock(&bp->mutex); 253 } 254 255 return r; 256 } 257 258 void 259 blklink(Blkphy *phy, Attr *attr) 260 { 261 size_t siz; 262 Blk *dev; 263 static int first = 1; 264 265 if (nblks == NR_BLKS) 266 panic("blklink"); 267 268 if (first) { 269 int i; 270 Buffer *bp; 271 272 for (i = 0; i < NR_BLOCKS; i++) { 273 bp = &bcache[i]; 274 bp->ptr = buffers[i]; 275 bp->flags = 0; 276 } 277 first = 0; 278 } 279 280 siz = sizeof(Blk); 281 dev = memset(alloc(siz), 0, siz); 282 dev->phy = phy; 283 blks[nblks++] = dev; 284 285 (*phy->init)(dev, attr); 286 } 287 288 Dev blkdevtab = { 289 .id = 'b', 290 .stat = blkstat, 291 .clone = devclone, 292 .attach = devattach, 293 .walk = blkwalk, 294 .read = blkread, 295 .write = blkwrite, 296 .mount = deverrmount, 297 .seek = devseek, 298 .sync = blksync, 299 .close = devclose, 300 };