This commit is contained in:
rtm 2006-07-21 22:10:40 +00:00
parent 11a9947f1a
commit 9d3fb67141
7 changed files with 164 additions and 11 deletions

18
Notes
View file

@ -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

4
defs.h
View file

@ -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);

119
fs.c
View file

@ -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++;
}
}

4
fs.h
View file

@ -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];
};

View file

@ -10,3 +10,5 @@ struct inode {
uint size;
uint addrs[NDIRECT];
};
extern uint rootdev;

16
mkfs.c
View file

@ -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);
}

View file

@ -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;
}