summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Notes18
-rw-r--r--defs.h4
-rw-r--r--fs.c119
-rw-r--r--fs.h4
-rw-r--r--fsvar.h2
-rw-r--r--mkfs.c16
-rw-r--r--syscall.c12
7 files changed, 164 insertions, 11 deletions
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;
}