diff --git a/bootmain.c b/bootmain.c
index 1882aa8647daffed68105ad99998207d7e939e94..6494c16422c7b5ceba076391ce8c863af20acb5f 100644
--- a/bootmain.c
+++ b/bootmain.c
@@ -12,7 +12,7 @@
 // BOOT UP STEPS
 //  * when the CPU boots it loads the BIOS into memory and executes it
 //
-//  * the BIOS intializes devices, sets of the interrupt routines, and
+//  * the BIOS intializes devices, sets up the interrupt routines, and
 //    reads the first sector of the boot device(e.g., hard-drive)
 //    into memory and jumps to it.
 //
diff --git a/fs.c b/fs.c
index e47b6fa352774fe36d063bcee0737ac23aae87c4..a6e1787d880877e27ff3ed9da48aa5fe0e4ac9ee 100644
--- a/fs.c
+++ b/fs.c
@@ -475,6 +475,7 @@ namecmp(const char *s, const char *t)
 
 // Look for a directory entry in a directory.
 // If found, set *poff to byte offset of entry.
+// Caller must have already locked dp.
 struct uinode*
 dirlookup(struct inode *dp, char *name, uint *poff)
 {
@@ -483,7 +484,7 @@ dirlookup(struct inode *dp, char *name, uint *poff)
   struct dirent *de;
 
   if(dp->type != T_DIR)
-    return 0;
+    panic("dirlookup not DIR");
 
   for(off = 0; off < dp->size; off += BSIZE){
     bp = bread(dp->dev, bmap(dp, off / BSIZE, 0));
@@ -558,7 +559,7 @@ dirlink(struct inode *dp, char *name, uint ino)
 //
 // Examples:
 //   skipelem("a/bb/c", name) = "bb/c", setting name = "a"
-//   skipelem("///a/bb", name) = "b", setting name="a"
+//   skipelem("///a/bb", name) = "bb", setting name="a"
 //   skipelem("", name) = skipelem("////", name) = 0
 //
 static char*
@@ -617,14 +618,15 @@ _namei(char *path, int parent, char *name)
 
     if((ipu = dirlookup(dp, name, &off)) == 0){
       iput(iunlock(dp));
-      iput(ipu);
       return 0;
     }
     iput(iunlock(dp));
     dpu = ipu;
   }
-  if(parent)
+  if(parent){
+    iput(dpu);
     return 0;
+  }
   return dpu;
 }
 
diff --git a/mkfs.c b/mkfs.c
index 462c2700d95da5a167d8a0b1e5063ebfe98cb558..b367f617a52c5a1fbbd3343baba2f76dd1a9c106 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -8,8 +8,8 @@
 #include "param.h"
 #include "fs.h"
 
-int nblocks = 1008;
-int ninodes = 100;
+int nblocks = 995;
+int ninodes = 200;
 int size = 1024;
 
 int fsfd;
diff --git a/param.h b/param.h
index 7ceecb59de2712deb0547aa6a7ab4c4c789662bb..343288cf01cca1916c35f2d9900d7aa0cc7cd608 100644
--- a/param.h
+++ b/param.h
@@ -6,6 +6,6 @@
 #define NFILE       100  // open files per system
 #define NBUF         10  // size of disk block cache
 #define NREQUEST   NBUF  // outstanding disk requests
-#define NINODE      100  // maximum number of active i-nodes
+#define NINODE       50  // maximum number of active i-nodes
 #define NDEV         10  // maximum major device number
 #define ROOTDEV       1  // device number of file system root disk
diff --git a/proc.h b/proc.h
index 9750c159d2c977e127ce59ce799593c60bd93259..137bda3265c836e6cd7887bb5b0a5cd980838a4e 100644
--- a/proc.h
+++ b/proc.h
@@ -43,19 +43,15 @@ struct proc {
   char name[16];            // Process name (debugging)
 };
 
-// Process memory is laid out contiguously:
+// Process memory is laid out contiguously, low addresses first:
 //   text
 //   original data and bss
 //   fixed-size stack
 //   expandable heap
 
-// If xv6 was only for uniprocessors, this could be
-//   struct proc *cp;
-// Instead we have an array curproc, one per
-// processor, and #define cp to the right element
-// in the array.  In general such preprocessor 
-// subterfuge is to be avoided, but cp is used 
-// so often that having the shorthand is worth the ugliness.
+// Arrange that cp point to the struct proc that this
+// CPU is currently running.  Such preprocessor 
+// subterfuge can be confusing, but saves a lot of typing.
 extern struct proc *curproc[NCPU];  // Current (running) process per CPU
 #define cp (curproc[cpu()])  // Current process on this CPU
 
diff --git a/runoff b/runoff
index 092c8b6846d38f2deedcda45619280f84362e085..386939198b8d734c2ee0937ed0dfc89d2df82e3b 100755
--- a/runoff
+++ b/runoff
@@ -18,7 +18,7 @@ files=`grep -v '^#' runoff.list | awk '{print $1}'`
 n=99
 for i in $files
 do
-	runoff1 -n $n $i >fmt/$i
+	./runoff1 -n $n $i >fmt/$i
 	nn=`tail -1 fmt/$i | sed 's/ .*//; s/^0*//'`
 	if [ "x$nn" != x ]; then
 		n=$nn
diff --git a/usertests.c b/usertests.c
index 71326668dfb44fb313e3918cf4c094411cb82cec..3a9cd9aad9e9f9af299682904be08a29a4efe111 100644
--- a/usertests.c
+++ b/usertests.c
@@ -1096,6 +1096,99 @@ rmdot(void)
   printf(1, "rmdot ok\n");
 }
 
+void
+dirfile(void)
+{
+  int fd;
+
+  printf(1, "dir vs file\n");
+
+  fd = open("dirfile", O_CREATE);
+  if(fd < 0){
+    printf(1, "create dirfile failed\n");
+    exit();
+  }
+  close(fd);
+  if(chdir("dirfile") == 0){
+    printf(1, "chdir dirfile succeeded!\n");
+    exit();
+  }
+  fd = open("dirfile/xx", 0);
+  if(fd >= 0){
+    printf(1, "create dirfile/xx succeeded!\n");
+    exit();
+  }
+  fd = open("dirfile/xx", O_CREATE);
+  if(fd >= 0){
+    printf(1, "create dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(mkdir("dirfile/xx") == 0){
+    printf(1, "mkdir dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(unlink("dirfile/xx") == 0){
+    printf(1, "unlink dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(link("README", "dirfile/xx") == 0){
+    printf(1, "link to dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(unlink("dirfile") != 0){
+    printf(1, "unlink dirfile failed!\n");
+    exit();
+  }
+
+  fd = open(".", O_RDWR);
+  if(fd >= 0){
+    printf(1, "open . for writing succeeded!\n");
+    exit();
+  }
+  fd = open(".", 0);
+  if(write(fd, "x", 1) > 0){
+    printf(1, "write . succeeded!\n");
+    exit();
+  }
+  close(fd);
+
+  printf(1, "dir vs file OK\n");
+}
+
+// test that iput() is called at the end of _namei()
+void
+iref(void)
+{
+  int i, fd;
+
+  printf(1, "empty file name\n");
+
+  // the 50 is NINODE
+  for(i = 0; i < 50 + 1; i++){
+    if(mkdir("irefd") != 0){
+      printf(1, "mkdir irefd failed\n");
+      exit();
+    }
+    if(chdir("irefd") != 0){
+      printf(1, "chdir irefd failed\n");
+      exit();
+    }
+
+    mkdir("");
+    link("README", "");
+    fd = open("", O_CREATE);
+    if(fd >= 0)
+      close(fd);
+    fd = open("xx", O_CREATE);
+    if(fd >= 0)
+      close(fd);
+    unlink("xx");
+  }
+
+  chdir("/");
+  printf(1, "empty file name OK\n");
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -1128,6 +1221,8 @@ main(int argc, char *argv[])
   createdelete();
   twofiles();
   sharedfd();
+  dirfile();
+  iref();
 
   exectest();