diff --git a/Notes b/Notes index 681d69a..f0955b8 100644 --- a/Notes +++ b/Notes @@ -142,10 +142,22 @@ systematic way to test sleep races? do you have to be holding the mutex in order to call wakeup()? -should lock around printf, not putc - device interrupts don't clear FL_IF so a recursive timer interrupt is possible -the sleep/swtch/schedule code that holds over a lock is ugly +what does inode->busy mean? + might be held across disk reads + no-one is allowed to do anything to the inode + protected by inode_table_lock +inode->count counts in-memory pointers to the struct + prevents inode[] element from being re-used + protected by inode_table_lock +blocks and inodes have ad-hoc sleep-locks + provide a single mechanism? + +need to lock bufs in bio between bread and brelse + +test 14-character file names +and file arguments longer than 14 +and directories longer than one sector diff --git a/defs.h b/defs.h index 0ed71bb..35a7139 100644 --- a/defs.h +++ b/defs.h @@ -97,4 +97,8 @@ void brelse(struct buf *); // fs.c struct inode * iget(uint dev, uint inum); +void ilock(struct inode *ip); +void iunlock(struct inode *ip); +void iincref(struct inode *ip); void iput(struct inode *ip); +struct inode * namei(char *path); diff --git a/fs.c b/fs.c index 48c943a..3eda6e9 100644 --- a/fs.c +++ b/fs.c @@ -14,6 +14,9 @@ struct inode inode[NINODE]; struct spinlock inode_table_lock; +uint rootdev = 1; + +// returns an inode with busy set and incremented reference count. struct inode * iget(uint dev, uint inum) { @@ -54,15 +57,50 @@ iget(uint dev, uint inum) 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 +ilock(struct inode *ip) +{ + if(ip->count < 1) + panic("ilock"); + + acquire(&inode_table_lock); + + while(ip->busy) + sleep(ip, &inode_table_lock); + ip->busy = 1; + + release(&inode_table_lock); +} + +// caller is holding onto a reference to this inode, but no +// longer needs to examine or change it, so clear ip->busy. +void +iunlock(struct inode *ip) +{ + if(ip->busy != 1) + panic("iunlock"); + + acquire(&inode_table_lock); + + ip->busy = 0; + wakeup(ip); + + release(&inode_table_lock); +} + +// caller is releasing a reference to this inode. +// you must have the inode lock. void iput(struct inode *ip) { + if(ip->count < 1 || ip->busy != 1) + panic("iput"); + acquire(&inode_table_lock); ip->count -= 1; @@ -71,3 +109,82 @@ iput(struct inode *ip) release(&inode_table_lock); } + +void +iincref(struct inode *ip) +{ + acquire(&inode_table_lock); + + ip->count += 1; + + release(&inode_table_lock); +} + +uint +bmap(struct inode *ip, uint bn) +{ + unsigned x; + + if(bn >= NDIRECT) + panic("bmap 1"); + x = ip->addrs[bn]; + if(x == 0) + panic("bmap 2"); + return x; +} + +struct inode * +namei(char *path) +{ + struct inode *dp; + char *cp = path; + uint off, dev; + struct buf *bp; + struct dirent *ep; + int i; + unsigned ninum; + + dp = iget(rootdev, 1); + + while(*cp == '/') + cp++; + + while(1){ + if(*cp == '\0') + return dp; + + if(dp->type != T_DIR){ + iput(dp); + return 0; + } + + for(off = 0; off < dp->size; off += 512){ + bp = bread(dp->dev, bmap(dp, off / 512)); + for(ep = (struct dirent *) bp->data; + ep < (struct dirent *) (bp->data + 512); + ep++){ + if(ep->inum == 0) + continue; + for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++) + if(cp[i] != ep->name[i]) + break; + if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){ + ninum = ep->inum; + brelse(bp); + cp += i; + goto found; + } + } + brelse(bp); + } + iput(dp); + return 0; + + found: + dev = dp->dev; + iput(dp); + dp = iget(dev, ninum); + while(*cp == '/') + cp++; + } +} diff --git a/fs.h b/fs.h index b710e1c..a842e64 100644 --- a/fs.h +++ b/fs.h @@ -21,8 +21,10 @@ struct dinode { #define IPB (512 / sizeof(struct dinode)) +#define DIRSIZ 14 + struct dirent { ushort inum; - char name[14]; + char name[DIRSIZ]; }; diff --git a/fsvar.h b/fsvar.h index 4388f75..dba45d5 100644 --- a/fsvar.h +++ b/fsvar.h @@ -10,3 +10,5 @@ struct inode { uint size; uint addrs[NDIRECT]; }; + +extern uint rootdev; diff --git a/mkfs.c b/mkfs.c index 033e064..9dcb29c 100644 --- a/mkfs.c +++ b/mkfs.c @@ -24,7 +24,7 @@ ushort xshort(ushort x) { ushort y; - uchar *a = &y; + uchar *a = (uchar *) &y; a[0] = x; a[1] = x >> 8; return y; @@ -34,7 +34,7 @@ uint xint(uint x) { uint y; - uchar *a = &y; + uchar *a = (uchar *) &y; a[0] = x; a[1] = x >> 8; a[2] = x >> 16; @@ -47,16 +47,21 @@ main(int argc, char *argv[]) int i; struct dinode din; char dbuf[512]; + uint bn; if(argc != 2){ fprintf(stderr, "Usage: mkfs fs.img\n"); exit(1); } - if(sizeof(struct dinode) * IPB != 512){ + if((512 % sizeof(struct dinode)) != 0){ fprintf(stderr, "sizeof(dinode) must divide 512\n"); exit(1); } + if((512 % sizeof(struct dirent)) != 0){ + fprintf(stderr, "sizeof(dirent) must divide 512\n"); + exit(1); + } fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); if(fd < 0){ @@ -78,7 +83,8 @@ main(int argc, char *argv[]) din.type = xshort(T_DIR); din.nlink = xshort(2); din.size = xint(512); - din.addrs[0] = xint(freeblock++); + bn = freeblock++; + din.addrs[0] = xint(bn); winode(1, &din); bzero(dbuf, sizeof(dbuf)); @@ -86,7 +92,7 @@ main(int argc, char *argv[]) strcpy(((struct dirent *) dbuf)[0].name, "."); ((struct dirent *) dbuf)[1].inum = xshort(1); strcpy(((struct dirent *) dbuf)[1].name, ".."); - wsect(din.addrs[0], dbuf); + wsect(bn, dbuf); exit(0); } diff --git a/syscall.c b/syscall.c index 68af208..c6ae0db 100644 --- a/syscall.c +++ b/syscall.c @@ -243,11 +243,21 @@ sys_block(void) } ip = iget(1, 1); - cprintf("%d %d %d %d %d %d %d %d\n", + cprintf("iget 1: %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); + ip = namei(".././//./../"); + if(ip){ + cprintf("namei: %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); + } else { + cprintf("namei failed\n"); + } + return 0; }