diff --git a/fs.c b/fs.c
index 13fc935454b70d8826fa381fa6b3453173a2f38a..fe65338be8f39e01d252f5aac79e40cf88a10de6 100644
--- a/fs.c
+++ b/fs.c
@@ -141,6 +141,53 @@ iinit(void)
   initlock(&icache.lock, "icache");
 }
 
+static struct inode* iget(uint dev, uint inum);
+
+//PAGEBREAK!
+// Allocate a new inode with the given type on device dev.
+struct inode*
+ialloc(uint dev, short type)
+{
+  int inum;
+  struct buf *bp;
+  struct dinode *dip;
+  struct superblock sb;
+
+  readsb(dev, &sb);
+  for(inum = 1; inum < sb.ninodes; inum++){  // loop over inode blocks
+    bp = bread(dev, IBLOCK(inum));
+    dip = (struct dinode*)bp->data + inum%IPB;
+    if(dip->type == 0){  // a free inode
+      memset(dip, 0, sizeof(*dip));
+      dip->type = type;
+      bwrite(bp);   // mark it allocated on the disk
+      brelse(bp);
+      return iget(dev, inum);
+    }
+    brelse(bp);
+  }
+  panic("ialloc: no inodes");
+}
+
+// Copy inode, which has changed, from memory to disk.
+void
+iupdate(struct inode *ip)
+{
+  struct buf *bp;
+  struct dinode *dip;
+
+  bp = bread(ip->dev, IBLOCK(ip->inum));
+  dip = (struct dinode*)bp->data + ip->inum%IPB;
+  dip->type = ip->type;
+  dip->major = ip->major;
+  dip->minor = ip->minor;
+  dip->nlink = ip->nlink;
+  dip->size = ip->size;
+  memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
+  bwrite(bp);
+  brelse(bp);
+}
+
 // Find the inode with number inum on device dev
 // and return the in-memory copy.
 static struct inode*
@@ -262,51 +309,6 @@ iunlockput(struct inode *ip)
   iput(ip);
 }
 
-//PAGEBREAK!
-// Allocate a new inode with the given type on device dev.
-struct inode*
-ialloc(uint dev, short type)
-{
-  int inum;
-  struct buf *bp;
-  struct dinode *dip;
-  struct superblock sb;
-
-  readsb(dev, &sb);
-  for(inum = 1; inum < sb.ninodes; inum++){  // loop over inode blocks
-    bp = bread(dev, IBLOCK(inum));
-    dip = (struct dinode*)bp->data + inum%IPB;
-    if(dip->type == 0){  // a free inode
-      memset(dip, 0, sizeof(*dip));
-      dip->type = type;
-      bwrite(bp);   // mark it allocated on the disk
-      brelse(bp);
-      return iget(dev, inum);
-    }
-    brelse(bp);
-  }
-  panic("ialloc: no inodes");
-}
-
-// Copy inode, which has changed, from memory to disk.
-void
-iupdate(struct inode *ip)
-{
-  struct buf *bp;
-  struct dinode *dip;
-
-  bp = bread(ip->dev, IBLOCK(ip->inum));
-  dip = (struct dinode*)bp->data + ip->inum%IPB;
-  dip->type = ip->type;
-  dip->major = ip->major;
-  dip->minor = ip->minor;
-  dip->nlink = ip->nlink;
-  dip->size = ip->size;
-  memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
-  bwrite(bp);
-  brelse(bp);
-}
-
 //PAGEBREAK!
 // Inode contents
 //
@@ -336,7 +338,6 @@ bmap(struct inode *ip, uint bn)
       ip->addrs[NDIRECT] = addr = balloc(ip->dev);
     bp = bread(ip->dev, addr);
     a = (uint*)bp->data;
-  
     if((addr = a[bn]) == 0){
       a[bn] = addr = balloc(ip->dev);
       bwrite(bp);
@@ -571,7 +572,7 @@ skipelem(char *path, char *name)
 // If parent != 0, return the inode for the parent and copy the final
 // path element into name, which must have room for DIRSIZ bytes.
 static struct inode*
-namex(char *path, int parent, char *name)
+namex(char *path, int nameiparent, char *name)
 {
   struct inode *ip, *next;
 
@@ -586,7 +587,7 @@ namex(char *path, int parent, char *name)
       iunlockput(ip);
       return 0;
     }
-    if(parent && *path == '\0'){
+    if(nameiparent && *path == '\0'){
       // Stop one level early.
       iunlock(ip);
       return ip;
@@ -598,7 +599,7 @@ namex(char *path, int parent, char *name)
     iunlockput(ip);
     ip = next;
   }
-  if(parent){
+  if(nameiparent){
     iput(ip);
     return 0;
   }
diff --git a/initcode.S b/initcode.S
index 984d29fdc25d53faa40f0ad5a2f54d3d090f4c43..41e84f419f7d96120a93c83b282aaf0dae3acee1 100644
--- a/initcode.S
+++ b/initcode.S
@@ -8,7 +8,7 @@
 start:
   pushl $argv
   pushl $init
-  pushl $0
+  pushl $0  // where caller pc would be
   movl $SYS_exec, %eax
   int $T_SYSCALL
 
diff --git a/kalloc.c b/kalloc.c
index 6c6ca7ee5ac1857f9bcf70411653fc7b47f8b836..2730d57f878c693a1d8088c3305fbca515edaf4c 100644
--- a/kalloc.c
+++ b/kalloc.c
@@ -22,21 +22,20 @@ struct {
 
 // Initialize free list of physical pages.
 // This code cheats by just considering one megabyte of
-// pages after _end.  Real systems would determine the
+// pages after end.  Real systems would determine the
 // amount of memory available in the system and use it all.
 void
 kinit(void)
 {
-  extern int end;
-  uint mem;
-  char *start;
+  extern char end[];
+  uint len;
+  char *p;
 
   initlock(&kmem.lock, "kmem");
-  start = (char*) &end;
-  start = (char*) (((uint)start + PAGE) & ~(PAGE-1));
-  mem = 256; // assume computer has 256 pages of RAM
-  cprintf("mem = %d\n", mem * PAGE);
-  kfree(start, mem * PAGE);
+  p = (char*)(((uint)end + PAGE) & ~(PAGE-1));
+  len = 256*PAGE; // assume computer has 256 pages of RAM, 1 MB
+  cprintf("mem = %d\n", len);
+  kfree(p, len);
 }
 
 // Free the len bytes of memory pointed at by v,
@@ -61,13 +60,7 @@ kfree(char *v, int len)
     rend = (struct run*)((char*)r + r->len);
     if(r <= p && p < rend)
       panic("freeing free page");
-    if(pend == r){  // p next to r: replace r with p
-      p->len = len + r->len;
-      p->next = r->next;
-      *rp = p;
-      goto out;
-    }
-    if(rend == p){  // r next to p: replace p with r
+    if(rend == p){  // r before p: expand r to include p
       r->len += len;
       if(r->next && r->next == pend){  // r now next to r->next?
         r->len += r->next->len;
@@ -75,6 +68,12 @@ kfree(char *v, int len)
       }
       goto out;
     }
+    if(pend == r){  // p before r: expand p to include, replace r
+      p->len = len + r->len;
+      p->next = r->next;
+      *rp = p;
+      goto out;
+    }
   }
   // Insert p before r in list.
   p->len = len;
@@ -99,14 +98,11 @@ kalloc(int n)
 
   acquire(&kmem.lock);
   for(rp=&kmem.freelist; (r=*rp) != 0; rp=&r->next){
-    if(r->len == n){
-      *rp = r->next;
-      release(&kmem.lock);
-      return (char*)r;
-    }
-    if(r->len > n){
+    if(r->len >= n){
       r->len -= n;
       p = (char*)r + r->len;
+      if(r->len == 0)
+        *rp = r->next;
       release(&kmem.lock);
       return p;
     }
diff --git a/sysfile.c b/sysfile.c
index efc42b00c1e7b925ff81612d2d728db82043c704..4d891c19a7695afd5daae52f5698dff0da9fa1be 100644
--- a/sysfile.c
+++ b/sysfile.c
@@ -44,6 +44,20 @@ fdalloc(struct file *f)
   return -1;
 }
 
+int
+sys_dup(void)
+{
+  struct file *f;
+  int fd;
+  
+  if(argfd(0, 0, &f) < 0)
+    return -1;
+  if((fd=fdalloc(f)) < 0)
+    return -1;
+  filedup(f);
+  return fd;
+}
+
 int
 sys_read(void)
 {
@@ -68,20 +82,6 @@ sys_write(void)
   return filewrite(f, p, n);
 }
 
-int
-sys_dup(void)
-{
-  struct file *f;
-  int fd;
-  
-  if(argfd(0, 0, &f) < 0)
-    return -1;
-  if((fd=fdalloc(f)) < 0)
-    return -1;
-  filedup(f);
-  return fd;
-}
-
 int
 sys_close(void)
 {
@@ -225,17 +225,15 @@ create(char *path, short type, short major, short minor)
   if((ip = dirlookup(dp, name, &off)) != 0){
     iunlockput(dp);
     ilock(ip);
-    if(ip->type != type || type != T_FILE){
-      iunlockput(ip);
-      return 0;
-    }
-    return ip;
-  }
-
-  if((ip = ialloc(dp->dev, type)) == 0){
-    iunlockput(dp);
+    if(type == T_FILE && ip->type == T_FILE)
+      return ip;
+    iunlockput(ip);
     return 0;
   }
+
+  if((ip = ialloc(dp->dev, type)) == 0)
+    panic("create: ialloc");
+
   ilock(ip);
   ip->major = major;
   ip->minor = minor;
@@ -298,6 +296,18 @@ sys_open(void)
   return fd;
 }
 
+int
+sys_mkdir(void)
+{
+  char *path;
+  struct inode *ip;
+
+  if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0)
+    return -1;
+  iunlockput(ip);
+  return 0;
+}
+
 int
 sys_mknod(void)
 {
@@ -315,18 +325,6 @@ sys_mknod(void)
   return 0;
 }
 
-int
-sys_mkdir(void)
-{
-  char *path;
-  struct inode *ip;
-
-  if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0)
-    return -1;
-  iunlockput(ip);
-  return 0;
-}
-
 int
 sys_chdir(void)
 {