From 7c1810e1ae9268581de6bec30cdb696c25bae030 Mon Sep 17 00:00:00 2001
From: Robert Morris <rtm@csail.mit.edu>
Date: Tue, 23 Aug 2022 12:26:26 -0400
Subject: [PATCH] tolerate running out of inodes

---
 kernel/fs.c      |  6 ++++--
 kernel/sysfile.c |  6 ++++--
 user/usertests.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/kernel/fs.c b/kernel/fs.c
index b220491..dea5864 100644
--- a/kernel/fs.c
+++ b/kernel/fs.c
@@ -193,7 +193,8 @@ static struct inode* iget(uint dev, uint inum);
 
 // Allocate an inode on device dev.
 // Mark it as allocated by  giving it type type.
-// Returns an unlocked but allocated and referenced inode.
+// Returns an unlocked but allocated and referenced inode,
+// or NULL if there is no free inode..
 struct inode*
 ialloc(uint dev, short type)
 {
@@ -213,7 +214,8 @@ ialloc(uint dev, short type)
     }
     brelse(bp);
   }
-  panic("ialloc: no inodes");
+  printf("ialloc: no inodes\n");
+  return 0;
 }
 
 // Copy a modified in-memory inode to disk.
diff --git a/kernel/sysfile.c b/kernel/sysfile.c
index d8a6fca..16b668c 100644
--- a/kernel/sysfile.c
+++ b/kernel/sysfile.c
@@ -262,8 +262,10 @@ create(char *path, short type, short major, short minor)
     return 0;
   }
 
-  if((ip = ialloc(dp->dev, type)) == 0)
-    panic("create: ialloc");
+  if((ip = ialloc(dp->dev, type)) == 0){
+    iunlockput(dp);
+    return 0;
+  }
 
   ilock(ip);
   ip->major = major;
diff --git a/user/usertests.c b/user/usertests.c
index 23a5048..4f183a5 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -2750,6 +2750,7 @@ diskfull(char *s)
     unlink(name);
     int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
     if(fd < 0){
+      // oops, ran out of inodes before running out of blocks.
       printf("%s: could not create file %s\n", s, name);
       done = 1;
       break;
@@ -2767,7 +2768,8 @@ diskfull(char *s)
 
   // now that there are no free blocks, test that dirlink()
   // merely fails (doesn't panic) if it can't extend
-  // directory content.
+  // directory content. one of these file creations
+  // is expected to fail.
   int nzz = 128;
   for(int i = 0; i < nzz; i++){
     char name[32];
@@ -2778,14 +2780,15 @@ diskfull(char *s)
     name[4] = '\0';
     unlink(name);
     int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
-    if(fd < 0){
-      printf("%s: could not create file %s\n", s, name);
+    if(fd < 0)
       break;
-    }
     close(fd);
   }
 
-  mkdir("diskfulldir");
+  // this mkdir() is expected to fail.
+  if(mkdir("diskfulldir") == 0)
+    printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n");
+
   unlink("diskfulldir");
 
   for(int i = 0; i < nzz; i++){
@@ -2809,6 +2812,37 @@ diskfull(char *s)
   }
 }
 
+void
+outofinodes(char *s)
+{
+  int nzz = 32*32;
+  for(int i = 0; i < nzz; i++){
+    char name[32];
+    name[0] = 'z';
+    name[1] = 'z';
+    name[2] = '0' + (i / 32);
+    name[3] = '0' + (i % 32);
+    name[4] = '\0';
+    unlink(name);
+    int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
+    if(fd < 0){
+      // failure is eventually expected.
+      break;
+    }
+    close(fd);
+  }
+
+  for(int i = 0; i < nzz; i++){
+    char name[32];
+    name[0] = 'z';
+    name[1] = 'z';
+    name[2] = '0' + (i / 32);
+    name[3] = '0' + (i % 32);
+    name[4] = '\0';
+    unlink(name);
+  }
+}
+
 //
 // use sbrk() to count how many free physical memory pages there are.
 // touches the pages to force allocation.
@@ -2986,6 +3020,7 @@ main(int argc, char *argv[])
     {badarg, "badarg" },
     {execout, "execout"},
     {diskfull, "diskfull"},
+    {outofinodes, "outofinodes"},
 
     { 0, 0},
   };