diff options
Diffstat (limited to 'src/filesys')
| -rw-r--r-- | src/filesys/file.c | 7 | ||||
| -rw-r--r-- | src/filesys/filesys.c | 19 | ||||
| -rw-r--r-- | src/filesys/free-map.c | 10 | ||||
| -rw-r--r-- | src/filesys/inode.c | 45 |
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. */ |
