1 diff --git a/src/Makefile.build b/src/Makefile.build
2 index 1057023..05e888c 100644
3 --- a/src/Makefile.build
4 +++ b/src/Makefile.build
5 @@ -73,6 +73,7 @@ filesys_SRC += filesys/file.c # Files.
6 filesys_SRC += filesys/directory.c # Directories.
7 filesys_SRC += filesys/inode.c # File headers.
8 filesys_SRC += filesys/fsutil.c # Utilities.
9 +filesys_SRC += filesys/cache.c # Cache.
11 SOURCES = $(foreach dir,$(KERNEL_SUBDIRS),$($(dir)_SRC))
12 OBJECTS = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SOURCES)))
13 diff --git a/src/filesys/Make.vars b/src/filesys/Make.vars
14 index b3aa005..d04ab67 100644
15 --- a/src/filesys/Make.vars
16 +++ b/src/filesys/Make.vars
17 @@ -7,7 +7,7 @@ GRADING_FILE = $(SRCDIR)/tests/filesys/Grading.no-vm
20 # Uncomment the lines below to enable VM.
21 -#kernel.bin: DEFINES += -DVM
22 -#KERNEL_SUBDIRS += vm
23 -#TEST_SUBDIRS += tests/vm
24 -#GRADING_FILE = $(SRCDIR)/tests/filesys/Grading.with-vm
25 +kernel.bin: DEFINES += -DVM
27 +TEST_SUBDIRS += tests/vm
28 +GRADING_FILE = $(SRCDIR)/tests/filesys/Grading.with-vm
29 diff --git a/src/filesys/cache.c b/src/filesys/cache.c
31 index 0000000..cd2ff1c
33 +++ b/src/filesys/cache.c
35 +#include "filesys/cache.h"
38 +#include "filesys/filesys.h"
39 +#include "devices/timer.h"
40 +#include "threads/malloc.h"
41 +#include "threads/synch.h"
42 +#include "threads/thread.h"
44 +#define INVALID_SECTOR ((block_sector_t) -1)
46 +/* A cached block. */
49 + /* Locking to prevent eviction. */
50 + struct lock block_lock; /* Protects fields in group. */
51 + struct condition no_readers_or_writers; /* readers == 0 && writers == 0 */
52 + struct condition no_writers; /* writers == 0 */
53 + int readers, read_waiters; /* # of readers, # waiting to read. */
54 + int writers, write_waiters; /* # of writers (<= 1), # waiting to write. */
56 + /* Sector number. INVALID_SECTOR indicates a free cache block.
58 + Changing from free to allocated requires cache_sync.
60 + Changing from allocated to free requires block_lock, block
61 + must be up-to-date and not dirty, and no one may be
63 + block_sector_t sector;
65 + /* Is data[] correct?
66 + Requires write lock or data_lock. */
69 + /* Does data[] need to be written back to disk?
70 + Valid only when up-to-date.
71 + Requires read lock or write lock or data_lock. */
75 + Access to data[] requires up-to-date and read or write lock.
76 + Bringing up-to-date requires write lock or data_lock. */
77 + struct lock data_lock; /* Protects fields in group. */
78 + uint8_t data[BLOCK_SECTOR_SIZE]; /* Disk data. */
83 +struct cache_block cache[CACHE_CNT];
87 + Required to allocate a cache block to a sector, to prevent a
88 + single sector being allocated two different cache blocks.
90 + Required to search the cache for a sector, to prevent the
91 + sector from being added while the search is ongoing.
94 +struct lock cache_sync;
96 +/* Cache eviction hand.
97 + Protected by cache_sync. */
100 +static void flushd_init (void);
101 +static void readaheadd_init (void);
102 +static void readaheadd_submit (block_sector_t sector);
104 +/* Initializes cache. */
110 + lock_init (&cache_sync);
111 + for (i = 0; i < CACHE_CNT; i++)
113 + struct cache_block *b = &cache[i];
114 + lock_init (&b->block_lock);
115 + cond_init (&b->no_readers_or_writers);
116 + cond_init (&b->no_writers);
117 + b->readers = b->read_waiters = 0;
118 + b->writers = b->write_waiters = 0;
119 + b->sector = INVALID_SECTOR;
120 + lock_init (&b->data_lock);
124 + readaheadd_init ();
127 +/* Flushes cache to disk. */
133 + for (i = 0; i < CACHE_CNT; i++)
135 + struct cache_block *b = &cache[i];
136 + block_sector_t sector;
138 + lock_acquire (&b->block_lock);
139 + sector = b->sector;
140 + lock_release (&b->block_lock);
142 + if (sector == INVALID_SECTOR)
145 + b = cache_lock (sector, EXCLUSIVE);
146 + if (b->up_to_date && b->dirty)
148 + block_write (fs_device, b->sector, b->data);
155 +/* Locks the given SECTOR into the cache and returns the cache
157 + If TYPE is EXCLUSIVE, then the block returned will be locked
158 + only by the caller. The calling thread must not already
159 + have any lock on the block.
160 + If TYPE is NON_EXCLUSIVE, then block returned may be locked by
161 + any number of other callers. The calling thread may already
162 + have any number of non-exclusive locks on the block. */
163 +struct cache_block *
164 +cache_lock (block_sector_t sector, enum lock_type type)
169 + lock_acquire (&cache_sync);
171 + /* Is the block already in-cache? */
172 + for (i = 0; i < CACHE_CNT; i++)
174 + /* Skip any blocks that don't hold SECTOR. */
175 + struct cache_block *b = &cache[i];
176 + lock_acquire (&b->block_lock);
177 + if (b->sector != sector)
179 + lock_release (&b->block_lock);
182 + lock_release (&cache_sync);
184 + /* Get read or write lock. */
185 + if (type == NON_EXCLUSIVE)
187 + /* Lock for read. */
189 + if (b->writers || b->write_waiters)
191 + cond_wait (&b->no_writers, &b->block_lock);
192 + } while (b->writers);
198 + /* Lock for write. */
199 + b->write_waiters++;
200 + if (b->readers || b->read_waiters || b->writers)
202 + cond_wait (&b->no_readers_or_writers, &b->block_lock);
203 + } while (b->readers || b->writers);
205 + b->write_waiters--;
207 + lock_release (&b->block_lock);
209 + /* Our sector should have been pinned in the cache while we
210 + were waiting. Make sure. */
211 + ASSERT (b->sector == sector);
216 + /* Not in cache. Find empty slot.
217 + We hold cache_sync. */
218 + for (i = 0; i < CACHE_CNT; i++)
220 + struct cache_block *b = &cache[i];
221 + lock_acquire (&b->block_lock);
222 + if (b->sector == INVALID_SECTOR)
224 + /* Drop block_lock, which is no longer needed because
225 + this is the only code that allocates free blocks,
226 + and we still have cache_sync.
228 + We can't drop cache_sync yet because someone else
229 + might try to allocate this same block (or read from
230 + it) while we're still initializing the block. */
231 + lock_release (&b->block_lock);
233 + b->sector = sector;
234 + b->up_to_date = false;
235 + ASSERT (b->readers == 0);
236 + ASSERT (b->writers == 0);
237 + if (type == NON_EXCLUSIVE)
241 + lock_release (&cache_sync);
244 + lock_release (&b->block_lock);
247 + /* No empty slots. Evict something.
248 + We hold cache_sync. */
249 + for (i = 0; i < CACHE_CNT; i++)
251 + struct cache_block *b = &cache[hand];
252 + if (++hand >= CACHE_CNT)
255 + /* Try to grab exclusive write access to block. */
256 + lock_acquire (&b->block_lock);
257 + if (b->readers || b->writers || b->read_waiters || b->write_waiters)
259 + lock_release (&b->block_lock);
263 + lock_release (&b->block_lock);
265 + lock_release (&cache_sync);
267 + /* Write block to disk if dirty. */
268 + if (b->up_to_date && b->dirty)
270 + block_write (fs_device, b->sector, b->data);
274 + /* Remove block from cache, if possible: someone might have
275 + started waiting on it while the lock was released. */
276 + lock_acquire (&b->block_lock);
278 + if (!b->read_waiters && !b->write_waiters)
280 + /* No one is waiting for it, so we can free it. */
281 + b->sector = INVALID_SECTOR;
285 + /* There is a waiter. Give it the block. */
286 + if (b->read_waiters)
287 + cond_broadcast (&b->no_writers, &b->block_lock);
289 + cond_signal (&b->no_readers_or_writers, &b->block_lock);
291 + lock_release (&b->block_lock);
297 + /* Wait for cache contention to die down. */
298 + lock_release (&cache_sync);
299 + timer_msleep (1000);
303 +/* Bring block B up-to-date, by reading it from disk if
304 + necessary, and return a pointer to its data.
305 + The caller must have an exclusive or non-exclusive lock on
308 +cache_read (struct cache_block *b)
310 + lock_acquire (&b->data_lock);
311 + if (!b->up_to_date)
313 + block_read (fs_device, b->sector, b->data);
314 + b->up_to_date = true;
317 + lock_release (&b->data_lock);
322 +/* Zero out block B, without reading it from disk, and return a
323 + pointer to the zeroed data.
324 + The caller must have an exclusive lock on B. */
326 +cache_zero (struct cache_block *b)
328 + ASSERT (b->writers);
329 + memset (b->data, 0, BLOCK_SECTOR_SIZE);
330 + b->up_to_date = true;
336 +/* Marks block B as dirty, so that it will be written back to
337 + disk before eviction.
338 + The caller must have a read or write lock on B,
339 + and B must be up-to-date. */
341 +cache_dirty (struct cache_block *b)
343 + ASSERT (b->up_to_date);
348 + If B is no longer locked by any thread, then it becomes a
349 + candidate for immediate eviction. */
351 +cache_unlock (struct cache_block *b)
353 + lock_acquire (&b->block_lock);
356 + ASSERT (b->writers == 0);
357 + if (--b->readers == 0)
358 + cond_signal (&b->no_readers_or_writers, &b->block_lock);
360 + else if (b->writers)
362 + ASSERT (b->readers == 0);
363 + ASSERT (b->writers == 1);
365 + if (b->read_waiters)
366 + cond_broadcast (&b->no_writers, &b->block_lock);
368 + cond_signal (&b->no_readers_or_writers, &b->block_lock);
372 + lock_release (&b->block_lock);
375 +/* If SECTOR is in the cache, evicts it immediately without
376 + writing it back to disk (even if dirty).
377 + The block must be entirely unused. */
379 +cache_free (block_sector_t sector)
383 + lock_acquire (&cache_sync);
384 + for (i = 0; i < CACHE_CNT; i++)
386 + struct cache_block *b = &cache[i];
388 + lock_acquire (&b->block_lock);
389 + if (b->sector == sector)
391 + lock_release (&cache_sync);
393 + /* Only invalidate the block if it's unused. That
394 + should be the normal case, but it could be part of a
395 + read-ahead (in readaheadd()) or write-behind (in
397 + if (b->readers == 0 && b->read_waiters == 0
398 + && b->writers == 0 && b->write_waiters == 0)
399 + b->sector = INVALID_SECTOR;
401 + lock_release (&b->block_lock);
404 + lock_release (&b->block_lock);
406 + lock_release (&cache_sync);
410 +cache_readahead (block_sector_t sector)
412 + readaheadd_submit (sector);
417 +static void flushd (void *aux);
419 +/* Initializes flush daemon. */
423 + thread_create ("flushd", PRI_MIN, flushd, NULL);
426 +/* Flush daemon thread. */
428 +flushd (void *aux UNUSED)
432 + timer_msleep (30 * 1000);
437 +/* A block to read ahead. */
438 +struct readahead_block
440 + struct list_elem list_elem; /* readahead_list element. */
441 + block_sector_t sector; /* Sector to read. */
444 +/* Protects readahead_list.
445 + Monitor lock for readahead_list_nonempty. */
446 +static struct lock readahead_lock;
448 +/* Signaled when a block is added to readahead_list. */
449 +static struct condition readahead_list_nonempty;
451 +/* List of blocks for read-ahead. */
452 +static struct list readahead_list;
454 +static void readaheadd (void *aux);
456 +/* Initialize read-ahead daemon. */
458 +readaheadd_init (void)
460 + lock_init (&readahead_lock);
461 + cond_init (&readahead_list_nonempty);
462 + list_init (&readahead_list);
463 + thread_create ("readaheadd", PRI_MIN, readaheadd, NULL);
466 +/* Adds SECTOR to the read-ahead queue. */
468 +readaheadd_submit (block_sector_t sector)
470 + /* Allocate readahead block. */
471 + struct readahead_block *block = malloc (sizeof *block);
474 + block->sector = sector;
476 + /* Add block to list. */
477 + lock_acquire (&readahead_lock);
478 + list_push_back (&readahead_list, &block->list_elem);
479 + cond_signal (&readahead_list_nonempty, &readahead_lock);
480 + lock_release (&readahead_lock);
483 +/* Read-ahead daemon. */
485 +readaheadd (void *aux UNUSED)
489 + struct readahead_block *ra_block;
490 + struct cache_block *cache_block;
492 + /* Get readahead block from list. */
493 + lock_acquire (&readahead_lock);
494 + while (list_empty (&readahead_list))
495 + cond_wait (&readahead_list_nonempty, &readahead_lock);
496 + ra_block = list_entry (list_pop_front (&readahead_list),
497 + struct readahead_block, list_elem);
498 + lock_release (&readahead_lock);
500 + /* Read block into cache. */
501 + cache_block = cache_lock (ra_block->sector, NON_EXCLUSIVE);
502 + cache_read (cache_block);
503 + cache_unlock (cache_block);
507 diff --git a/src/filesys/cache.h b/src/filesys/cache.h
509 index 0000000..2483924
511 +++ b/src/filesys/cache.h
513 +#ifndef FILESYS_CACHE_H
514 +#define FILESYS_CACHE_H
516 +#include "devices/block.h"
518 +/* Type of block lock. */
521 + NON_EXCLUSIVE, /* Any number of lockers. */
522 + EXCLUSIVE /* Only one locker. */
525 +void cache_init (void);
526 +void cache_flush (void);
527 +struct cache_block *cache_lock (block_sector_t, enum lock_type);
528 +void *cache_read (struct cache_block *);
529 +void *cache_zero (struct cache_block *);
530 +void cache_dirty (struct cache_block *);
531 +void cache_unlock (struct cache_block *);
532 +void cache_free (block_sector_t);
533 +void cache_readahead (block_sector_t);
535 +#endif /* filesys/cache.h */
536 diff --git a/src/filesys/directory.c b/src/filesys/directory.c
537 index 030c1c9..9855b9d 100644
538 --- a/src/filesys/directory.c
539 +++ b/src/filesys/directory.c
544 +#include "filesys/free-map.h"
545 #include "filesys/filesys.h"
546 #include "filesys/inode.h"
547 #include "threads/malloc.h"
548 @@ -21,12 +22,39 @@ struct dir_entry
549 bool in_use; /* In use or free? */
552 -/* Creates a directory with space for ENTRY_CNT entries in the
553 - given SECTOR. Returns true if successful, false on failure. */
555 -dir_create (block_sector_t sector, size_t entry_cnt)
556 +/* Creates a directory in the given SECTOR.
557 + The directory's parent is in PARENT_SECTOR.
558 + Returns inode of created directory if successful,
559 + null pointer on faiilure.
560 + On failure, SECTOR is released in the free map. */
562 +dir_create (block_sector_t sector, block_sector_t parent_sector)
564 - return inode_create (sector, entry_cnt * sizeof (struct dir_entry));
565 + struct inode *inode = inode_create (sector, DIR_INODE);
568 + struct dir_entry entries[2];
570 + memset (entries, 0, sizeof entries);
573 + entries[0].inode_sector = sector;
574 + strlcpy (entries[0].name, ".", sizeof entries[0].name);
575 + entries[0].in_use = true;
578 + entries[1].inode_sector = parent_sector;
579 + strlcpy (entries[1].name, "..", sizeof entries[1].name);
580 + entries[1].in_use = true;
582 + if (inode_write_at (inode, entries, sizeof entries, 0) != sizeof entries)
584 + inode_remove (inode);
585 + inode_close (inode);
592 /* Opens and returns the directory for the given INODE, of which
593 @@ -35,7 +63,7 @@ struct dir *
594 dir_open (struct inode *inode)
596 struct dir *dir = calloc (1, sizeof *dir);
597 - if (inode != NULL && dir != NULL)
598 + if (inode != NULL && dir != NULL && inode_get_type (inode) == DIR_INODE)
602 @@ -84,10 +112,8 @@ dir_get_inode (struct dir *dir)
605 /* Searches DIR for a file with the given NAME.
606 - If successful, returns true, sets *EP to the directory entry
607 - if EP is non-null, and sets *OFSP to the byte offset of the
608 - directory entry if OFSP is non-null.
609 - otherwise, returns false and ignores EP and OFSP. */
610 + If successful, returns the file's entry;
611 + otherwise, returns a null pointer. */
613 lookup (const struct dir *dir, const char *name,
614 struct dir_entry *ep, off_t *ofsp)
615 @@ -120,15 +146,16 @@ dir_lookup (const struct dir *dir, const char *name,
616 struct inode **inode)
621 ASSERT (dir != NULL);
622 ASSERT (name != NULL);
624 - if (lookup (dir, name, &e, NULL))
625 - *inode = inode_open (e.inode_sector);
628 + inode_lock (dir->inode);
629 + ok = lookup (dir, name, &e, NULL);
630 + inode_unlock (dir->inode);
632 + *inode = ok ? inode_open (e.inode_sector) : NULL;
633 return *inode != NULL;
636 @@ -149,10 +176,11 @@ dir_add (struct dir *dir, const char *name, block_sector_t inode_sector)
637 ASSERT (name != NULL);
639 /* Check NAME for validity. */
640 - if (*name == '\0' || strlen (name) > NAME_MAX)
641 + if (*name == '\0' || strchr (name, '/') || strlen (name) > NAME_MAX)
644 /* Check that NAME is not in use. */
645 + inode_lock (dir->inode);
646 if (lookup (dir, name, NULL, NULL))
649 @@ -175,6 +203,7 @@ dir_add (struct dir *dir, const char *name, block_sector_t inode_sector)
650 success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
653 + inode_unlock (dir->inode);
657 @@ -192,7 +221,11 @@ dir_remove (struct dir *dir, const char *name)
658 ASSERT (dir != NULL);
659 ASSERT (name != NULL);
661 + if (!strcmp (name, ".") || !strcmp (name, ".."))
664 /* Find directory entry. */
665 + inode_lock (dir->inode);
666 if (!lookup (dir, name, &e, &ofs))
669 @@ -201,6 +234,26 @@ dir_remove (struct dir *dir, const char *name)
673 + /* Verify that it is not an in-use or non-empty directory. */
674 + if (inode_get_type (inode) == DIR_INODE)
676 + struct dir_entry e2;
679 + if (inode_open_cnt (inode) != 1)
682 + inode_lock (inode);
683 + for (pos = 0; inode_read_at (inode, &e2, sizeof e2, pos) == sizeof e2;
685 + if (e2.in_use && strcmp (e2.name, ".") && strcmp (e2.name, ".."))
687 + inode_unlock (inode);
690 + inode_unlock (inode);
693 /* Erase directory entry. */
695 if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e)
696 @@ -211,6 +264,7 @@ dir_remove (struct dir *dir, const char *name)
700 + inode_unlock (dir->inode);
704 @@ -223,14 +277,17 @@ dir_readdir (struct dir *dir, char name[NAME_MAX + 1])
708 + inode_lock (dir->inode);
709 while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e)
711 dir->pos += sizeof e;
713 + if (e.in_use && strcmp (e.name, ".") && strcmp (e.name, ".."))
715 + inode_unlock (dir->inode);
716 strlcpy (name, e.name, NAME_MAX + 1);
720 + inode_unlock (dir->inode);
723 diff --git a/src/filesys/directory.h b/src/filesys/directory.h
724 index 930acf9..b8a4593 100644
725 --- a/src/filesys/directory.h
726 +++ b/src/filesys/directory.h
730 /* Opening and closing directories. */
731 -bool dir_create (block_sector_t sector, size_t entry_cnt);
732 +struct inode *dir_create (block_sector_t sector, block_sector_t parent_sector);
733 struct dir *dir_open (struct inode *);
734 struct dir *dir_open_root (void);
735 struct dir *dir_reopen (struct dir *);
736 diff --git a/src/filesys/file.c b/src/filesys/file.c
737 index d5fc10d..8669324 100644
738 --- a/src/filesys/file.c
739 +++ b/src/filesys/file.c
741 #include "filesys/file.h"
743 +#include "filesys/free-map.h"
744 #include "filesys/inode.h"
745 #include "threads/malloc.h"
747 @@ -11,6 +12,24 @@ struct file
748 bool deny_write; /* Has file_deny_write() been called? */
751 +/* Creates a file in the given SECTOR,
752 + initially LENGTH bytes long.
753 + Returns inode for the file on success, null pointer on failure.
754 + On failure, SECTOR is released in the free map. */
756 +file_create (block_sector_t sector, off_t length)
758 + struct inode *inode = inode_create (sector, FILE_INODE);
759 + if (inode != NULL && length > 0
760 + && inode_write_at (inode, "", 1, length - 1) != 1)
762 + inode_remove (inode);
763 + inode_close (inode);
769 /* Opens a file for the given INODE, of which it takes ownership,
770 and returns the new file. Returns a null pointer if an
771 allocation fails or if INODE is null. */
772 @@ -18,7 +37,7 @@ struct file *
773 file_open (struct inode *inode)
775 struct file *file = calloc (1, sizeof *file);
776 - if (inode != NULL && file != NULL)
777 + if (inode != NULL && file != NULL && inode_get_type (inode) == FILE_INODE)
781 diff --git a/src/filesys/file.h b/src/filesys/file.h
782 index a33c5af..63b4a65 100644
783 --- a/src/filesys/file.h
784 +++ b/src/filesys/file.h
786 #ifndef FILESYS_FILE_H
787 #define FILESYS_FILE_H
789 +#include <stdbool.h>
790 +#include "devices/block.h"
791 #include "filesys/off_t.h"
795 /* Opening and closing files. */
796 +struct inode *file_create (block_sector_t sector, off_t length);
797 struct file *file_open (struct inode *);
798 struct file *file_reopen (struct file *);
799 void file_close (struct file *);
800 diff --git a/src/filesys/filesys.c b/src/filesys/filesys.c
801 index 7a53f5f..51b4244 100644
802 --- a/src/filesys/filesys.c
803 +++ b/src/filesys/filesys.c
808 +#include "filesys/cache.h"
809 #include "filesys/file.h"
810 #include "filesys/free-map.h"
811 #include "filesys/inode.h"
812 #include "filesys/directory.h"
813 +#include "threads/thread.h"
815 /* Partition that contains the file system. */
816 struct block *fs_device;
817 @@ -22,6 +24,7 @@ filesys_init (bool format)
818 PANIC ("No file system device found, can't initialize file system.");
825 @@ -36,6 +39,130 @@ void
832 +/* Extracts a file name part from *SRCP into PART,
833 + and updates *SRCP so that the next call will return the next
835 + Returns 1 if successful, 0 at end of string, -1 for a too-long
838 +get_next_part (char part[NAME_MAX], const char **srcp)
840 + const char *src = *srcp;
843 + /* Skip leading slashes.
844 + If it's all slashes, we're done. */
845 + while (*src == '/')
850 + /* Copy up to NAME_MAX character from SRC to DST.
851 + Add null terminator. */
852 + while (*src != '/' && *src != '\0')
854 + if (dst < part + NAME_MAX)
862 + /* Advance source pointer. */
867 +/* Resolves relative or absolute file NAME.
868 + Returns true if successful, false on failure.
869 + Stores the directory corresponding to the name into *DIRP,
870 + and the file name part into BASE_NAME. */
872 +resolve_name_to_entry (const char *name,
873 + struct dir **dirp, char base_name[NAME_MAX + 1])
875 + struct dir *dir = NULL;
876 + struct inode *inode;
878 + char part[NAME_MAX + 1], next_part[NAME_MAX + 1];
881 + /* Find starting directory. */
882 + if (name[0] == '/' || thread_current ()->wd == NULL)
883 + dir = dir_open_root ();
885 + dir = dir_reopen (thread_current ()->wd);
889 + /* Get first name part. */
891 + if (get_next_part (part, &cp) <= 0)
894 + /* As long as another part follows the current one,
895 + traverse down another directory. */
896 + while ((ok = get_next_part (next_part, &cp)) > 0)
898 + if (!dir_lookup (dir, part, &inode))
902 + dir = dir_open (inode);
906 + strlcpy (part, next_part, NAME_MAX + 1);
911 + /* Return our results. */
913 + strlcpy (base_name, part, NAME_MAX + 1);
917 + /* Return failure. */
920 + base_name[0] = '\0';
924 +/* Resolves relative or absolute file NAME to an inode.
925 + Returns an inode if successful, or a null pointer on failure.
926 + The caller is responsible for closing the returned inode. */
927 +static struct inode *
928 +resolve_name_to_inode (const char *name)
930 + if (name[0] == '/' && name[strspn (name, "/")] == '\0')
932 + /* The name represents the root directory.
933 + There's no name part at all, so resolve_name_to_entry()
934 + would reject it entirely.
935 + Special case it. */
936 + return inode_open (ROOT_DIR_SECTOR);
941 + char base_name[NAME_MAX + 1];
943 + if (resolve_name_to_entry (name, &dir, base_name))
945 + struct inode *inode;
946 + dir_lookup (dir, base_name, &inode);
955 /* Creates a file named NAME with the given INITIAL_SIZE.
956 @@ -43,16 +170,32 @@ filesys_done (void)
957 Fails if a file named NAME already exists,
958 or if internal memory allocation fails. */
960 -filesys_create (const char *name, off_t initial_size)
961 +filesys_create (const char *name, off_t initial_size, enum inode_type type)
963 - block_sector_t inode_sector = 0;
964 - struct dir *dir = dir_open_root ();
965 - bool success = (dir != NULL
966 - && free_map_allocate (1, &inode_sector)
967 - && inode_create (inode_sector, initial_size)
968 - && dir_add (dir, name, inode_sector));
969 - if (!success && inode_sector != 0)
970 - free_map_release (inode_sector, 1);
972 + char base_name[NAME_MAX + 1];
973 + block_sector_t inode_sector;
975 + bool success = (resolve_name_to_entry (name, &dir, base_name)
976 + && free_map_allocate (&inode_sector));
979 + struct inode *inode;
980 + if (type == FILE_INODE)
981 + inode = file_create (inode_sector, initial_size);
983 + inode = dir_create (inode_sector,
984 + inode_get_inumber (dir_get_inode (dir)));
987 + success = dir_add (dir, base_name, inode_sector);
989 + inode_remove (inode);
990 + inode_close (inode);
998 @@ -63,17 +206,10 @@ filesys_create (const char *name, off_t initial_size)
1000 Fails if no file named NAME exists,
1001 or if an internal memory allocation fails. */
1004 filesys_open (const char *name)
1006 - struct dir *dir = dir_open_root ();
1007 - struct inode *inode = NULL;
1010 - dir_lookup (dir, name, &inode);
1013 - return file_open (inode);
1014 + return resolve_name_to_inode (name);
1017 /* Deletes the file named NAME.
1018 @@ -83,21 +219,53 @@ filesys_open (const char *name)
1020 filesys_remove (const char *name)
1022 - struct dir *dir = dir_open_root ();
1023 - bool success = dir != NULL && dir_remove (dir, name);
1026 + char base_name[NAME_MAX + 1];
1029 + if (resolve_name_to_entry (name, &dir, base_name))
1031 + success = dir_remove (dir, base_name);
1039 +/* Change current directory to NAME.
1040 + Return true if successful, false on failure. */
1042 +filesys_chdir (const char *name)
1044 + struct dir *dir = dir_open (resolve_name_to_inode (name));
1047 + dir_close (thread_current ()->wd);
1048 + thread_current ()->wd = dir;
1055 /* Formats the file system. */
1059 + struct inode *inode;
1060 printf ("Formatting file system...");
1062 + /* Set up free map. */
1064 - if (!dir_create (ROOT_DIR_SECTOR, 16))
1066 + /* Set up root directory. */
1067 + inode = dir_create (ROOT_DIR_SECTOR, ROOT_DIR_SECTOR);
1068 + if (inode == NULL)
1069 PANIC ("root directory creation failed");
1070 + inode_close (inode);
1076 diff --git a/src/filesys/filesys.h b/src/filesys/filesys.h
1077 index c1cda84..f181764 100644
1078 --- a/src/filesys/filesys.h
1079 +++ b/src/filesys/filesys.h
1082 #include <stdbool.h>
1083 #include "filesys/off_t.h"
1084 +#include "filesys/inode.h"
1086 /* Sectors of system file inodes. */
1087 #define FREE_MAP_SECTOR 0 /* Free map file inode sector. */
1088 @@ -13,8 +14,9 @@ struct block *fs_device;
1090 void filesys_init (bool format);
1091 void filesys_done (void);
1092 -bool filesys_create (const char *name, off_t initial_size);
1093 -struct file *filesys_open (const char *name);
1094 +bool filesys_create (const char *name, off_t initial_size, enum inode_type);
1095 +struct inode *filesys_open (const char *name);
1096 bool filesys_remove (const char *name);
1097 +bool filesys_chdir (const char *name);
1099 #endif /* filesys/filesys.h */
1100 diff --git a/src/filesys/free-map.c b/src/filesys/free-map.c
1101 index 29ea4df..2c88a5c 100644
1102 --- a/src/filesys/free-map.c
1103 +++ b/src/filesys/free-map.c
1106 #include "filesys/file.h"
1107 #include "filesys/filesys.h"
1108 -#include "filesys/inode.h"
1109 +#include "threads/synch.h"
1111 static struct file *free_map_file; /* Free map file. */
1112 static struct bitmap *free_map; /* Free map, one bit per sector. */
1113 +static struct lock free_map_lock; /* Mutual exclusion. */
1115 /* Initializes the free map. */
1117 free_map_init (void)
1119 + lock_init (&free_map_lock);
1121 free_map = bitmap_create (block_size (fs_device));
1122 if (free_map == NULL)
1123 PANIC ("bitmap creation failed--file system device is too large");
1124 @@ -19,34 +22,33 @@ free_map_init (void)
1125 bitmap_mark (free_map, ROOT_DIR_SECTOR);
1128 -/* Allocates CNT consecutive sectors from the free map and stores
1129 - the first into *SECTORP.
1130 +/* Allocates a sector from the free map and stores it into
1132 Returns true if successful, false if not enough consecutive
1133 sectors were available or if the free_map file could not be
1136 -free_map_allocate (size_t cnt, block_sector_t *sectorp)
1137 +free_map_allocate (block_sector_t *sectorp)
1139 - block_sector_t sector = bitmap_scan_and_flip (free_map, 0, cnt, false);
1140 - if (sector != BITMAP_ERROR
1141 - && free_map_file != NULL
1142 - && !bitmap_write (free_map, free_map_file))
1144 - bitmap_set_multiple (free_map, sector, cnt, false);
1145 - sector = BITMAP_ERROR;
1147 - if (sector != BITMAP_ERROR)
1150 + lock_acquire (&free_map_lock);
1151 + sector = bitmap_scan_and_flip (free_map, 0, 1, false);
1152 + lock_release (&free_map_lock);
1154 + if (sector != BITMAP_ERROR)
1156 return sector != BITMAP_ERROR;
1159 -/* Makes CNT sectors starting at SECTOR available for use. */
1160 +/* Makes SECTOR available for use. */
1162 -free_map_release (block_sector_t sector, size_t cnt)
1163 +free_map_release (block_sector_t sector)
1165 - ASSERT (bitmap_all (free_map, sector, cnt));
1166 - bitmap_set_multiple (free_map, sector, cnt, false);
1167 - bitmap_write (free_map, free_map_file);
1168 + lock_acquire (&free_map_lock);
1169 + ASSERT (bitmap_test (free_map, sector));
1170 + bitmap_reset (free_map, sector);
1171 + lock_release (&free_map_lock);
1174 /* Opens the free map file and reads it from disk. */
1175 @@ -64,6 +66,8 @@ free_map_open (void)
1177 free_map_close (void)
1179 + if (!bitmap_write (free_map, free_map_file))
1180 + PANIC ("can't write free map");
1181 file_close (free_map_file);
1184 @@ -72,9 +76,13 @@ free_map_close (void)
1186 free_map_create (void)
1188 + struct inode *inode;
1191 - if (!inode_create (FREE_MAP_SECTOR, bitmap_file_size (free_map)))
1192 + inode = file_create (FREE_MAP_SECTOR, 0);
1193 + if (inode == NULL)
1194 PANIC ("free map creation failed");
1195 + inode_close (inode);
1197 /* Write bitmap to file. */
1198 free_map_file = file_open (inode_open (FREE_MAP_SECTOR));
1199 diff --git a/src/filesys/free-map.h b/src/filesys/free-map.h
1200 index 316cd1c..63e35e9 100644
1201 --- a/src/filesys/free-map.h
1202 +++ b/src/filesys/free-map.h
1203 @@ -11,7 +11,7 @@ void free_map_create (void);
1204 void free_map_open (void);
1205 void free_map_close (void);
1207 -bool free_map_allocate (size_t, block_sector_t *);
1208 -void free_map_release (block_sector_t, size_t);
1209 +bool free_map_allocate (block_sector_t *);
1210 +void free_map_release (block_sector_t);
1212 #endif /* filesys/free-map.h */
1213 diff --git a/src/filesys/fsutil.c b/src/filesys/fsutil.c
1214 index 447f291..8016fb3 100644
1215 --- a/src/filesys/fsutil.c
1216 +++ b/src/filesys/fsutil.c
1217 @@ -38,7 +38,7 @@ fsutil_cat (char **argv)
1220 printf ("Printing '%s' to the console...\n", file_name);
1221 - file = filesys_open (file_name);
1222 + file = file_open (filesys_open (file_name));
1224 PANIC ("%s: open failed", file_name);
1225 buffer = palloc_get_page (PAL_ASSERT);
1226 @@ -117,9 +117,9 @@ fsutil_extract (char **argv UNUSED)
1227 printf ("Putting '%s' into the file system...\n", file_name);
1229 /* Create destination file. */
1230 - if (!filesys_create (file_name, size))
1231 + if (!filesys_create (file_name, size, FILE_INODE))
1232 PANIC ("%s: create failed", file_name);
1233 - dst = filesys_open (file_name);
1234 + dst = file_open (filesys_open (file_name));
1236 PANIC ("%s: open failed", file_name);
1238 @@ -181,7 +181,7 @@ fsutil_append (char **argv)
1239 PANIC ("couldn't allocate buffer");
1241 /* Open source file. */
1242 - src = filesys_open (file_name);
1243 + src = file_open (filesys_open (file_name));
1245 PANIC ("%s: open failed", file_name);
1246 size = file_length (src);
1247 diff --git a/src/filesys/inode.c b/src/filesys/inode.c
1248 index 3463563..58ab0d1 100644
1249 --- a/src/filesys/inode.c
1250 +++ b/src/filesys/inode.c
1252 #include "filesys/inode.h"
1253 +#include <bitmap.h>
1259 +#include "filesys/cache.h"
1260 #include "filesys/filesys.h"
1261 #include "filesys/free-map.h"
1262 #include "threads/malloc.h"
1263 +#include "threads/synch.h"
1265 /* Identifies an inode. */
1266 #define INODE_MAGIC 0x494e4f44
1268 +#define DIRECT_CNT 123
1269 +#define INDIRECT_CNT 1
1270 +#define DBL_INDIRECT_CNT 1
1271 +#define SECTOR_CNT (DIRECT_CNT + INDIRECT_CNT + DBL_INDIRECT_CNT)
1273 +#define PTRS_PER_SECTOR ((off_t) (BLOCK_SECTOR_SIZE / sizeof (block_sector_t)))
1274 +#define INODE_SPAN ((DIRECT_CNT \
1275 + + PTRS_PER_SECTOR * INDIRECT_CNT \
1276 + + PTRS_PER_SECTOR * PTRS_PER_SECTOR * DBL_INDIRECT_CNT) \
1277 + * BLOCK_SECTOR_SIZE)
1280 Must be exactly BLOCK_SECTOR_SIZE bytes long. */
1283 - block_sector_t start; /* First data sector. */
1284 + block_sector_t sectors[SECTOR_CNT]; /* Sectors. */
1285 + enum inode_type type; /* FILE_INODE or DIR_INODE. */
1286 off_t length; /* File size in bytes. */
1287 unsigned magic; /* Magic number. */
1288 - uint32_t unused[125]; /* Not used. */
1291 /* Returns the number of sectors to allocate for an inode SIZE
1292 @@ -35,74 +50,59 @@ struct inode
1293 block_sector_t sector; /* Sector number of disk location. */
1294 int open_cnt; /* Number of openers. */
1295 bool removed; /* True if deleted, false otherwise. */
1296 + struct lock lock; /* Protects the inode. */
1298 + /* Denying writes. */
1299 + struct lock deny_write_lock; /* Protects members below. */
1300 + struct condition no_writers_cond; /* Signaled when no writers. */
1301 int deny_write_cnt; /* 0: writes ok, >0: deny writes. */
1302 - struct inode_disk data; /* Inode content. */
1303 + int writer_cnt; /* Number of writers. */
1306 -/* Returns the block device sector that contains byte offset POS
1308 - Returns -1 if INODE does not contain data for a byte at offset
1310 -static block_sector_t
1311 -byte_to_sector (const struct inode *inode, off_t pos)
1313 - ASSERT (inode != NULL);
1314 - if (pos < inode->data.length)
1315 - return inode->data.start + pos / BLOCK_SECTOR_SIZE;
1320 /* List of open inodes, so that opening a single inode twice
1321 returns the same `struct inode'. */
1322 static struct list open_inodes;
1324 +/* Controls access to open_inodes list. */
1325 +static struct lock open_inodes_lock;
1327 +static void deallocate_inode (const struct inode *);
1329 /* Initializes the inode module. */
1333 list_init (&open_inodes);
1334 + lock_init (&open_inodes_lock);
1337 -/* Initializes an inode with LENGTH bytes of data and
1338 - writes the new inode to sector SECTOR on the file system
1340 - Returns true if successful.
1341 - Returns false if memory or disk allocation fails. */
1343 -inode_create (block_sector_t sector, off_t length)
1344 +/* Initializes an inode of the given TYPE, writes the new inode
1345 + to sector SECTOR on the file system device, and returns the
1346 + inode thus created. Returns a null pointer if unsuccessful,
1347 + in which case SECTOR is released in the free map. */
1349 +inode_create (block_sector_t sector, enum inode_type type)
1351 - struct inode_disk *disk_inode = NULL;
1352 - bool success = false;
1353 + struct cache_block *block;
1354 + struct inode_disk *disk_inode;
1355 + struct inode *inode;
1357 - ASSERT (length >= 0);
1358 + block = cache_lock (sector, EXCLUSIVE);
1360 /* If this assertion fails, the inode structure is not exactly
1361 one sector in size, and you should fix that. */
1362 ASSERT (sizeof *disk_inode == BLOCK_SECTOR_SIZE);
1364 - disk_inode = calloc (1, sizeof *disk_inode);
1365 - if (disk_inode != NULL)
1367 - size_t sectors = bytes_to_sectors (length);
1368 - disk_inode->length = length;
1369 - disk_inode->magic = INODE_MAGIC;
1370 - if (free_map_allocate (sectors, &disk_inode->start))
1372 - block_write (fs_device, sector, disk_inode);
1375 - static char zeros[BLOCK_SECTOR_SIZE];
1378 - for (i = 0; i < sectors; i++)
1379 - block_write (fs_device, disk_inode->start + i, zeros);
1383 - free (disk_inode);
1386 + disk_inode = cache_zero (block);
1387 + disk_inode->type = type;
1388 + disk_inode->length = 0;
1389 + disk_inode->magic = INODE_MAGIC;
1390 + cache_dirty (block);
1391 + cache_unlock (block);
1393 + inode = inode_open (sector);
1394 + if (inode == NULL)
1395 + free_map_release (sector);
1399 /* Reads an inode from SECTOR
1400 @@ -115,29 +115,35 @@ inode_open (block_sector_t sector)
1401 struct inode *inode;
1403 /* Check whether this inode is already open. */
1404 + lock_acquire (&open_inodes_lock);
1405 for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
1408 inode = list_entry (e, struct inode, elem);
1409 if (inode->sector == sector)
1411 - inode_reopen (inode);
1413 + inode->open_cnt++;
1418 /* Allocate memory. */
1419 inode = malloc (sizeof *inode);
1425 list_push_front (&open_inodes, &inode->elem);
1426 inode->sector = sector;
1427 inode->open_cnt = 1;
1428 + lock_init (&inode->lock);
1429 inode->deny_write_cnt = 0;
1430 + lock_init (&inode->deny_write_lock);
1431 + cond_init (&inode->no_writers_cond);
1432 inode->removed = false;
1433 - block_read (fs_device, inode->sector, &inode->data);
1436 + lock_release (&open_inodes_lock);
1440 @@ -146,10 +152,25 @@ struct inode *
1441 inode_reopen (struct inode *inode)
1444 - inode->open_cnt++;
1446 + lock_acquire (&open_inodes_lock);
1447 + inode->open_cnt++;
1448 + lock_release (&open_inodes_lock);
1453 +/* Returns the type of INODE. */
1455 +inode_get_type (const struct inode *inode)
1457 + struct cache_block *inode_block = cache_lock (inode->sector, NON_EXCLUSIVE);
1458 + struct inode_disk *disk_inode = cache_read (inode_block);
1459 + enum inode_type type = disk_inode->type;
1460 + cache_unlock (inode_block);
1464 /* Returns INODE's inode number. */
1466 inode_get_inumber (const struct inode *inode)
1467 @@ -168,21 +189,60 @@ inode_close (struct inode *inode)
1470 /* Release resources if this was the last opener. */
1471 + lock_acquire (&open_inodes_lock);
1472 if (--inode->open_cnt == 0)
1474 /* Remove from inode list and release lock. */
1475 list_remove (&inode->elem);
1476 + lock_release (&open_inodes_lock);
1478 /* Deallocate blocks if removed. */
1481 - free_map_release (inode->sector, 1);
1482 - free_map_release (inode->data.start,
1483 - bytes_to_sectors (inode->data.length));
1485 + deallocate_inode (inode);
1490 + lock_release (&open_inodes_lock);
1493 +/* Deallocates SECTOR and anything it points to recursively.
1494 + LEVEL is 2 if SECTOR is doubly indirect,
1495 + or 1 if SECTOR is indirect,
1496 + or 0 if SECTOR is a data sector. */
1498 +deallocate_recursive (block_sector_t sector, int level)
1502 + struct cache_block *block = cache_lock (sector, EXCLUSIVE);
1503 + block_sector_t *pointers = cache_read (block);
1505 + for (i = 0; i < PTRS_PER_SECTOR; i++)
1507 + deallocate_recursive (sector, level - 1);
1508 + cache_unlock (block);
1511 + cache_free (sector);
1512 + free_map_release (sector);
1515 +/* Deallocates the blocks allocated for INODE. */
1517 +deallocate_inode (const struct inode *inode)
1519 + struct cache_block *block = cache_lock (inode->sector, EXCLUSIVE);
1520 + struct inode_disk *disk_inode = cache_read (block);
1522 + for (i = 0; i < SECTOR_CNT; i++)
1523 + if (disk_inode->sectors[i])
1525 + int level = (i >= DIRECT_CNT) + (i >= DIRECT_CNT + INDIRECT_CNT);
1526 + deallocate_recursive (disk_inode->sectors[i], level);
1528 + cache_unlock (block);
1529 + deallocate_recursive (inode->sector, 0);
1532 /* Marks INODE to be deleted when it is closed by the last caller who
1533 @@ -194,6 +254,157 @@ inode_remove (struct inode *inode)
1534 inode->removed = true;
1537 +/* Translates SECTOR_IDX into a sequence of block indexes in
1538 + OFFSETS and sets *OFFSET_CNT to the number of offsets. */
1540 +calculate_indices (off_t sector_idx, size_t offsets[], size_t *offset_cnt)
1542 + /* Handle direct blocks. */
1543 + if (sector_idx < DIRECT_CNT)
1545 + offsets[0] = sector_idx;
1549 + sector_idx -= DIRECT_CNT;
1551 + /* Handle indirect blocks. */
1552 + if (sector_idx < PTRS_PER_SECTOR * INDIRECT_CNT)
1554 + offsets[0] = DIRECT_CNT + sector_idx / PTRS_PER_SECTOR;
1555 + offsets[1] = sector_idx % PTRS_PER_SECTOR;
1559 + sector_idx -= PTRS_PER_SECTOR * INDIRECT_CNT;
1561 + /* Handle doubly indirect blocks. */
1562 + if (sector_idx < DBL_INDIRECT_CNT * PTRS_PER_SECTOR * PTRS_PER_SECTOR)
1564 + offsets[0] = (DIRECT_CNT + INDIRECT_CNT
1565 + + sector_idx / (PTRS_PER_SECTOR * PTRS_PER_SECTOR));
1566 + offsets[1] = sector_idx / PTRS_PER_SECTOR;
1567 + offsets[2] = sector_idx % PTRS_PER_SECTOR;
1574 +/* Retrieves the data block for the given byte OFFSET in INODE,
1575 + setting *DATA_BLOCK to the block.
1576 + Returns true if successful, false on failure.
1577 + If ALLOCATE is false, then missing blocks will be successful
1578 + with *DATA_BLOCk set to a null pointer.
1579 + If ALLOCATE is true, then missing blocks will be allocated.
1580 + The block returned will be locked, normally non-exclusively,
1581 + but a newly allocated block will have an exclusive lock. */
1583 +get_data_block (struct inode *inode, off_t offset, bool allocate,
1584 + struct cache_block **data_block)
1586 + block_sector_t this_level_sector;
1587 + size_t offsets[3];
1588 + size_t offset_cnt;
1591 + ASSERT (offset >= 0);
1593 + calculate_indices (offset / BLOCK_SECTOR_SIZE, offsets, &offset_cnt);
1595 + this_level_sector = inode->sector;
1598 + struct cache_block *this_level_block;
1599 + uint32_t *this_level_data;
1601 + struct cache_block *next_level_block;
1603 + /* Check whether the block for the next level is allocated. */
1604 + this_level_block = cache_lock (this_level_sector, NON_EXCLUSIVE);
1605 + this_level_data = cache_read (this_level_block);
1606 + if (this_level_data[offsets[level]] != 0)
1608 + /* Yes, it's allocated. Advance to next level. */
1609 + this_level_sector = this_level_data[offsets[level]];
1611 + if (++level == offset_cnt)
1613 + /* We hit the data block.
1615 + if ((level == 0 && offsets[level] + 1 < DIRECT_CNT)
1616 + || (level > 0 && offsets[level] + 1 < PTRS_PER_SECTOR))
1618 + uint32_t next_sector = this_level_data[offsets[level] + 1];
1620 + && next_sector < block_size (fs_device))
1621 + cache_readahead (next_sector);
1623 + cache_unlock (this_level_block);
1625 + /* Return block. */
1626 + *data_block = cache_lock (this_level_sector, NON_EXCLUSIVE);
1629 + cache_unlock (this_level_block);
1632 + cache_unlock (this_level_block);
1634 + /* No block is allocated. Nothing is locked.
1635 + If we're not allocating new blocks, then this is
1636 + "success" (with all-zero data). */
1639 + *data_block = NULL;
1643 + /* We need to allocate a new block.
1644 + Grab an exclusive lock on this level's block so we can
1645 + insert the new block. */
1646 + this_level_block = cache_lock (this_level_sector, EXCLUSIVE);
1647 + this_level_data = cache_read (this_level_block);
1649 + /* Since we released this level's block, someone else might
1650 + have allocated the block in the meantime. Recheck. */
1651 + if (this_level_data[offsets[level]] != 0)
1653 + cache_unlock (this_level_block);
1657 + /* Allocate the new block. */
1658 + if (!free_map_allocate (&this_level_data[offsets[level]]))
1660 + cache_unlock (this_level_block);
1661 + *data_block = NULL;
1664 + cache_dirty (this_level_block);
1666 + /* Lock and clear the new block. */
1667 + next_level_block = cache_lock (this_level_data[offsets[level]],
1669 + cache_zero (next_level_block);
1671 + /* Release this level's block. No one else can access the
1672 + new block yet, because we have an exclusive lock on it. */
1673 + cache_unlock (this_level_block);
1675 + /* If this is the final level, then return the new block. */
1676 + if (level == offset_cnt - 1)
1678 + *data_block = next_level_block;
1682 + /* Otherwise, release the new block and go around again to
1683 + follow the new pointer. */
1684 + cache_unlock (next_level_block);
1688 /* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
1689 Returns the number of bytes actually read, which may be less
1690 than SIZE if an error occurs or end of file is reached. */
1691 @@ -202,13 +413,12 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
1693 uint8_t *buffer = buffer_;
1694 off_t bytes_read = 0;
1695 - uint8_t *bounce = NULL;
1699 - /* Disk sector to read, starting byte offset within sector. */
1700 - block_sector_t sector_idx = byte_to_sector (inode, offset);
1701 + /* Sector to read, starting byte offset within sector, sector data. */
1702 int sector_ofs = offset % BLOCK_SECTOR_SIZE;
1703 + struct cache_block *block;
1705 /* Bytes left in inode, bytes left in sector, lesser of the two. */
1706 off_t inode_left = inode_length (inode) - offset;
1707 @@ -217,26 +427,16 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
1709 /* Number of bytes to actually copy out of this sector. */
1710 int chunk_size = size < min_left ? size : min_left;
1711 - if (chunk_size <= 0)
1712 + if (chunk_size <= 0 || !get_data_block (inode, offset, false, &block))
1715 - if (sector_ofs == 0 && chunk_size == BLOCK_SECTOR_SIZE)
1717 - /* Read full sector directly into caller's buffer. */
1718 - block_read (fs_device, sector_idx, buffer + bytes_read);
1720 + if (block == NULL)
1721 + memset (buffer + bytes_read, 0, chunk_size);
1724 - /* Read sector into bounce buffer, then partially copy
1725 - into caller's buffer. */
1726 - if (bounce == NULL)
1728 - bounce = malloc (BLOCK_SECTOR_SIZE);
1729 - if (bounce == NULL)
1732 - block_read (fs_device, sector_idx, bounce);
1733 - memcpy (buffer + bytes_read, bounce + sector_ofs, chunk_size);
1734 + const uint8_t *sector_data = cache_read (block);
1735 + memcpy (buffer + bytes_read, sector_data + sector_ofs, chunk_size);
1736 + cache_unlock (block);
1740 @@ -244,75 +444,82 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
1741 offset += chunk_size;
1742 bytes_read += chunk_size;
1749 +/* Extends INODE to be at least LENGTH bytes long. */
1751 +extend_file (struct inode *inode, off_t length)
1753 + if (length > inode_length (inode))
1755 + struct cache_block *inode_block = cache_lock (inode->sector, EXCLUSIVE);
1756 + struct inode_disk *disk_inode = cache_read (inode_block);
1757 + if (length > disk_inode->length)
1759 + disk_inode->length = length;
1760 + cache_dirty (inode_block);
1762 + cache_unlock (inode_block);
1766 /* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
1767 Returns the number of bytes actually written, which may be
1768 - less than SIZE if end of file is reached or an error occurs.
1769 - (Normally a write at end of file would extend the inode, but
1770 - growth is not yet implemented.) */
1771 + less than SIZE if an error occurs. */
1773 inode_write_at (struct inode *inode, const void *buffer_, off_t size,
1776 const uint8_t *buffer = buffer_;
1777 off_t bytes_written = 0;
1778 - uint8_t *bounce = NULL;
1780 - if (inode->deny_write_cnt)
1782 + /* Don't write if writes are denied. */
1783 + lock_acquire (&inode->deny_write_lock);
1784 + if (inode->deny_write_cnt)
1786 + lock_release (&inode->deny_write_lock);
1789 + inode->writer_cnt++;
1790 + lock_release (&inode->deny_write_lock);
1794 - /* Sector to write, starting byte offset within sector. */
1795 - block_sector_t sector_idx = byte_to_sector (inode, offset);
1796 + /* Sector to write, starting byte offset within sector, sector data. */
1797 int sector_ofs = offset % BLOCK_SECTOR_SIZE;
1798 + struct cache_block *block;
1799 + uint8_t *sector_data;
1801 - /* Bytes left in inode, bytes left in sector, lesser of the two. */
1802 - off_t inode_left = inode_length (inode) - offset;
1803 + /* Bytes to max inode size, bytes left in sector, lesser of the two. */
1804 + off_t inode_left = INODE_SPAN - offset;
1805 int sector_left = BLOCK_SECTOR_SIZE - sector_ofs;
1806 int min_left = inode_left < sector_left ? inode_left : sector_left;
1808 /* Number of bytes to actually write into this sector. */
1809 int chunk_size = size < min_left ? size : min_left;
1810 - if (chunk_size <= 0)
1813 - if (sector_ofs == 0 && chunk_size == BLOCK_SECTOR_SIZE)
1815 - /* Write full sector directly to disk. */
1816 - block_write (fs_device, sector_idx, buffer + bytes_written);
1820 - /* We need a bounce buffer. */
1821 - if (bounce == NULL)
1823 - bounce = malloc (BLOCK_SECTOR_SIZE);
1824 - if (bounce == NULL)
1827 + if (chunk_size <= 0 || !get_data_block (inode, offset, true, &block))
1830 - /* If the sector contains data before or after the chunk
1831 - we're writing, then we need to read in the sector
1832 - first. Otherwise we start with a sector of all zeros. */
1833 - if (sector_ofs > 0 || chunk_size < sector_left)
1834 - block_read (fs_device, sector_idx, bounce);
1836 - memset (bounce, 0, BLOCK_SECTOR_SIZE);
1837 - memcpy (bounce + sector_ofs, buffer + bytes_written, chunk_size);
1838 - block_write (fs_device, sector_idx, bounce);
1840 + sector_data = cache_read (block);
1841 + memcpy (sector_data + sector_ofs, buffer + bytes_written, chunk_size);
1842 + cache_dirty (block);
1843 + cache_unlock (block);
1847 offset += chunk_size;
1848 bytes_written += chunk_size;
1852 + extend_file (inode, offset);
1854 + lock_acquire (&inode->deny_write_lock);
1855 + if (--inode->writer_cnt == 0)
1856 + cond_signal (&inode->no_writers_cond, &inode->deny_write_lock);
1857 + lock_release (&inode->deny_write_lock);
1859 return bytes_written;
1861 @@ -322,8 +529,12 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
1863 inode_deny_write (struct inode *inode)
1865 + lock_acquire (&inode->deny_write_lock);
1866 + while (inode->writer_cnt > 0)
1867 + cond_wait (&inode->no_writers_cond, &inode->deny_write_lock);
1868 + ASSERT (inode->deny_write_cnt < inode->open_cnt);
1869 inode->deny_write_cnt++;
1870 - ASSERT (inode->deny_write_cnt <= inode->open_cnt);
1871 + lock_release (&inode->deny_write_lock);
1874 /* Re-enables writes to INODE.
1875 @@ -332,14 +543,47 @@ inode_deny_write (struct inode *inode)
1877 inode_allow_write (struct inode *inode)
1879 + lock_acquire (&inode->deny_write_lock);
1880 ASSERT (inode->deny_write_cnt > 0);
1881 ASSERT (inode->deny_write_cnt <= inode->open_cnt);
1882 inode->deny_write_cnt--;
1883 + lock_release (&inode->deny_write_lock);
1886 /* Returns the length, in bytes, of INODE's data. */
1888 inode_length (const struct inode *inode)
1890 - return inode->data.length;
1891 + struct cache_block *inode_block = cache_lock (inode->sector, NON_EXCLUSIVE);
1892 + struct inode_disk *disk_inode = cache_read (inode_block);
1893 + off_t length = disk_inode->length;
1894 + cache_unlock (inode_block);
1898 +/* Returns the number of openers. */
1900 +inode_open_cnt (const struct inode *inode)
1904 + lock_acquire (&open_inodes_lock);
1905 + open_cnt = inode->open_cnt;
1906 + lock_release (&open_inodes_lock);
1913 +inode_lock (struct inode *inode)
1915 + lock_acquire (&inode->lock);
1918 +/* Releases INODE's lock. */
1920 +inode_unlock (struct inode *inode)
1922 + lock_release (&inode->lock);
1924 diff --git a/src/filesys/inode.h b/src/filesys/inode.h
1925 index cb42310..380d1b7 100644
1926 --- a/src/filesys/inode.h
1927 +++ b/src/filesys/inode.h
1932 +/* Type of an inode. */
1935 + FILE_INODE, /* Ordinary file. */
1936 + DIR_INODE /* Directory. */
1939 void inode_init (void);
1940 -bool inode_create (block_sector_t, off_t);
1941 +struct inode *inode_create (block_sector_t, enum inode_type);
1942 struct inode *inode_open (block_sector_t);
1943 struct inode *inode_reopen (struct inode *);
1944 +enum inode_type inode_get_type (const struct inode *);
1945 block_sector_t inode_get_inumber (const struct inode *);
1946 void inode_close (struct inode *);
1947 void inode_remove (struct inode *);
1948 @@ -19,5 +27,8 @@ off_t inode_write_at (struct inode *, const void *, off_t size, off_t offset);
1949 void inode_deny_write (struct inode *);
1950 void inode_allow_write (struct inode *);
1951 off_t inode_length (const struct inode *);
1952 +int inode_open_cnt (const struct inode *);
1953 +void inode_lock (struct inode *);
1954 +void inode_unlock (struct inode *);
1956 #endif /* filesys/inode.h */
1957 diff --git a/src/threads/thread.c b/src/threads/thread.c
1958 index f9f2310..1c82b6c 100644
1959 --- a/src/threads/thread.c
1960 +++ b/src/threads/thread.c
1961 @@ -475,6 +475,7 @@ init_thread (struct thread *t, const char *name, int priority, tid_t tid)
1962 list_init (&t->fds);
1963 list_init (&t->mappings);
1966 t->magic = THREAD_MAGIC;
1967 old_level = intr_disable ();
1968 list_push_back (&all_list, &t->allelem);
1969 diff --git a/src/threads/thread.h b/src/threads/thread.h
1970 index b9e7b0c..b60376f 100644
1971 --- a/src/threads/thread.h
1972 +++ b/src/threads/thread.h
1973 @@ -115,6 +115,7 @@ struct thread
1974 struct list mappings; /* Memory-mapped files. */
1975 int next_handle; /* Next handle value. */
1976 void *user_esp; /* User's stack pointer. */
1977 + struct dir *wd; /* Working directory. */
1979 /* Owned by thread.c. */
1980 unsigned magic; /* Detects stack overflow. */
1981 diff --git a/src/userprog/process.c b/src/userprog/process.c
1982 index 7a15814..3d16752 100644
1983 --- a/src/userprog/process.c
1984 +++ b/src/userprog/process.c
1985 @@ -32,6 +32,7 @@ struct exec_info
1986 const char *file_name; /* Program to load. */
1987 struct semaphore load_done; /* "Up"ed when loading complete. */
1988 struct wait_status *wait_status; /* Child process. */
1989 + struct dir *wd; /* Working directory. */
1990 bool success; /* Program successfully loaded? */
1993 @@ -42,6 +43,7 @@ struct exec_info
1995 process_execute (const char *file_name)
1997 + struct dir *wd = thread_current ()->wd;
1998 struct exec_info exec;
1999 char thread_name[16];
2001 @@ -49,6 +51,9 @@ process_execute (const char *file_name)
2003 /* Initialize exec_info. */
2004 exec.file_name = file_name;
2005 + exec.wd = wd != NULL ? dir_reopen (wd) : dir_open_root ();
2006 + if (exec.wd == NULL)
2008 sema_init (&exec.load_done, 0);
2010 /* Create a new thread to execute FILE_NAME. */
2011 @@ -61,8 +66,13 @@ process_execute (const char *file_name)
2013 list_push_back (&thread_current ()->children, &exec.wait_status->elem);
2018 + /* Don't close exec.wd; child process will have done so. */
2022 + dir_close (exec.wd);
2026 @@ -76,6 +86,8 @@ start_process (void *exec_)
2027 struct intr_frame if_;
2030 + thread_current ()->wd = exec->wd;
2032 /* Initialize interrupt frame and load executable. */
2033 memset (&if_, 0, sizeof if_);
2034 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
2035 @@ -334,13 +346,13 @@ load (const char *cmd_line, void (**eip) (void), void **esp)
2038 /* Open executable file. */
2039 - t->bin_file = file = filesys_open (file_name);
2040 + t->bin_file = file = file_open (filesys_open (file_name));
2043 printf ("load: %s: open failed\n", file_name);
2046 - file_deny_write (t->bin_file);
2047 + file_deny_write (file);
2049 /* Read and verify executable header. */
2050 if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
2051 diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c
2052 index e6be702..e41cbcd 100644
2053 --- a/src/userprog/syscall.c
2054 +++ b/src/userprog/syscall.c
2056 #include "filesys/directory.h"
2057 #include "filesys/filesys.h"
2058 #include "filesys/file.h"
2059 +#include "threads/init.h"
2060 #include "threads/interrupt.h"
2061 #include "threads/malloc.h"
2062 #include "threads/palloc.h"
2063 @@ -32,17 +33,19 @@ static int sys_tell (int handle);
2064 static int sys_close (int handle);
2065 static int sys_mmap (int handle, void *addr);
2066 static int sys_munmap (int mapping);
2067 +static int sys_chdir (const char *udir);
2068 +static int sys_mkdir (const char *udir);
2069 +static int sys_readdir (int handle, char *name);
2070 +static int sys_isdir (int handle);
2071 +static int sys_inumber (int handle);
2073 static void syscall_handler (struct intr_frame *);
2074 static void copy_in (void *, const void *, size_t);
2076 -static struct lock fs_lock;
2081 intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
2082 - lock_init (&fs_lock);
2085 /* System call handler. */
2086 @@ -76,6 +79,11 @@ syscall_handler (struct intr_frame *f)
2087 {1, (syscall_function *) sys_close},
2088 {2, (syscall_function *) sys_mmap},
2089 {1, (syscall_function *) sys_munmap},
2090 + {1, (syscall_function *) sys_chdir},
2091 + {1, (syscall_function *) sys_mkdir},
2092 + {2, (syscall_function *) sys_readdir},
2093 + {1, (syscall_function *) sys_isdir},
2094 + {1, (syscall_function *) sys_inumber},
2097 const struct syscall *sc;
2098 @@ -124,6 +132,32 @@ copy_in (void *dst_, const void *usrc_, size_t size)
2102 +/* Copies SIZE bytes from kernel address SRC to user address
2104 + Call thread_exit() if any of the user accesses are invalid. */
2106 +copy_out (void *udst_, const void *src_, size_t size)
2108 + uint8_t *udst = udst_;
2109 + const uint8_t *src = src_;
2113 + size_t chunk_size = PGSIZE - pg_ofs (udst);
2114 + if (chunk_size > size)
2115 + chunk_size = size;
2117 + if (!page_lock (udst, false))
2119 + memcpy (udst, src, chunk_size);
2120 + page_unlock (udst);
2122 + udst += chunk_size;
2123 + src += chunk_size;
2124 + size -= chunk_size;
2128 /* Creates a copy of user string US in kernel memory
2129 and returns it as a page that must be freed with
2131 @@ -191,10 +225,8 @@ sys_exec (const char *ufile)
2134 char *kfile = copy_in_string (ufile);
2136 - lock_acquire (&fs_lock);
2138 tid = process_execute (kfile);
2139 - lock_release (&fs_lock);
2141 palloc_free_page (kfile);
2143 @@ -213,12 +245,7 @@ static int
2144 sys_create (const char *ufile, unsigned initial_size)
2146 char *kfile = copy_in_string (ufile);
2149 - lock_acquire (&fs_lock);
2150 - ok = filesys_create (kfile, initial_size);
2151 - lock_release (&fs_lock);
2153 + bool ok = filesys_create (kfile, initial_size, FILE_INODE);
2154 palloc_free_page (kfile);
2157 @@ -229,12 +256,7 @@ static int
2158 sys_remove (const char *ufile)
2160 char *kfile = copy_in_string (ufile);
2163 - lock_acquire (&fs_lock);
2164 - ok = filesys_remove (kfile);
2165 - lock_release (&fs_lock);
2167 + bool ok = filesys_remove (kfile);
2168 palloc_free_page (kfile);
2171 @@ -245,6 +267,7 @@ struct file_descriptor
2173 struct list_elem elem; /* List element. */
2174 struct file *file; /* File. */
2175 + struct dir *dir; /* Directory. */
2176 int handle; /* File handle. */
2179 @@ -256,20 +279,28 @@ sys_open (const char *ufile)
2180 struct file_descriptor *fd;
2183 - fd = malloc (sizeof *fd);
2184 + fd = calloc (1, sizeof *fd);
2187 - lock_acquire (&fs_lock);
2188 - fd->file = filesys_open (kfile);
2189 - if (fd->file != NULL)
2190 + struct inode *inode = filesys_open (kfile);
2191 + if (inode != NULL)
2193 - struct thread *cur = thread_current ();
2194 - handle = fd->handle = cur->next_handle++;
2195 - list_push_front (&cur->fds, &fd->elem);
2196 + if (inode_get_type (inode) == FILE_INODE)
2197 + fd->file = file_open (inode);
2199 + fd->dir = dir_open (inode);
2200 + if (fd->file != NULL || fd->dir != NULL)
2202 + struct thread *cur = thread_current ();
2203 + handle = fd->handle = cur->next_handle++;
2204 + list_push_front (&cur->fds, &fd->elem);
2209 + inode_close (inode);
2214 - lock_release (&fs_lock);
2217 palloc_free_page (kfile);
2218 @@ -297,16 +328,38 @@ lookup_fd (int handle)
2222 +/* Returns the file descriptor associated with the given handle.
2223 + Terminates the process if HANDLE is not associated with an
2224 + open ordinary file. */
2225 +static struct file_descriptor *
2226 +lookup_file_fd (int handle)
2228 + struct file_descriptor *fd = lookup_fd (handle);
2229 + if (fd->file == NULL)
2234 +/* Returns the file descriptor associated with the given handle.
2235 + Terminates the process if HANDLE is not associated with an
2236 + open directory. */
2237 +static struct file_descriptor *
2238 +lookup_dir_fd (int handle)
2240 + struct file_descriptor *fd = lookup_fd (handle);
2241 + if (fd->dir == NULL)
2246 /* Filesize system call. */
2248 sys_filesize (int handle)
2250 - struct file_descriptor *fd = lookup_fd (handle);
2251 + struct file_descriptor *fd = lookup_file_fd (handle);
2254 - lock_acquire (&fs_lock);
2255 size = file_length (fd->file);
2256 - lock_release (&fs_lock);
2260 @@ -319,7 +372,10 @@ sys_read (int handle, void *udst_, unsigned size)
2261 struct file_descriptor *fd;
2264 - fd = lookup_fd (handle);
2265 + /* Look up file descriptor. */
2266 + if (handle != STDIN_FILENO)
2267 + fd = lookup_file_fd (handle);
2271 /* How much to read into this page? */
2272 @@ -327,44 +383,37 @@ sys_read (int handle, void *udst_, unsigned size)
2273 size_t read_amt = size < page_left ? size : page_left;
2276 + /* Check that touching this page is okay. */
2277 + if (!page_lock (udst, true))
2280 /* Read from file into page. */
2281 if (handle != STDIN_FILENO)
2283 - if (!page_lock (udst, true))
2285 - lock_acquire (&fs_lock);
2286 retval = file_read (fd->file, udst, read_amt);
2287 - lock_release (&fs_lock);
2288 - page_unlock (udst);
2291 + if (bytes_read == 0)
2295 + bytes_read += retval;
2301 for (i = 0; i < read_amt; i++)
2303 - char c = input_getc ();
2304 - if (!page_lock (udst, true))
2307 - page_unlock (udst);
2309 + udst[i] = input_getc ();
2310 bytes_read = read_amt;
2313 - /* Check success. */
2316 - if (bytes_read == 0)
2320 - bytes_read += retval;
2321 - if (retval != (off_t) read_amt)
2323 - /* Short read, so we're done. */
2327 + /* Release page. */
2328 + page_unlock (udst);
2330 + /* If it was a short read we're done. */
2331 + if (retval != (off_t) read_amt)
2336 @@ -384,7 +433,7 @@ sys_write (int handle, void *usrc_, unsigned size)
2338 /* Lookup up file descriptor. */
2339 if (handle != STDOUT_FILENO)
2340 - fd = lookup_fd (handle);
2341 + fd = lookup_file_fd (handle);
2345 @@ -393,10 +442,11 @@ sys_write (int handle, void *usrc_, unsigned size)
2346 size_t write_amt = size < page_left ? size : page_left;
2349 - /* Write from page into file. */
2350 + /* Check that we can touch this user page. */
2351 if (!page_lock (usrc, false))
2353 - lock_acquire (&fs_lock);
2355 + /* Do the write. */
2356 if (handle == STDOUT_FILENO)
2358 putbuf ((char *) usrc, write_amt);
2359 @@ -404,7 +454,8 @@ sys_write (int handle, void *usrc_, unsigned size)
2362 retval = file_write (fd->file, usrc, write_amt);
2363 - lock_release (&fs_lock);
2365 + /* Release user page. */
2368 /* Handle return value. */
2369 @@ -432,13 +483,8 @@ sys_write (int handle, void *usrc_, unsigned size)
2371 sys_seek (int handle, unsigned position)
2373 - struct file_descriptor *fd = lookup_fd (handle);
2375 - lock_acquire (&fs_lock);
2376 if ((off_t) position >= 0)
2377 - file_seek (fd->file, position);
2378 - lock_release (&fs_lock);
2380 + file_seek (lookup_file_fd (handle)->file, position);
2384 @@ -446,14 +492,7 @@ sys_seek (int handle, unsigned position)
2386 sys_tell (int handle)
2388 - struct file_descriptor *fd = lookup_fd (handle);
2389 - unsigned position;
2391 - lock_acquire (&fs_lock);
2392 - position = file_tell (fd->file);
2393 - lock_release (&fs_lock);
2396 + return file_tell (lookup_file_fd (handle)->file);
2399 /* Close system call. */
2400 @@ -461,9 +500,8 @@ static int
2401 sys_close (int handle)
2403 struct file_descriptor *fd = lookup_fd (handle);
2404 - lock_acquire (&fs_lock);
2405 file_close (fd->file);
2406 - lock_release (&fs_lock);
2407 + dir_close (fd->dir);
2408 list_remove (&fd->elem);
2411 @@ -518,7 +556,7 @@ unmap (struct mapping *m)
2413 sys_mmap (int handle, void *addr)
2415 - struct file_descriptor *fd = lookup_fd (handle);
2416 + struct file_descriptor *fd = lookup_file_fd (handle);
2417 struct mapping *m = malloc (sizeof *m);
2420 @@ -527,9 +565,7 @@ sys_mmap (int handle, void *addr)
2423 m->handle = thread_current ()->next_handle++;
2424 - lock_acquire (&fs_lock);
2425 m->file = file_reopen (fd->file);
2426 - lock_release (&fs_lock);
2427 if (m->file == NULL)
2430 @@ -540,9 +576,7 @@ sys_mmap (int handle, void *addr)
2431 list_push_front (&thread_current ()->mappings, &m->elem);
2434 - lock_acquire (&fs_lock);
2435 length = file_length (m->file);
2436 - lock_release (&fs_lock);
2439 struct page *p = page_allocate ((uint8_t *) addr + offset, false);
2440 @@ -570,6 +604,58 @@ sys_munmap (int mapping)
2441 unmap (lookup_mapping (mapping));
2445 +/* Chdir system call. */
2447 +sys_chdir (const char *udir)
2449 + char *kdir = copy_in_string (udir);
2450 + bool ok = filesys_chdir (kdir);
2451 + palloc_free_page (kdir);
2455 +/* Mkdir system call. */
2457 +sys_mkdir (const char *udir)
2459 + char *kdir = copy_in_string (udir);
2460 + bool ok = filesys_create (kdir, 0, DIR_INODE);
2461 + palloc_free_page (kdir);
2466 +/* Readdir system call. */
2468 +sys_readdir (int handle, char *uname)
2470 + struct file_descriptor *fd = lookup_dir_fd (handle);
2471 + char name[NAME_MAX + 1];
2472 + bool ok = dir_readdir (fd->dir, name);
2474 + copy_out (uname, name, strlen (name) + 1);
2478 +/* Isdir system call. */
2480 +sys_isdir (int handle)
2482 + struct file_descriptor *fd = lookup_fd (handle);
2483 + return fd->dir != NULL;
2486 +/* Inumber system call. */
2488 +sys_inumber (int handle)
2490 + struct file_descriptor *fd = lookup_fd (handle);
2491 + struct inode *inode = (fd->file
2492 + ? file_get_inode (fd->file)
2493 + : dir_get_inode (fd->dir));
2494 + return inode_get_inumber (inode);
2497 /* On thread exit, close all open files and unmap all mappings. */
2499 @@ -582,9 +668,8 @@ syscall_exit (void)
2501 struct file_descriptor *fd = list_entry (e, struct file_descriptor, elem);
2502 next = list_next (e);
2503 - lock_acquire (&fs_lock);
2504 file_close (fd->file);
2505 - lock_release (&fs_lock);
2506 + dir_close (fd->dir);
2510 @@ -595,4 +680,6 @@ syscall_exit (void)
2511 next = list_next (e);
2515 + dir_close (cur->wd);
2517 diff --git a/src/vm/frame.c b/src/vm/frame.c
2518 index ef55376..39b4cec 100644
2519 --- a/src/vm/frame.c
2520 +++ b/src/vm/frame.c
2521 @@ -100,7 +100,6 @@ try_frame_alloc_and_lock (struct page *page)
2526 /* Tries really hard to allocate and lock a frame for PAGE.
2527 Returns the frame if successful, false on failure. */
2529 diff --git a/src/vm/page.c b/src/vm/page.c
2530 index f08bcf8..62aab36 100644
2533 @@ -24,6 +24,7 @@ destroy_page (struct hash_elem *p_, void *aux UNUSED)
2538 /* Destroys the current process's page table. */
2541 diff --git a/src/vm/swap.c b/src/vm/swap.c
2542 index 76fcf71..ce9d25e 100644
2547 #include "vm/frame.h"
2548 #include "vm/page.h"
2549 +#include "devices/block.h"
2550 #include "threads/synch.h"
2551 #include "threads/vaddr.h"
2553 -/* The swap device. */
2554 +/* The swap partition. */
2555 static struct block *swap_device;
2557 /* Used swap pages. */