Change list_elem from typedef to struct.
[pintos-anon] / src / filesys / inode.c
index 5ca91f157449b80c2afd29a1f00991da730d7fcd..749af375d8b8ae8ec42275df0688ff25ba5522e5 100644 (file)
@@ -2,27 +2,32 @@
 #include <bitmap.h>
 #include <list.h>
 #include <debug.h>
+#include <round.h>
 #include <stdio.h>
 #include "filesys/filesys.h"
 #include "threads/malloc.h"
 
-/* Number of direct sector pointers in an inode. */
-#define DIRECT_CNT ((DISK_SECTOR_SIZE - sizeof (off_t) - sizeof (size_t)) \
-                    / sizeof (disk_sector_t))
-
 /* On-disk inode.
-   It is exactly DISK_SECTOR_SIZE bytes long. */
+   Must be exactly DISK_SECTOR_SIZE bytes long. */
 struct inode_disk
   {
     off_t length;                       /* File size in bytes. */
-    size_t sector_cnt;                  /* File size in sectors. */
-    disk_sector_t sectors[DIRECT_CNT];  /* Sectors allocated for file. */
+    disk_sector_t start;                /* Starting sector. */
+    uint32_t unused[126];               /* Unused padding. */
   };
 
+/* Returns the number of sectors to allocate for a file SIZE
+   bytes long. */
+static inline size_t
+bytes_to_sectors (off_t size)
+{
+  return DIV_ROUND_UP (size, DISK_SECTOR_SIZE);
+}
+
 /* In-memory inode. */
 struct inode 
   {
-    list_elem elem;                     /* Element in inode list. */
+    struct list_elem elem;              /* Element in inode list. */
     disk_sector_t sector;               /* Sector number of disk location. */
     int open_cnt;                       /* Number of openers. */
     bool removed;                       /* True if deleted, false otherwise. */
@@ -31,9 +36,9 @@ struct inode
 
 /* List of open inodes, so that opening a single inode twice
    returns the same `struct inode'. */
-struct list open_inodes;
+static struct list open_inodes;
 
-static struct inode *alloc_inode (disk_sector_t);
+static void deallocate_inode (const struct inode *);
 
 /* Initializes the inode module. */
 void
@@ -42,63 +47,42 @@ inode_init (void)
   list_init (&open_inodes);
 }
 
-/* Allocates sectors from bitmap B for the content of a file
-   whose size is LENGTH bytes, and returns a new `struct inode'
-   properly initialized for the file.
-   It is the caller's responsible to write the inode to disk with
-   inode_commit(), as well as the bitmap.
-   If memory or disk allocation fails, returns a null pointer,
-   leaving bitmap B is unchanged. */
-struct inode *
-inode_create (struct bitmap *b, disk_sector_t sector, off_t length) 
+/* Initializes an inode for a file LENGTH bytes in size and
+   writes the new inode to sector SECTOR on the file system
+   disk.  Allocates sectors for the file from FREE_MAP.
+   Returns true if successful.
+   Returns false if memory or disk allocation fails.  FREE_MAP
+   may be modified regardless. */
+bool
+inode_create (struct bitmap *free_map, disk_sector_t sector, off_t length) 
 {
-  struct inode *idx;
-  size_t sector_cnt;
+  static const char zero_sector[DISK_SECTOR_SIZE];
+  struct inode_disk *idx;
+  size_t start;
+  size_t i;
 
-  ASSERT (b != NULL);
+  ASSERT (free_map != NULL);
   ASSERT (length >= 0);
 
-  /* Calculate number of sectors to allocate for file data. */
-  sector_cnt = (length / DISK_SECTOR_SIZE) + (length % DISK_SECTOR_SIZE > 0);
-  if (sector_cnt > DIRECT_CNT)
-    return NULL;
+  /* Allocate sectors. */
+  start = bitmap_scan_and_flip (free_map, 0, bytes_to_sectors (length), false);
+  if (start == BITMAP_ERROR)
+    return false;
 
-  /* Allocate inode. */
-  idx = alloc_inode (sector);
+  /* Create inode. */
+  idx = calloc (sizeof *idx, 1);
   if (idx == NULL)
-    return NULL;
+    return false;
+  idx->length = length;
+  idx->start = start;
 
-  /* Allocate disk sectors. */
-  idx->data.length = length;
-  while (idx->data.sector_cnt < sector_cnt)
-    {
-      size_t sector = bitmap_scan_and_flip (b, 0, 1, false);
-      if (sector == BITMAP_ERROR)
-        goto error;
+  /* Commit to disk. */
+  disk_write (filesys_disk, sector, idx);
+  for (i = 0; i < bytes_to_sectors (length); i++)
+    disk_write (filesys_disk, idx->start + i, zero_sector);
 
-      idx->data.sectors[idx->data.sector_cnt++] = sector;
-    }
-
-  /* Zero out the file contents. */
-  if (sector_cnt > 0) 
-    {
-      void *zero_sector;
-      size_t i;
-      
-      zero_sector = calloc (1, DISK_SECTOR_SIZE);
-      if (zero_sector == NULL)
-        goto error;
-      for (i = 0; i < sector_cnt; i++)
-        disk_write (filesys_disk, idx->data.sectors[i], zero_sector);
-      free (zero_sector);
-    }
-
-  return idx;
-
- error:
-  inode_remove (idx);
-  inode_close (idx);
-  return NULL;
+  free (idx);
+  return true;
 }
 
 /* Reads an inode from SECTOR
@@ -107,7 +91,7 @@ inode_create (struct bitmap *b, disk_sector_t sector, off_t length)
 struct inode *
 inode_open (disk_sector_t sector) 
 {
-  list_elem *e;
+  struct list_elem *e;
   struct inode *idx;
 
   /* Check whether this inode is already open.
@@ -125,11 +109,17 @@ inode_open (disk_sector_t sector)
         }
     }
 
-  /* Allocate inode. */
-  idx = alloc_inode (sector);
+  /* Allocate memory. */
+  idx = calloc (1, sizeof *idx);
   if (idx == NULL)
     return NULL;
 
+  /* Initialize. */
+  list_push_front (&open_inodes, &idx->elem);
+  idx->sector = sector;
+  idx->open_cnt = 1;
+  idx->removed = false;
+
   /* Read from disk. */
   ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
   disk_read (filesys_disk, sector, &idx->data);
@@ -143,43 +133,39 @@ inode_open (disk_sector_t sector)
 void
 inode_close (struct inode *idx) 
 {
+  /* Ignore null pointer. */
   if (idx == NULL)
     return;
 
+  /* Release resources if this was the last opener. */
   if (--idx->open_cnt == 0)
     {
-      if (idx->removed) 
-        {
-          struct bitmap *free_map;
-          size_t i;
-
-          free_map = bitmap_create (disk_size (filesys_disk));
-          if (free_map != NULL)
-            {
-              bitmap_read (free_map, free_map_file);
-              
-              bitmap_reset (free_map, idx->sector);
-              for (i = 0; i < idx->data.sector_cnt; i++)
-                bitmap_reset (free_map, idx->data.sectors[i]);
-
-              bitmap_write (free_map, free_map_file);
-              bitmap_destroy (free_map);
-            }
-          else
-            printf ("inode_close(): can't free blocks");
-        }
+      /* Deallocate blocks if removed. */
+      if (idx->removed)
+        deallocate_inode (idx);
+
+      /* Remove from inode list and free memory. */
       list_remove (&idx->elem);
       free (idx); 
     }
 }
 
-/* Writes IDX to disk. */
-void
-inode_commit (const struct inode *idx) 
+/* Deallocates the blocks allocated for IDX. */
+static void
+deallocate_inode (const struct inode *idx)
 {
-  ASSERT (idx != NULL);
-  ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
-  disk_write (filesys_disk, idx->sector, &idx->data);
+  struct bitmap *free_map = bitmap_create (disk_size (filesys_disk));
+  if (free_map != NULL) 
+    {
+      bitmap_read (free_map, free_map_file);
+      bitmap_reset (free_map, idx->sector);
+      bitmap_set_multiple (free_map, idx->data.start,
+                           bytes_to_sectors (idx->data.length), false);
+      bitmap_write (free_map, free_map_file);
+      bitmap_destroy (free_map);
+    }
+  else
+    printf ("inode_close(): can't free blocks");
 }
 
 /* Marks IDX to be deleted when it is closed by the last caller who
@@ -198,12 +184,9 @@ inode_remove (struct inode *idx)
 disk_sector_t
 inode_byte_to_sector (const struct inode *idx, off_t pos) 
 {
-  size_t i;
-
   ASSERT (idx != NULL);
-
-  i = pos / DISK_SECTOR_SIZE;
-  return i < idx->data.sector_cnt ? idx->data.sectors[i] : (disk_sector_t) -1;
+  ASSERT (pos < idx->data.length);
+  return idx->data.start + pos / DISK_SECTOR_SIZE;
 }
 
 /* Returns the length, in bytes, of the file with inode IDX. */
@@ -218,36 +201,10 @@ inode_length (const struct inode *idx)
 void
 inode_print (const struct inode *idx) 
 {
-  size_t i;
-  
-  printf ("Inode %"PRDSNu": %"PRDSNu" bytes, %zu sectors (",
-          idx->sector, idx->data.length, idx->data.sector_cnt);
-
-  /* This loop could be unsafe for large idx->data.sector_cnt, can
-     you see why? */
-  for (i = 0; i < idx->data.sector_cnt; i++) 
-    {
-      if (i != 0)
-        printf (", ");
-      printf ("%"PRDSNu, idx->data.sectors[i]); 
-    }
-  printf (")\n");
-}
-\f
-/* Returns a newly allocated and initialized inode. */
-static struct inode *
-alloc_inode (disk_sector_t sector) 
-{
-  /* Allocate memory. */
-  struct inode *idx = calloc (1, sizeof *idx);
-  if (idx == NULL)
-    return NULL;
-
-  /* Initialize. */
-  list_push_front (&open_inodes, &idx->elem);
-  idx->sector = sector;
-  idx->open_cnt = 1;
-  idx->removed = false;
-
-  return idx;
+  ASSERT (idx != NULL);
+  printf ("Inode %"PRDSNu": %"PRDSNu" bytes, "
+          "%zu sectors starting at %"PRDSNu"\n",
+          idx->sector, idx->data.length,
+          (size_t) DIV_ROUND_UP (idx->data.length, DISK_SECTOR_SIZE),
+          idx->data.start);
 }