summaryrefslogtreecommitdiffstats
path: root/src/filesys/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/filesys/inode.c')
-rw-r--r--src/filesys/inode.c45
1 files changed, 42 insertions, 3 deletions
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. */