From 8621be8f3d105cd73ffbc681f9810d04b083b0ae Mon Sep 17 00:00:00 2001
From: Robert Morris <rtm@csail.mit.edu>
Date: Tue, 23 Aug 2022 08:52:15 -0400
Subject: [PATCH] tolerate out of disk when creating . and .. in mkdir()

---
 kernel/sysfile.c | 25 ++++++++++++++++---------
 user/usertests.c |  5 +++++
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/kernel/sysfile.c b/kernel/sysfile.c
index 4c0470e..d8a6fca 100644
--- a/kernel/sysfile.c
+++ b/kernel/sysfile.c
@@ -272,24 +272,31 @@ create(char *path, short type, short major, short minor)
   iupdate(ip);
 
   if(type == T_DIR){  // Create . and .. entries.
-    dp->nlink++;  // for ".."
-    iupdate(dp);
     // No ip->nlink++ for ".": avoid cyclic ref count.
     if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
-      panic("create dots");
+      goto fail;
   }
 
-  if(dirlink(dp, name, ip->inum) < 0){
-    // oops. we don't need ip after all.
-    ip->nlink = 0;
-    iupdate(ip);
-    iunlockput(ip);
-    ip = 0;
+  if(dirlink(dp, name, ip->inum) < 0)
+    goto fail;
+
+  if(type == T_DIR){
+    // now that success is guaranteed:
+    dp->nlink++;  // for ".."
+    iupdate(dp);
   }
 
   iunlockput(dp);
 
   return ip;
+
+ fail:
+  // something went wrong. de-allocate ip.
+  ip->nlink = 0;
+  iupdate(ip);
+  iunlockput(ip);
+  iunlockput(dp);
+  return 0;
 }
 
 uint64
diff --git a/user/usertests.c b/user/usertests.c
index 968034a..60d1762 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -2712,6 +2712,8 @@ diskfull(char *s)
 {
   int fi;
   int done = 0;
+
+  unlink("diskfulldir");
   
   for(fi = 0; done == 0; fi++){
     char name[32];
@@ -2758,6 +2760,9 @@ diskfull(char *s)
     close(fd);
   }
 
+  mkdir("diskfulldir");
+  unlink("diskfulldir");
+
   for(int i = 0; i < nzz; i++){
     char name[32];
     name[0] = 'z';