summaryrefslogtreecommitdiffstats
path: root/src/filesys
diff options
context:
space:
mode:
Diffstat (limited to 'src/filesys')
-rw-r--r--src/filesys/file.c7
-rw-r--r--src/filesys/filesys.c19
-rw-r--r--src/filesys/free-map.c10
-rw-r--r--src/filesys/inode.c45
4 files changed, 72 insertions, 9 deletions
diff --git a/src/filesys/file.c b/src/filesys/file.c
index d5fc10d..238806a 100644
--- a/src/filesys/file.c
+++ b/src/filesys/file.c
@@ -155,7 +155,12 @@ file_seek (struct file *file, off_t new_pos)
{
ASSERT (file != NULL);
ASSERT (new_pos >= 0);
- file->pos = new_pos;
+ off_t size = inode_length (file->inode);
+ if (new_pos < size) {
+ file->pos = new_pos;
+ } else {
+ file->pos = size;
+ }
}
/* Returns the current position in FILE as a byte offset from the
diff --git a/src/filesys/filesys.c b/src/filesys/filesys.c
index fedda08..d30f728 100644
--- a/src/filesys/filesys.c
+++ b/src/filesys/filesys.c
@@ -7,6 +7,11 @@
#include "filesys/inode.h"
#include "filesys/directory.h"
#include "devices/disk.h"
+#include "threads/synch.h"
+
+/* Locks filesys_create so the same file isn't
+ created twice with the same name. */
+static struct lock create_lock;
/* The disk that contains the file system. */
struct disk *filesys_disk;
@@ -22,6 +27,8 @@ filesys_init (bool format)
if (filesys_disk == NULL)
PANIC ("hd0:1 (hdb) not present, file system initialization failed");
+ lock_init (&create_lock);
+
inode_init ();
free_map_init ();
@@ -48,12 +55,14 @@ filesys_create (const char *name, off_t initial_size)
{
disk_sector_t inode_sector = 0;
struct dir *dir = dir_open_root ();
+ lock_acquire (&create_lock);
bool success = (dir != NULL
- && free_map_allocate (1, &inode_sector)
- && inode_create (inode_sector, initial_size)
- && dir_add (dir, name, inode_sector));
- if (!success && inode_sector != 0)
- free_map_release (inode_sector, 1);
+ && free_map_allocate (1, &inode_sector) // find sector
+ && inode_create (inode_sector, initial_size) // create inode pointing to sector
+ && dir_add (dir, name, inode_sector)); // add dir entry pointing to inode
+ lock_release (&create_lock);
+ if (!success && inode_sector != 0) // oops, we got a sector but file creation failed
+ free_map_release (inode_sector, 1); // so deallocate the sector
dir_close (dir);
return success;
diff --git a/src/filesys/free-map.c b/src/filesys/free-map.c
index 1cd9175..8b8aeae 100644
--- a/src/filesys/free-map.c
+++ b/src/filesys/free-map.c
@@ -4,8 +4,11 @@
#include "filesys/file.h"
#include "filesys/filesys.h"
#include "filesys/inode.h"
+#include "threads/synch.h"
static struct file *free_map_file; /* Free map file. */
+
+static struct lock free_map_lock;
static struct bitmap *free_map; /* Free map, one bit per disk sector. */
/* Initializes the free map. */
@@ -15,6 +18,7 @@ free_map_init (void)
free_map = bitmap_create (disk_size (filesys_disk));
if (free_map == NULL)
PANIC ("bitmap creation failed--disk is too large");
+ lock_init (&free_map_lock);
bitmap_mark (free_map, FREE_MAP_SECTOR);
bitmap_mark (free_map, ROOT_DIR_SECTOR);
}
@@ -26,6 +30,7 @@ free_map_init (void)
bool
free_map_allocate (size_t cnt, disk_sector_t *sectorp)
{
+ lock_acquire (&free_map_lock);
disk_sector_t sector = bitmap_scan_and_flip (free_map, 0, cnt, false);
if (sector != BITMAP_ERROR
&& free_map_file != NULL
@@ -34,6 +39,7 @@ free_map_allocate (size_t cnt, disk_sector_t *sectorp)
bitmap_set_multiple (free_map, sector, cnt, false);
sector = BITMAP_ERROR;
}
+ lock_release (&free_map_lock);
if (sector != BITMAP_ERROR)
*sectorp = sector;
return sector != BITMAP_ERROR;
@@ -43,9 +49,11 @@ free_map_allocate (size_t cnt, disk_sector_t *sectorp)
void
free_map_release (disk_sector_t sector, size_t cnt)
{
+ lock_acquire (&free_map_lock);
ASSERT (bitmap_all (free_map, sector, cnt));
bitmap_set_multiple (free_map, sector, cnt, false);
bitmap_write (free_map, free_map_file);
+ lock_release (&free_map_lock);
}
/* Opens the free map file and reads it from disk. */
@@ -55,8 +63,10 @@ free_map_open (void)
free_map_file = file_open (inode_open (FREE_MAP_SECTOR));
if (free_map_file == NULL)
PANIC ("can't open free map");
+ lock_acquire (&free_map_lock);
if (!bitmap_read (free_map, free_map_file))
PANIC ("can't read free map");
+ lock_release (&free_map_lock);
}
/* Writes the free map to disk and closes the free map file. */
diff --git a/src/filesys/inode.c b/src/filesys/inode.c
index cfdcb7b..dca5432 100644
--- a/src/filesys/inode.c
+++ b/src/filesys/inode.c
@@ -6,6 +6,7 @@
#include "filesys/filesys.h"
#include "filesys/free-map.h"
#include "threads/malloc.h"
+#include "threads/synch.h"
/* Identifies an inode. */
#define INODE_MAGIC 0x494e4f44
@@ -31,11 +32,14 @@ bytes_to_sectors (off_t size)
/* In-memory inode. */
struct inode
{
+ struct lock lock; /* Lock for inode metadata. */
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. */
int deny_write_cnt; /* 0: writes ok, >0: deny writes. */
+
+ struct rwlock rwlock; /* RwLock for inode_disk data. */
struct inode_disk data; /* Inode content. */
};
@@ -53,6 +57,9 @@ byte_to_sector (const struct inode *inode, off_t pos)
return -1;
}
+/* Lock the open inode list since so inode_open doesn't race. */
+struct lock open_inodes_lock;
+
/* List of open inodes, so that opening a single inode twice
returns the same `struct inode'. */
static struct list open_inodes;
@@ -62,6 +69,7 @@ void
inode_init (void)
{
list_init (&open_inodes);
+ lock_init (&open_inodes_lock);
}
/* Initializes an inode with LENGTH bytes of data and
@@ -114,6 +122,7 @@ inode_open (disk_sector_t sector)
struct list_elem *e;
struct inode *inode;
+ lock_acquire (&open_inodes_lock);
/* Check whether this inode is already open. */
for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
e = list_next (e))
@@ -122,22 +131,30 @@ inode_open (disk_sector_t sector)
if (inode->sector == sector)
{
inode_reopen (inode);
+ lock_release (&open_inodes_lock);
return inode;
}
}
/* Allocate memory. */
inode = malloc (sizeof *inode);
- if (inode == NULL)
+ if (inode == NULL) {
+ lock_release (&open_inodes_lock);
return NULL;
+ }
/* Initialize. */
+ lock_init (&inode->lock);
+ lock_acquire (&inode->lock);
list_push_front (&open_inodes, &inode->elem);
+ lock_release (&open_inodes_lock);
inode->sector = sector;
inode->open_cnt = 1;
inode->deny_write_cnt = 0;
inode->removed = false;
+ rwlock_init (&inode->rwlock);
disk_read (filesys_disk, inode->sector, &inode->data);
+ lock_release (&inode->lock);
return inode;
}
@@ -147,8 +164,10 @@ inode_reopen (struct inode *inode)
{
if (inode != NULL)
{
+ lock_acquire (&inode->lock);
ASSERT(inode->open_cnt != 0);
inode->open_cnt++;
+ lock_release (&inode->lock);
}
return inode;
}
@@ -170,11 +189,17 @@ inode_close (struct inode *inode)
if (inode == NULL)
return;
+ lock_acquire (&inode->lock);
+
/* Release resources if this was the last opener. */
- if (--inode->open_cnt == 0)
+ if (--inode->open_cnt > 0)
{
- /* Remove from inode list and release lock. */
+ lock_release (&inode->lock);
+ } else {
+ /* Remove from inode list. */
+ lock_acquire (&open_inodes_lock);
list_remove (&inode->elem);
+ lock_release (&open_inodes_lock);
/* Deallocate blocks if removed. */
if (inode->removed)
@@ -194,7 +219,9 @@ void
inode_remove (struct inode *inode)
{
ASSERT (inode != NULL);
+ lock_acquire (&inode->lock);
inode->removed = true;
+ lock_release (&inode->lock);
}
/* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
@@ -207,6 +234,8 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
off_t bytes_read = 0;
uint8_t *bounce = NULL;
+ rwlock_read_p (&inode->rwlock);
+
while (size > 0)
{
/* Disk sector to read, starting byte offset within sector. */
@@ -247,6 +276,8 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
offset += chunk_size;
bytes_read += chunk_size;
}
+
+ rwlock_read_v (&inode->rwlock);
free (bounce);
return bytes_read;
@@ -268,6 +299,8 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
if (inode->deny_write_cnt)
return 0;
+ rwlock_write_p (&inode->rwlock);
+
while (size > 0)
{
/* Sector to write, starting byte offset within sector. */
@@ -315,6 +348,8 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
offset += chunk_size;
bytes_written += chunk_size;
}
+
+ rwlock_write_v (&inode->rwlock);
free (bounce);
return bytes_written;
@@ -325,8 +360,10 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
void
inode_deny_write (struct inode *inode)
{
+ lock_acquire (&inode->lock);
inode->deny_write_cnt++;
ASSERT (inode->deny_write_cnt <= inode->open_cnt);
+ lock_release (&inode->lock);
}
/* Re-enables writes to INODE.
@@ -335,9 +372,11 @@ inode_deny_write (struct inode *inode)
void
inode_allow_write (struct inode *inode)
{
+ lock_acquire (&inode->lock);
ASSERT (inode->deny_write_cnt > 0);
ASSERT (inode->deny_write_cnt <= inode->open_cnt);
inode->deny_write_cnt--;
+ lock_release (&inode->lock);
}
/* Returns the length, in bytes, of INODE's data. */