diff --git a/Makefile b/Makefile index a9ae631..d995429 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,8 @@ OBJS = \ trapasm.o\ trap.o\ vectors.o\ + bio.o\ + fs.o\ # Cross-compiling (e.g., on Mac OS X) TOOLPREFIX = i386-jos-elf- @@ -30,7 +32,7 @@ OBJDUMP = $(TOOLPREFIX)objdump CFLAGS = -fno-builtin -O2 -Wall -MD AS = $(TOOLPREFIX)gas -xv6.img : bootblock kernel +xv6.img : bootblock kernel fs.img dd if=/dev/zero of=xv6.img count=10000 dd if=bootblock of=xv6.img conv=notrunc dd if=kernel of=xv6.img seek=1 conv=notrunc @@ -68,8 +70,15 @@ userfs : userfs.o $(ULIB) $(LD) -N -e main -Ttext 0 -o userfs userfs.o $(ULIB) $(OBJDUMP) -S userfs > userfs.asm +mkfs : mkfs.c fs.h + cc -o mkfs mkfs.c + +fs.img : mkfs + ./mkfs fs.img + -include *.d clean : rm -f *.o *.d *.asm vectors.S parport.out \ - bootblock kernel xv6.img user1 userfs usertests + bootblock kernel xv6.img user1 userfs usertests \ + fs.img mkfs diff --git a/bio.c b/bio.c new file mode 100644 index 0000000..9be11df --- /dev/null +++ b/bio.c @@ -0,0 +1,66 @@ +#include "types.h" +#include "param.h" +#include "x86.h" +#include "mmu.h" +#include "proc.h" +#include "defs.h" +#include "spinlock.h" +#include "buf.h" + +struct buf buf[NBUF]; +struct spinlock buf_table_lock; + +struct buf * +getblk() +{ + int i; + + acquire(&buf_table_lock); + + // XXX need to lock the block even if not caching, to + // avoid read modify write problems. + + while(1){ + for(i = 0; i < NBUF; i++){ + if((buf[i].flags & B_BUSY) == 0){ + buf[i].flags |= B_BUSY; + release(&buf_table_lock); + return buf + i; + } + } + sleep(buf, &buf_table_lock); + } +} + +struct buf * +bread(uint dev, uint sector) +{ + void *c; + struct buf *b; + extern struct spinlock ide_lock; + + b = getblk(); + + acquire(&ide_lock); + c = ide_start_read(dev & 0xff, sector, b->data, 1); + // sleep (c, &ide_lock); + ide_finish_read(c); + release(&ide_lock); + + return b; +} + +void +brelse(struct buf *b) +{ + if((b->flags & B_BUSY) == 0) + panic("brelse"); + + acquire(&buf_table_lock); + + b->flags &= ~B_BUSY; + wakeup(buf); + + release(&buf_table_lock); +} + diff --git a/buf.h b/buf.h new file mode 100644 index 0000000..a4cea5e --- /dev/null +++ b/buf.h @@ -0,0 +1,5 @@ +struct buf { + int flags; + uchar data[512]; +}; +#define B_BUSY 0x1 diff --git a/defs.h b/defs.h index beed68a..0ed71bb 100644 --- a/defs.h +++ b/defs.h @@ -87,6 +87,14 @@ void fd_incref(struct fd *fd); // ide.c void ide_init(void); void ide_intr(void); -void* ide_start_read(uint secno, void *dst, uint nsecs); +void* ide_start_read(int diskno, uint secno, void *dst, uint nsecs); int ide_finish_read(void *); +// bio.c +struct buf; +struct buf *bread(uint, uint); +void brelse(struct buf *); + +// fs.c +struct inode * iget(uint dev, uint inum); +void iput(struct inode *ip); diff --git a/fs.c b/fs.c new file mode 100644 index 0000000..48c943a --- /dev/null +++ b/fs.c @@ -0,0 +1,73 @@ +#include "types.h" +#include "param.h" +#include "x86.h" +#include "mmu.h" +#include "proc.h" +#include "defs.h" +#include "spinlock.h" +#include "buf.h" +#include "fs.h" +#include "fsvar.h" + +// these are inodes currently in use +// an entry is free if count == 0 +struct inode inode[NINODE]; +struct spinlock inode_table_lock; + +struct inode * +iget(uint dev, uint inum) +{ + struct inode *ip, *nip = 0; + struct dinode *dip; + struct buf *bp; + + acquire(&inode_table_lock); + + loop: + for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ + if(ip->count > 0 && ip->dev == dev && ip->inum == inum){ + if(ip->busy){ + sleep(ip, &inode_table_lock); + goto loop; + } + ip->count++; + release(&inode_table_lock); + return ip; + } + if(nip == 0 && ip->count == 0) + nip = ip; + } + + if(nip == 0) + panic("out of inodes"); + + nip->dev = dev; + nip->inum = inum; + nip->count = 1; + nip->busy = 1; + + release(&inode_table_lock); + + bp = bread(dev, inum / IPB + 2); + dip = &((struct dinode *)(bp->data))[inum % IPB]; + nip->type = dip->type; + nip->nlink = dip->nlink; + nip->size = dip->size; + memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); + cprintf("bn %d off %d\n", inum / IPB + 2, (unsigned)dip - (unsigned)bp->data); + brelse(bp); + + return nip; +} + +void +iput(struct inode *ip) +{ + acquire(&inode_table_lock); + + ip->count -= 1; + ip->busy = 0; + wakeup(ip); + + release(&inode_table_lock); +} diff --git a/fs.h b/fs.h new file mode 100644 index 0000000..b710e1c --- /dev/null +++ b/fs.h @@ -0,0 +1,28 @@ +// on-disk file system format + +// second sector +struct superblock{ + int nblocks; + int ninodes; +}; + +#define NDIRECT 14 + +// inodes start at the third sector +// and blocks start at (ninodes * sizeof(dinode) + 511) / 512 +struct dinode { + short type; + short nlink; + uint size; + uint addrs[NDIRECT]; +}; +#define T_DIR 1 +#define T_FILE 2 + +#define IPB (512 / sizeof(struct dinode)) + +struct dirent { + ushort inum; + char name[14]; +}; + diff --git a/fsvar.h b/fsvar.h new file mode 100644 index 0000000..4388f75 --- /dev/null +++ b/fsvar.h @@ -0,0 +1,12 @@ +// in-core file system types + +struct inode { + uint dev; + uint inum; + int count; + int busy; + short type; + short nlink; + uint size; + uint addrs[NDIRECT]; +}; diff --git a/ide.c b/ide.c index 5b75053..291ab83 100644 --- a/ide.c +++ b/ide.c @@ -84,7 +84,7 @@ ide_start_request (void) { struct ide_request *r; - if (head == tail) { + if (head != tail) { r = &request[tail]; ide_wait_ready(0); outb(0x3f6, 0); @@ -98,7 +98,7 @@ ide_start_request (void) } void * -ide_start_read(uint secno, void *dst, uint nsecs) +ide_start_read(int diskno, uint secno, void *dst, uint nsecs) { struct ide_request *r; if(!holding(&ide_lock)) @@ -114,12 +114,12 @@ ide_start_read(uint secno, void *dst, uint nsecs) r->secno = secno; r->dst = dst; r->nsecs = nsecs; - r->diskno = 0; - - ide_start_request(); + r->diskno = diskno; head = (head + 1) % NREQUEST; + ide_start_request(); + return r; } @@ -129,6 +129,9 @@ ide_finish_read(void *c) int r = 0; struct ide_request *req = (struct ide_request *) c; + if(c != &request[tail]) + panic("ide_finish_read"); + if(!holding(&ide_lock)) panic("ide_start_read: not holding ide_lock"); for (; req->nsecs > 0; req->nsecs--, req->dst += 512) { @@ -148,10 +151,9 @@ ide_finish_read(void *c) } int -ide_write(uint secno, const void *src, uint nsecs) +ide_write(int diskno, uint secno, const void *src, uint nsecs) { int r; - int diskno = 0; if(nsecs > 256) panic("ide_write"); diff --git a/mkfs.c b/mkfs.c new file mode 100644 index 0000000..033e064 --- /dev/null +++ b/mkfs.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include "types.h" +#include "param.h" +#include "fs.h" + +int nblocks = 1009; +int ninodes = 100; + +int fd; +struct superblock sb; +char zeroes[512]; +uint freeblock; + +void wsect(uint, void *); +void winode(uint, struct dinode *); +void rsect(uint sec, void *buf); + +// convert to intel byte order +ushort +xshort(ushort x) +{ + ushort y; + uchar *a = &y; + a[0] = x; + a[1] = x >> 8; + return y; +} + +uint +xint(uint x) +{ + uint y; + uchar *a = &y; + a[0] = x; + a[1] = x >> 8; + a[2] = x >> 16; + a[3] = x >> 24; + return y; +} + +main(int argc, char *argv[]) +{ + int i; + struct dinode din; + char dbuf[512]; + + if(argc != 2){ + fprintf(stderr, "Usage: mkfs fs.img\n"); + exit(1); + } + + if(sizeof(struct dinode) * IPB != 512){ + fprintf(stderr, "sizeof(dinode) must divide 512\n"); + exit(1); + } + + fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); + if(fd < 0){ + perror(argv[1]); + exit(1); + } + + sb.nblocks = xint(nblocks); // so whole disk is 1024 sectors + sb.ninodes = xint(ninodes); + + freeblock = ninodes / IPB + 2; + + for(i = 0; i < nblocks + (ninodes / IPB) + 3; i++) + wsect(i, zeroes); + + wsect(1, &sb); + + bzero(&din, sizeof(din)); + din.type = xshort(T_DIR); + din.nlink = xshort(2); + din.size = xint(512); + din.addrs[0] = xint(freeblock++); + winode(1, &din); + + bzero(dbuf, sizeof(dbuf)); + ((struct dirent *) dbuf)[0].inum = xshort(1); + strcpy(((struct dirent *) dbuf)[0].name, "."); + ((struct dirent *) dbuf)[1].inum = xshort(1); + strcpy(((struct dirent *) dbuf)[1].name, ".."); + wsect(din.addrs[0], dbuf); + + exit(0); +} + +void +wsect(uint sec, void *buf) +{ + if(lseek(fd, sec * 512L, 0) != sec * 512L){ + perror("lseek"); + exit(1); + } + if(write(fd, buf, 512) != 512){ + perror("write"); + exit(1); + } +} + +uint +i2b(uint inum) +{ + return (inum / IPB) + 2; +} + +void +winode(uint inum, struct dinode *ip) +{ + char buf[512]; + uint bn; + struct dinode *dip; + + bn = i2b(inum); + rsect(bn, buf); + dip = ((struct dinode *) buf) + (inum % IPB); + *dip = *ip; + printf("bn %d off %d\n", + bn, (unsigned)dip - (unsigned) buf); + wsect(bn, buf); +} + +void +rsect(uint sec, void *buf) +{ + if(lseek(fd, sec * 512L, 0) != sec * 512L){ + perror("lseek"); + exit(1); + } + if(read(fd, buf, 512) != 512){ + perror("read"); + exit(1); + } +} diff --git a/mmu.h b/mmu.h index fd10ed6..82fb89d 100644 --- a/mmu.h +++ b/mmu.h @@ -125,7 +125,7 @@ struct segdesc { // Task state segment format (as described by the Pentium architecture book) struct taskstate { uint link; // Old ts selector - uint * esp0; // Stack pointers and segment selectors + uint esp0; // Stack pointers and segment selectors ushort ss0; // after an increase in privilege level ushort padding1; uint * esp1; diff --git a/param.h b/param.h index bdd8b70..9b5c5e8 100644 --- a/param.h +++ b/param.h @@ -5,3 +5,5 @@ #define NOFILE 16 // file descriptors per process #define NFD 100 // file descriptors per system #define NREQUEST 100 // outstanding disk requests +#define NBUF 10 +#define NINODE 100 diff --git a/syscall.c b/syscall.c index ff5fea6..68af208 100644 --- a/syscall.c +++ b/syscall.c @@ -7,6 +7,9 @@ #include "traps.h" #include "syscall.h" #include "spinlock.h" +#include "buf.h" +#include "fs.h" +#include "fsvar.h" /* * User code makes a system call with INT T_SYSCALL. @@ -224,30 +227,27 @@ sys_cons_puts(void) int sys_block(void) { - char buf[512]; int i, j; - void *c; - extern struct spinlock ide_lock; + struct buf *b; + struct inode *ip; - cprintf("%d: call sys_block\n", cpu()); - for (i = 0; i < 100; i++) { - acquire(&ide_lock); - if ((c = ide_start_read(i, buf, 1)) == 0) { - panic("couldn't start read\n"); - } -#if 0 - cprintf("call sleep\n"); - sleep (c, &ide_lock); -#endif - if (ide_finish_read(c)) { - panic("couldn't do read\n"); - } - release(&ide_lock); - cprintf("sector %d: ", i); - for (j = 0; j < 2; j++) - cprintf("%x ", buf[j] & 0xff); + for (i = 0; i < 2; i++) { + b = bread(1, i); + + cprintf("disk 1 sector %d: ", i); + for (j = 0; j < 4; j++) + cprintf("%x ", b->data[j] & 0xff); cprintf("\n"); + + brelse(b); } + + ip = iget(1, 1); + cprintf("%d %d %d %d %d %d %d %d\n", + ip->dev, ip->inum, ip->count, ip->busy, + ip->type, ip->nlink, ip->size, ip->addrs[0]); + iput(ip); + return 0; }